chore: consistency/prettier (#3852)

* chore: consistency/prettier

* chore: rebase

* chore: rebase

* chore: include typings

* fix: include typings file in prettier lint-staged
This commit is contained in:
Crawl
2020-02-29 14:35:57 +01:00
committed by GitHub
parent 6650d50a56
commit c065156a88
127 changed files with 5198 additions and 4513 deletions

View File

@@ -3,8 +3,8 @@
require('setimmediate');
const EventEmitter = require('events');
const RESTManager = require('../rest/RESTManager');
const Util = require('../util/Util');
const { DefaultOptions } = require('../util/Constants');
const Util = require('../util/Util');
/**
* The base class for all clients.

View File

@@ -1,24 +1,24 @@
'use strict';
const BaseClient = require('./BaseClient');
const Permissions = require('../util/Permissions');
const ActionsManager = require('./actions/ActionsManager');
const ClientVoiceManager = require('./voice/ClientVoiceManager');
const WebSocketManager = require('./websocket/WebSocketManager');
const ActionsManager = require('./actions/ActionsManager');
const Collection = require('../util/Collection');
const { Error, TypeError, RangeError } = require('../errors');
const ChannelManager = require('../managers/ChannelManager');
const GuildEmojiManager = require('../managers/GuildEmojiManager');
const GuildManager = require('../managers/GuildManager');
const UserManager = require('../managers/UserManager');
const ShardClientUtil = require('../sharding/ShardClientUtil');
const ClientApplication = require('../structures/ClientApplication');
const Invite = require('../structures/Invite');
const VoiceRegion = require('../structures/VoiceRegion');
const Webhook = require('../structures/Webhook');
const Invite = require('../structures/Invite');
const ClientApplication = require('../structures/ClientApplication');
const ShardClientUtil = require('../sharding/ShardClientUtil');
const UserManager = require('../managers/UserManager');
const ChannelManager = require('../managers/ChannelManager');
const GuildManager = require('../managers/GuildManager');
const GuildEmojiManager = require('../managers/GuildEmojiManager');
const Collection = require('../util/Collection');
const { Events, browser, DefaultOptions } = require('../util/Constants');
const DataResolver = require('../util/DataResolver');
const Permissions = require('../util/Permissions');
const Structures = require('../util/Structures');
const { Error, TypeError, RangeError } = require('../errors');
/**
* The main hub for interacting with the Discord API, and the starting point for any bot.
@@ -63,9 +63,11 @@ class Client extends BaseClient {
if (typeofShards === 'number') this.options.shards = [this.options.shards];
if (Array.isArray(this.options.shards)) {
this.options.shards = [...new Set(
this.options.shards.filter(item => !isNaN(item) && item >= 0 && item < Infinity && item === (item | 0)),
)];
this.options.shards = [
...new Set(
this.options.shards.filter(item => !isNaN(item) && item >= 0 && item < Infinity && item === (item | 0)),
),
];
}
this._validateOptions();
@@ -93,9 +95,10 @@ class Client extends BaseClient {
* Shard helpers for the client (only if the process was spawned from a {@link ShardingManager})
* @type {?ShardClientUtil}
*/
this.shard = !browser && process.env.SHARDING_MANAGER ?
ShardClientUtil.singleton(this, process.env.SHARDING_MANAGER_MODE) :
null;
this.shard =
!browser && process.env.SHARDING_MANAGER
? ShardClientUtil.singleton(this, process.env.SHARDING_MANAGER_MODE)
: null;
/**
* All of the {@link User} objects that have been cached at any point, mapped by their IDs
@@ -198,8 +201,12 @@ class Client extends BaseClient {
async login(token = this.token) {
if (!token || typeof token !== 'string') throw new Error('TOKEN_INVALID');
this.token = token = token.replace(/^(Bot|Bearer)\s*/i, '');
this.emit(Events.DEBUG,
`Provided token: ${token.split('.').map((val, i) => i > 1 ? val.replace(/./g, '*') : val).join('.')}`,
this.emit(
Events.DEBUG,
`Provided token: ${token
.split('.')
.map((val, i) => (i > 1 ? val.replace(/./g, '*') : val))
.join('.')}`,
);
if (this.options.presence) {
@@ -238,7 +245,9 @@ class Client extends BaseClient {
*/
fetchInvite(invite) {
const code = DataResolver.resolveInviteCode(invite);
return this.api.invites(code).get({ query: { with_counts: true } })
return this.api
.invites(code)
.get({ query: { with_counts: true } })
.then(data => new Invite(this, data));
}
@@ -253,7 +262,10 @@ class Client extends BaseClient {
* .catch(console.error);
*/
fetchWebhook(id, token) {
return this.api.webhooks(id, token).get().then(data => new Webhook(this, data));
return this.api
.webhooks(id, token)
.get()
.then(data => new Webhook(this, data));
}
/**
@@ -289,7 +301,7 @@ class Client extends BaseClient {
throw new TypeError('INVALID_TYPE', 'lifetime', 'number');
}
if (lifetime <= 0) {
this.emit(Events.DEBUG, 'Didn\'t sweep messages - lifetime is unlimited');
this.emit(Events.DEBUG, "Didn't sweep messages - lifetime is unlimited");
return -1;
}
@@ -307,8 +319,10 @@ class Client extends BaseClient {
);
}
this.emit(Events.DEBUG,
`Swept ${messages} messages older than ${lifetime} seconds in ${channels} text-based channels`);
this.emit(
Events.DEBUG,
`Swept ${messages} messages older than ${lifetime} seconds in ${channels} text-based channels`,
);
return messages;
}
@@ -317,7 +331,9 @@ class Client extends BaseClient {
* @returns {Promise<ClientApplication>}
*/
fetchApplication() {
return this.api.oauth2.applications('@me').get()
return this.api.oauth2
.applications('@me')
.get()
.then(app => new ClientApplication(this, app));
}
@@ -364,14 +380,12 @@ class Client extends BaseClient {
* @param {ClientOptions} [options=this.options] Options to validate
* @private
*/
_validateOptions(options = this.options) { // eslint-disable-line complexity
_validateOptions(options = this.options) {
if (typeof options.shardCount !== 'number' || isNaN(options.shardCount) || options.shardCount < 1) {
throw new TypeError('CLIENT_INVALID_OPTION', 'shardCount', 'a number greater than or equal to 1');
}
if (options.shards &&
!(options.shards === 'auto' || Array.isArray(options.shards))
) {
throw new TypeError('CLIENT_INVALID_OPTION', 'shards', '\'auto\', a number or array of numbers');
if (options.shards && !(options.shards === 'auto' || Array.isArray(options.shards))) {
throw new TypeError('CLIENT_INVALID_OPTION', 'shards', "'auto', a number or array of numbers");
}
if (options.shards && !options.shards.length) throw new RangeError('CLIENT_INVALID_PROVIDED_SHARDS');
if (typeof options.messageCacheMaxSize !== 'number' || isNaN(options.messageCacheMaxSize)) {

View File

@@ -1,7 +1,7 @@
'use strict';
const Webhook = require('../structures/Webhook');
const BaseClient = require('./BaseClient');
const Webhook = require('../structures/Webhook');
/**
* The webhook client.

View File

@@ -33,38 +33,65 @@ class GenericAction {
getChannel(data) {
const id = data.channel_id || data.id;
return data.channel || this.getPayload({
id,
guild_id: data.guild_id,
recipients: [data.author || { id: data.user_id }],
}, this.client.channels, id, PartialTypes.CHANNEL);
return (
data.channel ||
this.getPayload(
{
id,
guild_id: data.guild_id,
recipients: [data.author || { id: data.user_id }],
},
this.client.channels,
id,
PartialTypes.CHANNEL,
)
);
}
getMessage(data, channel, cache) {
const id = data.message_id || data.id;
return data.message || this.getPayload({
id,
channel_id: channel.id,
guild_id: data.guild_id || (channel.guild ? channel.guild.id : null),
}, channel.messages, id, PartialTypes.MESSAGE, cache);
return (
data.message ||
this.getPayload(
{
id,
channel_id: channel.id,
guild_id: data.guild_id || (channel.guild ? channel.guild.id : null),
},
channel.messages,
id,
PartialTypes.MESSAGE,
cache,
)
);
}
getReaction(data, message, user) {
const id = data.emoji.id || decodeURIComponent(data.emoji.name);
return this.getPayload({
emoji: data.emoji,
count: message.partial ? null : 0,
me: user ? user.id === this.client.user.id : false,
}, message.reactions, id, PartialTypes.REACTION);
return this.getPayload(
{
emoji: data.emoji,
count: message.partial ? null : 0,
me: user ? user.id === this.client.user.id : false,
},
message.reactions,
id,
PartialTypes.REACTION,
);
}
getMember(data, guild) {
const id = data.user.id;
return this.getPayload({
user: {
id,
return this.getPayload(
{
user: {
id,
},
},
}, guild.members, id, PartialTypes.GUILD_MEMBER);
guild.members,
id,
PartialTypes.GUILD_MEMBER,
);
}
getUser(data) {

View File

@@ -1,8 +1,8 @@
'use strict';
const Action = require('./Action');
const { Events } = require('../../util/Constants');
const DMChannel = require('../../structures/DMChannel');
const { Events } = require('../../util/Constants');
class ChannelDeleteAction extends Action {
constructor(client) {

View File

@@ -17,4 +17,3 @@ class GuildIntegrationsUpdate extends Action {
}
module.exports = GuildIntegrationsUpdate;

View File

@@ -27,5 +27,4 @@ class GuildMemberRemoveAction extends Action {
}
}
module.exports = GuildMemberRemoveAction;

View File

@@ -22,5 +22,4 @@ class GuildRoleCreate extends Action {
}
}
module.exports = GuildRoleCreate;

View File

@@ -27,5 +27,4 @@ class GuildRoleDeleteAction extends Action {
}
}
module.exports = GuildRoleDeleteAction;

View File

@@ -36,5 +36,4 @@ class GuildRoleUpdateAction extends Action {
}
}
module.exports = GuildRoleUpdateAction;

View File

@@ -30,5 +30,4 @@ class GuildUpdateAction extends Action {
}
}
module.exports = GuildUpdateAction;

View File

@@ -36,5 +36,4 @@ class MessageCreateAction extends Action {
}
}
module.exports = MessageCreateAction;

View File

@@ -26,5 +26,4 @@ class MessageDeleteAction extends Action {
}
}
module.exports = MessageDeleteAction;

View File

@@ -13,10 +13,14 @@ class MessageDeleteBulkAction extends Action {
const ids = data.ids;
const messages = new Collection();
for (const id of ids) {
const message = this.getMessage({
id,
guild_id: data.guild_id,
}, channel, false);
const message = this.getMessage(
{
id,
guild_id: data.guild_id,
},
channel,
false,
);
if (message) {
message.deleted = true;
messages.set(message.id, message);
@@ -36,5 +40,4 @@ class MessageDeleteBulkAction extends Action {
}
}
module.exports = MessageDeleteBulkAction;

View File

@@ -41,5 +41,4 @@ class MessageReactionRemove extends Action {
}
}
module.exports = MessageReactionRemove;

View File

@@ -1,8 +1,8 @@
'use strict';
const Action = require('./Action');
const { Events } = require('../../util/Constants');
const VoiceState = require('../../structures/VoiceState');
const { Events } = require('../../util/Constants');
class VoiceStateUpdate extends Action {
handle(data) {
@@ -10,9 +10,9 @@ class VoiceStateUpdate extends Action {
const guild = client.guilds.cache.get(data.guild_id);
if (guild) {
// Update the state
const oldState = guild.voiceStates.cache.has(data.user_id) ?
guild.voiceStates.cache.get(data.user_id)._clone() :
new VoiceState(guild, { user_id: data.user_id });
const oldState = guild.voiceStates.cache.has(data.user_id)
? guild.voiceStates.cache.get(data.user_id)._clone()
: new VoiceState(guild, { user_id: data.user_id });
const newState = guild.voiceStates.add(data);
@@ -41,5 +41,4 @@ class VoiceStateUpdate extends Action {
}
}
module.exports = VoiceStateUpdate;

View File

@@ -16,5 +16,4 @@ class WebhooksUpdate extends Action {
}
}
module.exports = WebhooksUpdate;

View File

@@ -1,9 +1,9 @@
'use strict';
const Collection = require('../../util/Collection');
const VoiceConnection = require('./VoiceConnection');
const VoiceBroadcast = require('./VoiceBroadcast');
const VoiceConnection = require('./VoiceConnection');
const { Error } = require('../../errors');
const Collection = require('../../util/Collection');
/**
* Manages voice connections for the client
@@ -83,7 +83,8 @@ class ClientVoiceManager {
} else {
connection = new VoiceConnection(this, channel);
connection.on('debug', msg =>
this.client.emit('debug', `[VOICE (${channel.guild.id}:${connection.status})]: ${msg}`));
this.client.emit('debug', `[VOICE (${channel.guild.id}:${connection.status})]: ${msg}`),
);
connection.authenticate();
this.connections.set(channel.guild.id, connection);
}

View File

@@ -2,8 +2,8 @@
const EventEmitter = require('events');
const BroadcastAudioPlayer = require('./player/BroadcastAudioPlayer');
const { Events } = require('../../util/Constants');
const PlayInterface = require('./util/PlayInterface');
const { Events } = require('../../util/Constants');
/**
* A voice broadcast can be played across multiple voice connections for improved shared-stream efficiency.
@@ -59,8 +59,9 @@ class VoiceBroadcast extends EventEmitter {
* broadcast.play('http://www.sample-videos.com/audio/mp3/wave.mp3');
* @returns {BroadcastDispatcher}
*/
play() { return null; }
play() {
return null;
}
/**
* Ends the broadcast, unsubscribing all subscribed channels and deleting the broadcast

View File

@@ -1,16 +1,16 @@
'use strict';
const VoiceWebSocket = require('./networking/VoiceWebSocket');
const EventEmitter = require('events');
const VoiceUDP = require('./networking/VoiceUDPClient');
const Util = require('../../util/Util');
const { OPCodes, VoiceOPCodes, VoiceStatus, Events } = require('../../util/Constants');
const VoiceWebSocket = require('./networking/VoiceWebSocket');
const AudioPlayer = require('./player/AudioPlayer');
const VoiceReceiver = require('./receiver/Receiver');
const EventEmitter = require('events');
const { Error } = require('../../errors');
const PlayInterface = require('./util/PlayInterface');
const Speaking = require('../../util/Speaking');
const Silence = require('./util/Silence');
const { Error } = require('../../errors');
const { OPCodes, VoiceOPCodes, VoiceStatus, Events } = require('../../util/Constants');
const Speaking = require('../../util/Speaking');
const Util = require('../../util/Util');
// Workaround for Discord now requiring silence to be sent before being able to receive audio
class SingleSilence extends Silence {
@@ -20,11 +20,7 @@ class SingleSilence extends Silence {
}
}
const SUPPORTED_MODES = [
'xsalsa20_poly1305_lite',
'xsalsa20_poly1305_suffix',
'xsalsa20_poly1305',
];
const SUPPORTED_MODES = ['xsalsa20_poly1305_lite', 'xsalsa20_poly1305_suffix', 'xsalsa20_poly1305'];
/**
* Represents a connection to a guild's voice server.
@@ -154,16 +150,18 @@ class VoiceConnection extends EventEmitter {
if (this.speaking.equals(value)) return;
if (this.status !== VoiceStatus.CONNECTED) return;
this.speaking = new Speaking(value).freeze();
this.sockets.ws.sendPacket({
op: VoiceOPCodes.SPEAKING,
d: {
speaking: this.speaking.bitfield,
delay: 0,
ssrc: this.authentication.ssrc,
},
}).catch(e => {
this.emit('debug', e);
});
this.sockets.ws
.sendPacket({
op: VoiceOPCodes.SPEAKING,
d: {
speaking: this.speaking.bitfield,
delay: 0,
ssrc: this.authentication.ssrc,
},
})
.catch(e => {
this.emit('debug', e);
});
}
/**
@@ -181,19 +179,25 @@ class VoiceConnection extends EventEmitter {
* @private
*/
sendVoiceStateUpdate(options = {}) {
options = Util.mergeDefault({
guild_id: this.channel.guild.id,
channel_id: this.channel.id,
self_mute: this.voice ? this.voice.selfMute : false,
self_deaf: this.voice ? this.voice.selfDeaf : false,
}, options);
options = Util.mergeDefault(
{
guild_id: this.channel.guild.id,
channel_id: this.channel.id,
self_mute: this.voice ? this.voice.selfMute : false,
self_deaf: this.voice ? this.voice.selfDeaf : false,
},
options,
);
this.emit('debug', `Sending voice state update: ${JSON.stringify(options)}`);
return this.channel.guild.shard.send({
op: OPCodes.VOICE_STATE_UPDATE,
d: options,
}, true);
return this.channel.guild.shard.send(
{
op: OPCodes.VOICE_STATE_UPDATE,
d: options,
},
true,
);
}
/**
@@ -318,8 +322,7 @@ class VoiceConnection extends EventEmitter {
*/
authenticate() {
this.sendVoiceStateUpdate();
this.connectTimeout = this.client.setTimeout(
() => this.authenticateFailed('VOICE_CONNECTION_TIMEOUT'), 15000);
this.connectTimeout = this.client.setTimeout(() => this.authenticateFailed('VOICE_CONNECTION_TIMEOUT'), 15000);
}
/**
@@ -371,7 +374,6 @@ class VoiceConnection extends EventEmitter {
this.emit('disconnect');
}
/**
* Cleans up after disconnect.
* @private
@@ -513,7 +515,7 @@ class VoiceConnection extends EventEmitter {
}
}
play() { } // eslint-disable-line no-empty-function
play() {} // eslint-disable-line no-empty-function
}
PlayInterface.applyToClass(VoiceConnection);

View File

@@ -1,16 +1,15 @@
'use strict';
const VolumeInterface = require('../util/VolumeInterface');
const { Writable } = require('stream');
const secretbox = require('../util/Secretbox');
const Silence = require('../util/Silence');
const VolumeInterface = require('../util/VolumeInterface');
const FRAME_LENGTH = 20;
const CHANNELS = 2;
const TIMESTAMP_INC = (48000 / 100) * CHANNELS;
const MAX_NONCE_SIZE = (2 ** 32) - 1;
const MAX_NONCE_SIZE = 2 ** 32 - 1;
const nonce = Buffer.alloc(24);
/**
@@ -31,10 +30,7 @@ const nonce = Buffer.alloc(24);
* @extends {WritableStream}
*/
class StreamDispatcher extends Writable {
constructor(
player,
{ seek = 0, volume = 1, fec, plp, bitrate = 96, highWaterMark = 12 } = {},
streams) {
constructor(player, { seek = 0, volume = 1, fec, plp, bitrate = 96, highWaterMark = 12 } = {}, streams) {
const streamOptions = { seek, volume, fec, plp, bitrate, highWaterMark };
super(streamOptions);
/**
@@ -146,7 +142,9 @@ class StreamDispatcher extends Writable {
* @type {boolean}
* @readonly
*/
get paused() { return Boolean(this.pausedSince); }
get paused() {
return Boolean(this.pausedSince);
}
/**
* Total time that this dispatcher has been paused in milliseconds
@@ -233,7 +231,7 @@ class StreamDispatcher extends Writable {
done();
};
if (!this.streams.broadcast) {
const next = FRAME_LENGTH + (this.count * FRAME_LENGTH) - (Date.now() - this.startTime - this._pausedTime);
const next = FRAME_LENGTH + this.count * FRAME_LENGTH - (Date.now() - this.startTime - this._pausedTime);
setTimeout(() => {
if ((!this.pausedSince || this._silence) && this._writeCallback) this._writeCallback();
}, next);
@@ -261,10 +259,7 @@ class StreamDispatcher extends Writable {
this._nonce++;
if (this._nonce > MAX_NONCE_SIZE) this._nonce = 0;
this._nonceBuffer.writeUInt32BE(this._nonce, 0);
return [
secretbox.methods.close(buffer, this._nonceBuffer, secret_key),
this._nonceBuffer.slice(0, 4),
];
return [secretbox.methods.close(buffer, this._nonceBuffer, secret_key), this._nonceBuffer.slice(0, 4)];
} else if (mode === 'xsalsa20_poly1305_suffix') {
const random = secretbox.methods.random(24);
return [secretbox.methods.close(buffer, random, secret_key), random];
@@ -297,11 +292,10 @@ class StreamDispatcher extends Writable {
this.emit('debug', 'Failed to send a packet - no UDP socket');
return;
}
this.player.voiceConnection.sockets.udp.send(packet)
.catch(e => {
this._setSpeaking(0);
this.emit('debug', `Failed to send a packet - ${e}`);
});
this.player.voiceConnection.sockets.udp.send(packet).catch(e => {
this._setSpeaking(0);
this.emit('debug', `Failed to send a packet - ${e}`);
});
}
_setSpeaking(value) {
@@ -316,14 +310,18 @@ class StreamDispatcher extends Writable {
this.emit('speaking', value);
}
get volumeEditable() { return Boolean(this.streams.volume); }
get volumeEditable() {
return Boolean(this.streams.volume);
}
/**
* Whether or not the Opus bitrate of this stream is editable
* @type {boolean}
* @readonly
*/
get bitrateEditable() { return this.streams.opus && this.streams.opus.setBitrate; }
get bitrateEditable() {
return this.streams.opus && this.streams.opus.setBitrate;
}
// Volume
get volume() {

View File

@@ -1,9 +1,9 @@
'use strict';
const udp = require('dgram');
const { VoiceOPCodes } = require('../../../util/Constants');
const EventEmitter = require('events');
const { Error } = require('../../../errors');
const { VoiceOPCodes } = require('../../../util/Constants');
/**
* Represents a UDP client for a Voice Connection.
@@ -90,7 +90,7 @@ class VoiceConnectionUDPClient extends EventEmitter {
async createUDPSocket(address) {
this.discordAddress = address;
const socket = this.socket = udp.createSocket('udp4');
const socket = (this.socket = udp.createSocket('udp4'));
socket.on('error', e => {
this.emit('debug', `[UDP] Error: ${e}`);
this.emit('error', e);

View File

@@ -1,9 +1,9 @@
'use strict';
const { OPCodes, VoiceOPCodes } = require('../../../util/Constants');
const EventEmitter = require('events');
const { Error } = require('../../../errors');
const WebSocket = require('../../../WebSocket');
const { Error } = require('../../../errors');
const { OPCodes, VoiceOPCodes } = require('../../../util/Constants');
/**
* Represents a Voice Connection's WebSocket.
@@ -92,7 +92,8 @@ class VoiceWebSocket extends EventEmitter {
return new Promise((resolve, reject) => {
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) throw new Error('WS_NOT_OPEN', data);
this.ws.send(data, null, error => {
if (error) reject(error); else resolve(data);
if (error) reject(error);
else resolve(data);
});
});
}

View File

@@ -1,17 +1,11 @@
'use strict';
const EventEmitter = require('events').EventEmitter;
const EventEmitter = require('events');
const { Readable: ReadableStream } = require('stream');
const prism = require('prism-media');
const StreamDispatcher = require('../dispatcher/StreamDispatcher');
const FFMPEG_ARGUMENTS = [
'-analyzeduration', '0',
'-loglevel', '0',
'-f', 's16le',
'-ar', '48000',
'-ac', '2',
];
const FFMPEG_ARGUMENTS = ['-analyzeduration', '0', '-loglevel', '0', '-f', 's16le', '-ar', '48000', '-ac', '2'];
/**
* An Audio Player for a Voice Connection.
@@ -61,7 +55,7 @@ class BasePlayer extends EventEmitter {
playPCMStream(stream, options, streams = {}) {
this.destroyDispatcher();
const opus = streams.opus = new prism.opus.Encoder({ channels: 2, rate: 48000, frameSize: 960 });
const opus = (streams.opus = new prism.opus.Encoder({ channels: 2, rate: 48000, frameSize: 960 }));
if (options && options.volume === false) {
stream.pipe(opus);
return this.playOpusStream(opus, options, streams);
@@ -90,7 +84,7 @@ class BasePlayer extends EventEmitter {
createDispatcher(options, streams, broadcast) {
this.destroyDispatcher();
const dispatcher = this.dispatcher = new StreamDispatcher(this, options, streams, broadcast);
const dispatcher = (this.dispatcher = new StreamDispatcher(this, options, streams, broadcast));
return dispatcher;
}
}

View File

@@ -1,7 +1,7 @@
'use strict';
const BroadcastDispatcher = require('../dispatcher/BroadcastDispatcher');
const BasePlayer = require('./BasePlayer');
const BroadcastDispatcher = require('../dispatcher/BroadcastDispatcher');
/**
* An Audio Player for a Voice Connection.
@@ -20,7 +20,7 @@ class AudioPlayer extends BasePlayer {
createDispatcher(options, streams) {
this.destroyDispatcher();
const dispatcher = this.dispatcher = new BroadcastDispatcher(this, options, streams);
const dispatcher = (this.dispatcher = new BroadcastDispatcher(this, options, streams));
return dispatcher;
}
}

View File

@@ -1,13 +1,15 @@
'use strict';
const secretbox = require('../util/Secretbox');
const EventEmitter = require('events');
const secretbox = require('../util/Secretbox');
// The delay between packets when a user is considered to have stopped speaking
// https://github.com/discordjs/discord.js/issues/3524#issuecomment-540373200
const DISCORD_SPEAKING_DELAY = 250;
class Readable extends require('stream').Readable { _read() {} } // eslint-disable-line no-empty-function
class Readable extends require('stream').Readable {
_read() {} // eslint-disable-line no-empty-function
}
class PacketHandler extends EventEmitter {
constructor(receiver) {
@@ -59,7 +61,7 @@ class PacketHandler extends EventEmitter {
packet = Buffer.from(packet);
// Strip RTP Header Extensions (one-byte only)
if (packet[0] === 0xBE && packet[1] === 0xDE && packet.length > 4) {
if (packet[0] === 0xbe && packet[1] === 0xde && packet.length > 4) {
const headerExtensionLength = packet.readUInt16BE(2);
let offset = 4;
for (let i = 0; i < headerExtensionLength; i++) {

View File

@@ -85,12 +85,12 @@ class PlayInterface {
static applyToClass(structure) {
for (const prop of ['play']) {
Object.defineProperty(structure.prototype, prop,
Object.getOwnPropertyDescriptor(PlayInterface.prototype, prop));
Object.defineProperty(structure.prototype, prop, Object.getOwnPropertyDescriptor(PlayInterface.prototype, prop));
}
}
}
module.exports = PlayInterface;
// eslint-disable-next-line import/order
const Broadcast = require('../VoiceBroadcast');

View File

@@ -2,7 +2,7 @@
const { Readable } = require('stream');
const SILENCE_FRAME = Buffer.from([0xF8, 0xFF, 0xFE]);
const SILENCE_FRAME = Buffer.from([0xf8, 0xff, 0xfe]);
class Silence extends Readable {
_read() {

View File

@@ -94,19 +94,10 @@ class VolumeInterface extends EventEmitter {
}
}
const props = [
'volumeDecibels',
'volumeLogarithmic',
'setVolumeDecibels',
'setVolumeLogarithmic',
];
const props = ['volumeDecibels', 'volumeLogarithmic', 'setVolumeDecibels', 'setVolumeLogarithmic'];
exports.applyToClass = function applyToClass(structure) {
for (const prop of props) {
Object.defineProperty(
structure.prototype,
prop,
Object.getOwnPropertyDescriptor(VolumeInterface.prototype, prop),
);
Object.defineProperty(structure.prototype, prop, Object.getOwnPropertyDescriptor(VolumeInterface.prototype, prop));
}
};

View File

@@ -1,12 +1,12 @@
'use strict';
const EventEmitter = require('events');
const WebSocketShard = require('./WebSocketShard');
const PacketHandlers = require('./handlers');
const { Error: DJSError } = require('../../errors');
const Collection = require('../../util/Collection');
const Util = require('../../util/Util');
const WebSocketShard = require('./WebSocketShard');
const { Events, ShardEvents, Status, WSCodes, WSEvents } = require('../../util/Constants');
const PacketHandlers = require('./handlers');
const Util = require('../../util/Util');
const BeforeReadyWhitelist = [
WSEvents.READY,
@@ -18,7 +18,9 @@ const BeforeReadyWhitelist = [
WSEvents.GUILD_MEMBER_REMOVE,
];
const UNRECOVERABLE_CLOSE_CODES = Object.keys(WSCodes).slice(1).map(Number);
const UNRECOVERABLE_CLOSE_CODES = Object.keys(WSCodes)
.slice(1)
.map(Number);
const UNRESUMABLE_CLOSE_CODES = [1000, 4006, 4007];
/**

View File

@@ -237,14 +237,15 @@ class WebSocketShard extends EventEmitter {
Gateway : ${gateway}
Version : ${client.options.ws.version}
Encoding : ${WebSocket.encoding}
Compression: ${zlib ? 'zlib-stream' : 'none'}`);
Compression: ${zlib ? 'zlib-stream' : 'none'}`,
);
this.status = this.status === Status.DISCONNECTED ? Status.RECONNECTING : Status.CONNECTING;
this.setHelloTimeout();
this.connectedAt = Date.now();
const ws = this.connection = WebSocket.create(gateway, wsQuery);
const ws = (this.connection = WebSocket.create(gateway, wsQuery));
ws.onopen = this.onOpen.bind(this);
ws.onmessage = this.onMessage.bind(this);
ws.onerror = this.onError.bind(this);
@@ -271,11 +272,8 @@ class WebSocketShard extends EventEmitter {
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
if (zlib) {
const l = data.length;
const flush = l >= 4 &&
data[l - 4] === 0x00 &&
data[l - 3] === 0x00 &&
data[l - 2] === 0xFF &&
data[l - 1] === 0xFF;
const flush =
l >= 4 && data[l - 4] === 0x00 && data[l - 3] === 0x00 && data[l - 2] === 0xff && data[l - 1] === 0xff;
this.inflate.push(data, flush && zlib.Z_SYNC_FLUSH);
if (!flush) return;
@@ -529,8 +527,10 @@ class WebSocketShard extends EventEmitter {
* @param {boolean} [ignoreHeartbeatAck] If we should send the heartbeat forcefully.
* @private
*/
sendHeartbeat(tag = 'HeartbeatTimer',
ignoreHeartbeatAck = [Status.WAITING_FOR_GUILDS, Status.IDENTIFYING, Status.RESUMING].includes(this.status)) {
sendHeartbeat(
tag = 'HeartbeatTimer',
ignoreHeartbeatAck = [Status.WAITING_FOR_GUILDS, Status.IDENTIFYING, Status.RESUMING].includes(this.status),
) {
if (ignoreHeartbeatAck && !this.lastHeartbeatAcked) {
this.debug(`[${tag}] Didn't process heartbeat ack yet but we are still connected. Sending one now.`);
} else if (!this.lastHeartbeatAcked) {
@@ -538,7 +538,8 @@ class WebSocketShard extends EventEmitter {
`[${tag}] Didn't receive a heartbeat ack last time, assuming zombie connection. Destroying and reconnecting.
Status : ${STATUS_KEYS[this.status]}
Sequence : ${this.sequence}
Connection State: ${this.connection ? CONNECTION_STATE[this.connection.readyState] : 'No Connection??'}`);
Connection State: ${this.connection ? CONNECTION_STATE[this.connection.readyState] : 'No Connection??'}`,
);
this.destroy({ closeCode: 4009, reset: true });
return;
@@ -741,10 +742,7 @@ class WebSocketShard extends EventEmitter {
* @private
*/
_cleanupConnection() {
this.connection.onopen =
this.connection.onclose =
this.connection.onerror =
this.connection.onmessage = null;
this.connection.onopen = this.connection.onclose = this.connection.onerror = this.connection.onmessage = null;
}
/**

View File

@@ -14,4 +14,3 @@ module.exports = (client, packet) => {
client.emit(Events.CHANNEL_UPDATE, old, updated);
}
};

View File

@@ -10,9 +10,9 @@ module.exports = async (client, { d: data }, shard) => {
guild._patch(data);
// If the client was ready before and we had unavailable guilds, fetch them
if (client.ws.status === Status.READY && client.options.fetchAllMembers) {
await guild.members.fetch().catch(err =>
client.emit(Events.DEBUG, `Failed to fetch all members: ${err}\n${err.stack}`),
);
await guild.members
.fetch()
.catch(err => client.emit(Events.DEBUG, `Failed to fetch all members: ${err}\n${err.stack}`));
}
}
} else {
@@ -26,9 +26,9 @@ module.exports = async (client, { d: data }, shard) => {
* @param {Guild} guild The created guild
*/
if (client.options.fetchAllMembers) {
await guild.members.fetch().catch(err =>
client.emit(Events.DEBUG, `Failed to fetch all members: ${err}\n${err.stack}`),
);
await guild.members
.fetch()
.catch(err => client.emit(Events.DEBUG, `Failed to fetch all members: ${err}\n${err.stack}`));
}
client.emit(Events.GUILD_CREATE, guild);
}

View File

@@ -1,7 +1,7 @@
'use strict';
const { Events } = require('../../../util/Constants');
const Collection = require('../../../util/Collection');
const { Events } = require('../../../util/Constants');
module.exports = (client, { d: data }) => {
const guild = client.guilds.cache.get(data.guild_id);

View File

@@ -8,11 +8,11 @@ module.exports = (client, { d: data }, shard) => {
guild.memberCount++;
const member = guild.members.add(data);
if (shard.status === Status.READY) {
/**
* Emitted whenever a user joins a guild.
* @event Client#guildMemberAdd
* @param {GuildMember} member The member that has joined a guild
*/
/**
* Emitted whenever a user joins a guild.
* @event Client#guildMemberAdd
* @param {GuildMember} member The member that has joined a guild
*/
client.emit(Events.GUILD_MEMBER_ADD, member);
}
}

View File

@@ -7,12 +7,12 @@ module.exports = (client, { d: data }) => {
const user = client.users.cache.get(data.user_id);
if (channel && user) {
/**
* Emitted whenever a user starts typing in a channel.
* @event Client#typingStart
* @param {Channel} channel The channel the user started typing in
* @param {User} user The user that started typing
*/
/**
* Emitted whenever a user starts typing in a channel.
* @event Client#typingStart
* @param {Channel} channel The channel the user started typing in
* @param {User} user The user that started typing
*/
client.emit(Events.TYPING_START, channel, user);
}
};

View File

@@ -36,7 +36,7 @@ const Messages = {
USER_NO_DMCHANNEL: 'No DM Channel exists!',
VOICE_INVALID_HEARTBEAT: 'Tried to set voice heartbeat but no valid interval was specified.',
VOICE_USER_MISSING: 'Couldn\'t resolve the user to create stream.',
VOICE_USER_MISSING: "Couldn't resolve the user to create stream.",
VOICE_JOIN_CHANNEL: (full = false) =>
`You do not have permission to join this voice channel${full ? '; it is full.' : '.'}`,
VOICE_CONNECTION_TIMEOUT: 'Connection not established within 15 seconds.',
@@ -71,7 +71,7 @@ const Messages = {
SPLIT_MAX_LEN: 'Chunk exceeds the max length and contains no split characters.',
BAN_RESOLVE_ID: (ban = false) => `Couldn't resolve the user ID to ${ban ? 'ban' : 'unban'}.`,
FETCH_BAN_RESOLVE_ID: 'Couldn\'t resolve the user ID to fetch the ban.',
FETCH_BAN_RESOLVE_ID: "Couldn't resolve the user ID to fetch the ban.",
PRUNE_DAYS_TYPE: 'Days must be a number',
@@ -79,7 +79,7 @@ const Messages = {
GUILD_VOICE_CHANNEL_RESOLVE: 'Could not resolve channel to a guild voice channel.',
GUILD_CHANNEL_ORPHAN: 'Could not find a parent to this guild channel.',
GUILD_OWNED: 'Guild is owned by the client.',
GUILD_MEMBERS_TIMEOUT: 'Members didn\'t arrive in time.',
GUILD_MEMBERS_TIMEOUT: "Members didn't arrive in time.",
GUILD_UNCACHED_ME: 'The client user as a member of this guild is uncached.',
INVALID_TYPE: (name, expected, an = false) => `Supplied ${name} is not a${an ? 'n' : ''} ${expected}.`,
@@ -88,15 +88,15 @@ const Messages = {
EMOJI_TYPE: 'Emoji must be a string or GuildEmoji/ReactionEmoji',
EMOJI_MANAGED: 'Emoji is managed and has no Author.',
MISSING_MANAGE_EMOJIS_PERMISSION:
guild => `Client must have Manage Emoji permission in guild ${guild} to see emoji authors.`,
MISSING_MANAGE_EMOJIS_PERMISSION: guild =>
`Client must have Manage Emoji permission in guild ${guild} to see emoji authors.`,
REACTION_RESOLVE_USER: 'Couldn\'t resolve the user ID to remove from the reaction.',
REACTION_RESOLVE_USER: "Couldn't resolve the user ID to remove from the reaction.",
VANITY_URL: 'This guild does not have the VANITY_URL feature enabled.',
DELETE_GROUP_DM_CHANNEL: 'Bots don\'t have access to Group DM Channels and cannot delete them',
FETCH_GROUP_DM_CHANNEL: 'Bots don\'t have access to Group DM Channels and cannot fetch them',
DELETE_GROUP_DM_CHANNEL: "Bots don't have access to Group DM Channels and cannot delete them",
FETCH_GROUP_DM_CHANNEL: "Bots don't have access to Group DM Channels and cannot fetch them",
};
for (const [name, message] of Object.entries(Messages)) register(name, message);

View File

@@ -34,9 +34,9 @@ class BaseManager {
this.cacheType = cacheType;
/**
* Holds the cache for the data model
* @type {Collection}
*/
* Holds the cache for the data model
* @type {Collection}
*/
this.cache = new cacheType(...cacheOptions);
if (iterable) for (const i of iterable) this.add(i);
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Channel = require('../structures/Channel');
const BaseManager = require('./BaseManager');
const Channel = require('../structures/Channel');
const { Events } = require('../util/Constants');
/**
@@ -14,10 +14,10 @@ class ChannelManager extends BaseManager {
}
/**
* The cache of Channels
* @type {Collection<Snowflake, Channel>}
* @name ChannelManager#cache
*/
* The cache of Channels
* @type {Collection<Snowflake, Channel>}
* @name ChannelManager#cache
*/
add(data, guild, cache = true) {
const existing = this.cache.get(data.id);

View File

@@ -1,9 +1,9 @@
'use strict';
const { ChannelTypes } = require('../util/Constants');
const BaseManager = require('./BaseManager');
const GuildChannel = require('../structures/GuildChannel');
const PermissionOverwrites = require('../structures/PermissionOverwrites');
const { ChannelTypes } = require('../util/Constants');
/**
* Manages API methods for GuildChannels and stores their cache.

View File

@@ -1,11 +1,11 @@
'use strict';
const Collection = require('../util/Collection');
const BaseManager = require('./BaseManager');
const { TypeError } = require('../errors');
const GuildEmoji = require('../structures/GuildEmoji');
const ReactionEmoji = require('../structures/ReactionEmoji');
const Collection = require('../util/Collection');
const DataResolver = require('../util/DataResolver');
const { TypeError } = require('../errors');
/**
* Manages API methods for GuildEmojis and stores their cache.
@@ -22,10 +22,10 @@ class GuildEmojiManager extends BaseManager {
}
/**
* The cache of GuildEmojis
* @type {Collection<Snowflake, GuildEmoji>}
* @name GuildEmojiManager#cache
*/
* The cache of GuildEmojis
* @type {Collection<Snowflake, GuildEmoji>}
* @name GuildEmojiManager#cache
*/
add(data, cache) {
return super.add(data, cache, { extras: [this.guild] });
@@ -58,14 +58,17 @@ class GuildEmojiManager extends BaseManager {
for (let role of roles instanceof Collection ? roles.values() : roles) {
role = this.guild.roles.resolve(role);
if (!role) {
return Promise.reject(new TypeError('INVALID_TYPE', 'options.roles',
'Array or Collection of Roles or Snowflakes', true));
return Promise.reject(
new TypeError('INVALID_TYPE', 'options.roles', 'Array or Collection of Roles or Snowflakes', true),
);
}
data.roles.push(role.id);
}
}
return this.client.api.guilds(this.guild.id).emojis.post({ data, reason })
return this.client.api
.guilds(this.guild.id)
.emojis.post({ data, reason })
.then(emoji => this.client.actions.GuildEmojiCreate.handle(this.guild, emoji).emoji);
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Collection = require('../util/Collection');
const { TypeError } = require('../errors');
const Collection = require('../util/Collection');
/**
* Manages API methods for roles belonging to emojis and stores their cache.
@@ -56,8 +56,7 @@ class GuildEmojiRoleManager {
roleOrRoles = roleOrRoles.map(r => this.guild.roles.resolve(r));
if (roleOrRoles.includes(null)) {
return Promise.reject(new TypeError('INVALID_TYPE', 'roles',
'Array or Collection of Roles or Snowflakes', true));
return Promise.reject(new TypeError('INVALID_TYPE', 'roles', 'Array or Collection of Roles or Snowflakes', true));
}
const newRoles = [...new Set(roleOrRoles.concat(...this._roles.values()))];
@@ -75,8 +74,7 @@ class GuildEmojiRoleManager {
roleOrRoles = roleOrRoles.map(r => this.guild.roles.resolveID(r));
if (roleOrRoles.includes(null)) {
return Promise.reject(new TypeError('INVALID_TYPE', 'roles',
'Array or Collection of Roles or Snowflakes', true));
return Promise.reject(new TypeError('INVALID_TYPE', 'roles', 'Array or Collection of Roles or Snowflakes', true));
}
const newRoles = this._roles.keyArray().filter(role => !roleOrRoles.includes(role));

View File

@@ -1,21 +1,21 @@
'use strict';
const BaseManager = require('./BaseManager');
const DataResolver = require('../util/DataResolver');
const Guild = require('../structures/Guild');
const GuildChannel = require('../structures/GuildChannel');
const GuildEmoji = require('../structures/GuildEmoji');
const GuildMember = require('../structures/GuildMember');
const Invite = require('../structures/Invite');
const Role = require('../structures/Role');
const {
Events,
VerificationLevels,
DefaultMessageNotifications,
ExplicitContentFilterLevels,
} = require('../util/Constants');
const Guild = require('../structures/Guild');
const GuildChannel = require('../structures/GuildChannel');
const GuildMember = require('../structures/GuildMember');
const DataResolver = require('../util/DataResolver');
const Permissions = require('../util/Permissions');
const { resolveColor } = require('../util/Util');
const GuildEmoji = require('../structures/GuildEmoji');
const Invite = require('../structures/Invite');
const Role = require('../structures/Role');
/**
* Manages API methods for Guilds and stores their cache.
@@ -91,11 +91,15 @@ class GuildManager extends BaseManager {
* @returns {?Guild}
*/
resolve(guild) {
if (guild instanceof GuildChannel ||
if (
guild instanceof GuildChannel ||
guild instanceof GuildMember ||
guild instanceof GuildEmoji ||
guild instanceof Role ||
(guild instanceof Invite && guild.guild)) return super.resolve(guild.guild);
(guild instanceof Invite && guild.guild)
) {
return super.resolve(guild.guild);
}
return super.resolve(guild);
}
@@ -108,11 +112,15 @@ class GuildManager extends BaseManager {
* @returns {?Snowflake}
*/
resolveID(guild) {
if (guild instanceof GuildChannel ||
if (
guild instanceof GuildChannel ||
guild instanceof GuildMember ||
guild instanceof GuildEmoji ||
guild instanceof Role ||
(guild instanceof Invite && guild.guild)) return super.resolveID(guild.guild.id);
(guild instanceof Invite && guild.guild)
) {
return super.resolveID(guild.guild.id);
}
return super.resolveID(guild);
}
@@ -132,15 +140,18 @@ class GuildManager extends BaseManager {
* @param {VerificationLevel} [options.verificationLevel] The verification level for the guild
* @returns {Promise<Guild>} The guild that was created
*/
async create(name, {
channels = [],
defaultMessageNotifications,
explicitContentFilter,
icon = null,
region,
roles = [],
verificationLevel,
} = {}) {
async create(
name,
{
channels = [],
defaultMessageNotifications,
explicitContentFilter,
icon = null,
region,
roles = [],
verificationLevel,
} = {},
) {
icon = await DataResolver.resolveImage(icon);
if (typeof verificationLevel !== 'undefined' && typeof verificationLevel !== 'number') {
verificationLevel = VerificationLevels.indexOf(verificationLevel);
@@ -167,16 +178,19 @@ class GuildManager extends BaseManager {
if (role.permissions) role.permissions = Permissions.resolve(role.permissions);
}
return new Promise((resolve, reject) =>
this.client.api.guilds.post({ data: {
name,
region,
icon,
verification_level: verificationLevel,
default_message_notifications: defaultMessageNotifications,
explicit_content_filter: explicitContentFilter,
channels,
roles,
} })
this.client.api.guilds
.post({
data: {
name,
region,
icon,
verification_level: verificationLevel,
default_message_notifications: defaultMessageNotifications,
explicit_content_filter: explicitContentFilter,
channels,
roles,
},
})
.then(data => {
if (this.client.guilds.cache.has(data.id)) return resolve(this.client.guilds.cache.get(data.id));

View File

@@ -1,10 +1,10 @@
'use strict';
const BaseManager = require('./BaseManager');
const GuildMember = require('../structures/GuildMember');
const { Events, OPCodes } = require('../util/Constants');
const Collection = require('../util/Collection');
const { Error, TypeError } = require('../errors');
const GuildMember = require('../structures/GuildMember');
const Collection = require('../util/Collection');
const { Events, OPCodes } = require('../util/Constants');
/**
* Manages API methods for GuildMembers and stores their cache.
@@ -148,10 +148,15 @@ class GuildMemberManager extends BaseManager {
*/
prune({ days = 7, dry = false, count = true, reason } = {}) {
if (typeof days !== 'number') throw new TypeError('PRUNE_DAYS_TYPE');
return this.client.api.guilds(this.guild.id).prune[dry ? 'get' : 'post']({ query: {
days,
compute_prune_count: count,
}, reason })
return this.client.api
.guilds(this.guild.id)
.prune[dry ? 'get' : 'post']({
query: {
days,
compute_prune_count: count,
},
reason,
})
.then(data => data.pruned);
}
@@ -174,7 +179,9 @@ class GuildMemberManager extends BaseManager {
if (options.days) options['delete-message-days'] = options.days;
const id = this.client.users.resolveID(user);
if (!id) return Promise.reject(new Error('BAN_RESOLVE_ID', true));
return this.client.api.guilds(this.guild.id).bans[id].put({ query: options })
return this.client.api
.guilds(this.guild.id)
.bans[id].put({ query: options })
.then(() => {
if (user instanceof GuildMember) return user;
const _user = this.client.users.resolve(id);
@@ -200,21 +207,25 @@ class GuildMemberManager extends BaseManager {
unban(user, reason) {
const id = this.client.users.resolveID(user);
if (!id) return Promise.reject(new Error('BAN_RESOLVE_ID'));
return this.client.api.guilds(this.guild.id).bans[id].delete({ reason })
return this.client.api
.guilds(this.guild.id)
.bans[id].delete({ reason })
.then(() => this.client.users.resolve(user));
}
_fetchSingle({ user, cache }) {
const existing = this.cache.get(user);
if (existing && !existing.partial) return Promise.resolve(existing);
return this.client.api.guilds(this.guild.id).members(user).get()
return this.client.api
.guilds(this.guild.id)
.members(user)
.get()
.then(data => this.add(data, cache));
}
_fetchMany({ limit = 0, withPresences: presences = false, user: user_ids, query } = {}) {
return new Promise((resolve, reject) => {
if (this.guild.memberCount === this.cache.size && (!query && !limit && !presences && !user_ids)) {
if (this.guild.memberCount === this.cache.size && !query && !limit && !presences && !user_ids) {
resolve(this.cache);
return;
}
@@ -237,9 +248,11 @@ class GuildMemberManager extends BaseManager {
for (const member of members.values()) {
if (option) fetchedMembers.set(member.id, member);
}
if (this.guild.memberCount <= this.cache.size ||
if (
this.guild.memberCount <= this.cache.size ||
(option && members.size < 1000) ||
(limit && fetchedMembers.size >= limit)) {
(limit && fetchedMembers.size >= limit)
) {
this.guild.client.removeListener(Events.GUILD_MEMBERS_CHUNK, handler);
let fetched = option ? fetchedMembers : this.cache;
if (user_ids && !Array.isArray(user_ids) && fetched.size) fetched = fetched.first();

View File

@@ -1,7 +1,7 @@
'use strict';
const Collection = require('../util/Collection');
const { TypeError } = require('../errors');
const Collection = require('../util/Collection');
/**
* Manages API methods for roles of a GuildMember and stores their cache.
@@ -49,7 +49,7 @@ class GuildMemberRoleManager {
get hoist() {
const hoistedRoles = this._roles.filter(role => role.hoist);
if (!hoistedRoles.size) return null;
return hoistedRoles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev);
return hoistedRoles.reduce((prev, role) => (!prev || role.comparePositionTo(prev) > 0 ? role : prev));
}
/**
@@ -60,7 +60,7 @@ class GuildMemberRoleManager {
get color() {
const coloredRoles = this._roles.filter(role => role.color);
if (!coloredRoles.size) return null;
return coloredRoles.reduce((prev, role) => !prev || role.comparePositionTo(prev) > 0 ? role : prev);
return coloredRoles.reduce((prev, role) => (!prev || role.comparePositionTo(prev) > 0 ? role : prev));
}
/**
@@ -69,7 +69,7 @@ class GuildMemberRoleManager {
* @readonly
*/
get highest() {
return this._roles.reduce((prev, role) => role.comparePositionTo(prev) > 0 ? role : prev, this._roles.first());
return this._roles.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev), this._roles.first());
}
/**
@@ -82,8 +82,7 @@ class GuildMemberRoleManager {
if (roleOrRoles instanceof Collection || Array.isArray(roleOrRoles)) {
roleOrRoles = roleOrRoles.map(r => this.guild.roles.resolve(r));
if (roleOrRoles.includes(null)) {
throw new TypeError('INVALID_TYPE', 'roles',
'Array or Collection of Roles or Snowflakes', true);
throw new TypeError('INVALID_TYPE', 'roles', 'Array or Collection of Roles or Snowflakes', true);
}
const newRoles = [...new Set(roleOrRoles.concat(...this._roles.values()))];
@@ -91,8 +90,7 @@ class GuildMemberRoleManager {
} else {
roleOrRoles = this.guild.roles.resolve(roleOrRoles);
if (roleOrRoles === null) {
throw new TypeError('INVALID_TYPE', 'roles',
'Array or Collection of Roles or Snowflakes', true);
throw new TypeError('INVALID_TYPE', 'roles', 'Array or Collection of Roles or Snowflakes', true);
}
await this.client.api.guilds[this.guild.id].members[this.member.id].roles[roleOrRoles.id].put({ reason });
@@ -113,8 +111,7 @@ class GuildMemberRoleManager {
if (roleOrRoles instanceof Collection || Array.isArray(roleOrRoles)) {
roleOrRoles = roleOrRoles.map(r => this.guild.roles.resolve(r));
if (roleOrRoles.includes(null)) {
throw new TypeError('INVALID_TYPE', 'roles',
'Array or Collection of Roles or Snowflakes', true);
throw new TypeError('INVALID_TYPE', 'roles', 'Array or Collection of Roles or Snowflakes', true);
}
const newRoles = this._roles.filter(role => !roleOrRoles.includes(role));
@@ -122,8 +119,7 @@ class GuildMemberRoleManager {
} else {
roleOrRoles = this.guild.roles.resolve(roleOrRoles);
if (roleOrRoles === null) {
throw new TypeError('INVALID_TYPE', 'roles',
'Array or Collection of Roles or Snowflakes', true);
throw new TypeError('INVALID_TYPE', 'roles', 'Array or Collection of Roles or Snowflakes', true);
}
await this.client.api.guilds[this.guild.id].members[this.member.id].roles[roleOrRoles.id].delete({ reason });

View File

@@ -2,82 +2,82 @@
const BaseManager = require('./BaseManager');
const Message = require('../structures/Message');
const LimitedCollection = require('../util/LimitedCollection');
const Collection = require('../util/Collection');
const LimitedCollection = require('../util/LimitedCollection');
/**
* Manages API methods for Messages and holds their cache.
* @extends {BaseManager}
*/
* 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}
*/
* The channel that the messages belong to
* @type {TextBasedChannel}
*/
this.channel = channel;
}
/**
* The cache of Messages
* @type {LimitedCollection<Snowflake, Message>}
* @name MessageManager#cache
*/
* The cache of Messages
* @type {LimitedCollection<Snowflake, Message>}
* @name MessageManager#cache
*/
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
*/
* 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);
*/
* 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);
*/
* 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();
@@ -94,23 +94,22 @@ class MessageManager extends BaseManager {
*/
/**
* 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 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}
*/
* 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.
@@ -119,7 +118,12 @@ class MessageManager extends BaseManager {
*/
async delete(message, reason) {
message = this.resolveID(message);
if (message) await this.client.api.channels(this.channel.id).messages(message).delete({ reason });
if (message) {
await this.client.api
.channels(this.channel.id)
.messages(message)
.delete({ reason });
}
}
async _fetchId(messageID, cache) {

View File

@@ -1,7 +1,7 @@
'use strict';
const { Presence } = require('../structures/Presence');
const BaseManager = require('./BaseManager');
const { Presence } = require('../structures/Presence');
/**
* Manages API methods for Presences and holds their cache.
@@ -13,10 +13,10 @@ class PresenceManager extends BaseManager {
}
/**
* The cache of Presences
* @type {Collection<Snowflake, Presence>}
* @name PresenceManager#cache
*/
* The cache of Presences
* @type {Collection<Snowflake, Presence>}
* @name PresenceManager#cache
*/
add(data, cache) {
const existing = this.cache.get(data.user.id);
@@ -32,10 +32,10 @@ class PresenceManager extends BaseManager {
*/
/**
* Resolves a PresenceResolvable to a Presence object.
* @param {PresenceResolvable} presence The presence resolvable to resolve
* @returns {?Presence}
*/
* Resolves a PresenceResolvable to a Presence object.
* @param {PresenceResolvable} presence The presence resolvable to resolve
* @returns {?Presence}
*/
resolve(presence) {
const presenceResolvable = super.resolve(presence);
if (presenceResolvable) return presenceResolvable;
@@ -44,10 +44,10 @@ class PresenceManager extends BaseManager {
}
/**
* Resolves a PresenceResolvable to a Presence ID string.
* @param {PresenceResolvable} presence The presence resolvable to resolve
* @returns {?Snowflake}
*/
* Resolves a PresenceResolvable to a Presence ID string.
* @param {PresenceResolvable} presence The presence resolvable to resolve
* @returns {?Snowflake}
*/
resolveID(presence) {
const presenceResolvable = super.resolveID(presence);
if (presenceResolvable) return presenceResolvable;

View File

@@ -1,7 +1,7 @@
'use strict';
const MessageReaction = require('../structures/MessageReaction');
const BaseManager = require('./BaseManager');
const MessageReaction = require('../structures/MessageReaction');
/**
* Manages API methods for reactions and holds their cache.
@@ -36,29 +36,32 @@ class ReactionManager extends BaseManager {
*/
/**
* Resolves a MessageReactionResolvable to a MessageReaction object.
* @method resolve
* @memberof ReactionManager
* @instance
* @param {MessageReactionResolvable} reaction The MessageReaction to resolve
* @returns {?MessageReaction}
*/
* Resolves a MessageReactionResolvable to a MessageReaction object.
* @method resolve
* @memberof ReactionManager
* @instance
* @param {MessageReactionResolvable} reaction The MessageReaction to resolve
* @returns {?MessageReaction}
*/
/**
* Resolves a MessageReactionResolvable to a MessageReaction ID string.
* @method resolveID
* @memberof ReactionManager
* @instance
* @param {MessageReactionResolvable} reaction The MessageReaction to resolve
* @returns {?Snowflake}
*/
* Resolves a MessageReactionResolvable to a MessageReaction ID string.
* @method resolveID
* @memberof ReactionManager
* @instance
* @param {MessageReactionResolvable} reaction The MessageReaction to resolve
* @returns {?Snowflake}
*/
/**
* Removes all reactions from a message.
* @returns {Promise<Message>}
*/
removeAll() {
return this.client.api.channels(this.message.channel.id).messages(this.message.id).reactions.delete()
return this.client.api
.channels(this.message.channel.id)
.messages(this.message.id)
.reactions.delete()
.then(() => this.message);
}
@@ -72,7 +75,10 @@ class ReactionManager extends BaseManager {
const id = reactionEmoji.id || reactionEmoji.name;
const existing = this.cache.get(id);
if (!this._partial(reactionEmoji)) return existing;
const data = await this.client.api.channels(this.message.channel.id).messages(this.message.id).get();
const data = await this.client.api
.channels(this.message.channel.id)
.messages(this.message.id)
.get();
if (this.message.partial) this.message._patch(data);
if (!data.reactions || !data.reactions.some(r => (r.emoji.id || r.emoji.name) === id)) {
reactionEmoji.reaction._patch({ count: 0 });

View File

@@ -1,8 +1,8 @@
'use strict';
const Collection = require('../util/Collection');
const BaseManager = require('./BaseManager');
const { Error } = require('../errors');
const Collection = require('../util/Collection');
/**
* Manages API methods for users who reacted to a reaction and stores their cache.
@@ -34,9 +34,9 @@ class ReactionUserManager extends BaseManager {
*/
async fetch({ limit = 100, after, before } = {}) {
const message = this.reaction.message;
const data = await this.client.api.channels[message.channel.id].messages[message.id]
.reactions[this.reaction.emoji.identifier]
.get({ query: { limit, before, after } });
const data = await this.client.api.channels[message.channel.id].messages[message.id].reactions[
this.reaction.emoji.identifier
].get({ query: { limit, before, after } });
const users = new Collection();
for (const rawUser of data) {
const user = this.client.users.add(rawUser);
@@ -55,8 +55,9 @@ class ReactionUserManager extends BaseManager {
const message = this.reaction.message;
const userID = message.client.users.resolveID(user);
if (!userID) return Promise.reject(new Error('REACTION_RESOLVE_USER'));
return message.client.api.channels[message.channel.id].messages[message.id]
.reactions[this.reaction.emoji.identifier][userID === message.client.user.id ? '@me' : userID]
return message.client.api.channels[message.channel.id].messages[message.id].reactions[
this.reaction.emoji.identifier
][userID === message.client.user.id ? '@me' : userID]
.delete()
.then(() => this.reaction);
}

View File

@@ -2,8 +2,8 @@
const BaseManager = require('./BaseManager');
const Role = require('../structures/Role');
const { resolveColor } = require('../util/Util');
const Permissions = require('../util/Permissions');
const { resolveColor } = require('../util/Util');
/**
* Manages API methods for roles and stores their cache.
@@ -110,14 +110,17 @@ class RoleManager extends BaseManager {
if (data.color) data.color = resolveColor(data.color);
if (data.permissions) data.permissions = Permissions.resolve(data.permissions);
return this.guild.client.api.guilds(this.guild.id).roles.post({ data, reason }).then(r => {
const { role } = this.client.actions.GuildRoleCreate.handle({
guild_id: this.guild.id,
role: r,
return this.guild.client.api
.guilds(this.guild.id)
.roles.post({ data, reason })
.then(r => {
const { role } = this.client.actions.GuildRoleCreate.handle({
guild_id: this.guild.id,
role: r,
});
if (data.position) return role.setPosition(data.position, reason);
return role;
});
if (data.position) return role.setPosition(data.position, reason);
return role;
});
}
/**
@@ -135,7 +138,7 @@ class RoleManager extends BaseManager {
* @readonly
*/
get highest() {
return this.cache.reduce((prev, role) => role.comparePositionTo(prev) > 0 ? role : prev, this.cache.first());
return this.cache.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev), this.cache.first());
}
}

View File

@@ -1,9 +1,9 @@
'use strict';
const BaseManager = require('./BaseManager');
const User = require('../structures/User');
const GuildMember = require('../structures/GuildMember');
const Message = require('../structures/Message');
const User = require('../structures/User');
/**
* Manages API methods for users and stores their cache.

View File

@@ -1,10 +1,10 @@
'use strict';
const FormData = require('form-data');
const https = require('https');
const { browser, UserAgent } = require('../util/Constants');
const fetch = require('node-fetch');
const AbortController = require('abort-controller');
const FormData = require('form-data');
const fetch = require('node-fetch');
const { browser, UserAgent } = require('../util/Constants');
if (https.Agent) var agent = new https.Agent({ keepAlive: true });
@@ -26,8 +26,10 @@ class APIRequest {
}
make() {
const API = this.options.versioned === false ? this.client.options.http.api :
`${this.client.options.http.api}/v${this.client.options.http.version}`;
const API =
this.options.versioned === false
? this.client.options.http.api
: `${this.client.options.http.api}/v${this.client.options.http.version}`;
const url = API + this.path;
let headers = {};
@@ -42,7 +44,8 @@ class APIRequest {
for (const file of this.options.files) if (file && file.file) body.append(file.name, file.file, file.name);
if (typeof this.options.data !== 'undefined') body.append('payload_json', JSON.stringify(this.options.data));
if (!browser) headers = Object.assign(headers, body.getHeaders());
} else if (this.options.data != null) { // eslint-disable-line eqeqeq
// eslint-disable-next-line eqeqeq
} else if (this.options.data != null) {
body = JSON.stringify(this.options.data);
headers['Content-Type'] = 'application/json';
}

View File

@@ -3,8 +3,12 @@
const noop = () => {}; // eslint-disable-line no-empty-function
const methods = ['get', 'post', 'delete', 'patch', 'put'];
const reflectors = [
'toString', 'valueOf', 'inspect', 'constructor',
Symbol.toPrimitive, Symbol.for('nodejs.util.inspect.custom'),
'toString',
'valueOf',
'inspect',
'constructor',
Symbol.toPrimitive,
Symbol.for('nodejs.util.inspect.custom'),
];
function buildRoute(manager) {
@@ -22,10 +26,18 @@ function buildRoute(manager) {
// All other parts of the route should be considered as part of the bucket identifier
else routeBucket.push(route[i]);
}
return options => manager.request(name, route.join('/'), Object.assign({
versioned: manager.versioned,
route: routeBucket.join('/'),
}, options));
return options =>
manager.request(
name,
route.join('/'),
Object.assign(
{
versioned: manager.versioned,
route: routeBucket.join('/'),
},
options,
),
);
}
route.push(name);
return new Proxy(noop, handler);

View File

@@ -48,7 +48,7 @@ class DiscordAPIError extends Error {
for (const [k, v] of Object.entries(obj)) {
if (k === 'message') continue;
const newKey = key ? isNaN(k) ? `${key}.${k}` : `${key}[${k}]` : k;
const newKey = key ? (isNaN(k) ? `${key}.${k}` : `${key}[${k}]`) : k;
if (v._errors) {
messages.push(`${newKey}: ${v._errors.map(e => e.message).join(' ')}`);

View File

@@ -1,11 +1,11 @@
'use strict';
const RequestHandler = require('./RequestHandler');
const APIRequest = require('./APIRequest');
const routeBuilder = require('./APIRouter');
const RequestHandler = require('./RequestHandler');
const { Error } = require('../errors');
const { Endpoints } = require('../util/Constants');
const Collection = require('../util/Collection');
const { Endpoints } = require('../util/Constants');
class RESTManager {
constructor(client, tokenPrefix = 'Bot') {
@@ -37,12 +37,14 @@ class RESTManager {
push(handler, apiRequest) {
return new Promise((resolve, reject) => {
handler.push({
request: apiRequest,
resolve,
reject,
retries: 0,
}).catch(reject);
handler
.push({
request: apiRequest,
resolve,
reject,
retries: 0,
})
.catch(reject);
});
}

View File

@@ -2,8 +2,11 @@
const DiscordAPIError = require('./DiscordAPIError');
const HTTPError = require('./HTTPError');
const {
Events: { RATE_LIMIT },
browser,
} = require('../util/Constants');
const Util = require('../util/Util');
const { Events: { RATE_LIMIT }, browser } = require('../util/Constants');
function parseResponse(res) {
if (res.headers.get('content-type').startsWith('application/json')) return res.json();
@@ -52,7 +55,6 @@ class RequestHandler {
return this.queue.length === 0 && !this.limited && this.busy !== true;
}
/* eslint-disable-next-line complexity */
async execute(item) {
// Insert item back to the beginning if currently busy
if (this.busy) {
@@ -102,9 +104,7 @@ class RequestHandler {
} catch (error) {
// NodeFetch error expected for all "operational" errors, such as 500 status code
this.busy = false;
return reject(
new HTTPError(error.message, error.constructor.name, error.status, request.method, request.path),
);
return reject(new HTTPError(error.message, error.constructor.name, error.status, request.method, request.path));
}
if (res && res.headers) {
@@ -171,9 +171,7 @@ class RequestHandler {
}
return null;
} catch (err) {
return reject(
new HTTPError(err.message, err.constructor.name, err.status, request.method, request.path),
);
return reject(new HTTPError(err.message, err.constructor.name, err.status, request.method, request.path));
}
}
}

View File

@@ -2,8 +2,8 @@
const EventEmitter = require('events');
const path = require('path');
const Util = require('../util/Util');
const { Error } = require('../errors');
const Util = require('../util/Util');
let childProcess = null;
let Worker = null;
@@ -111,9 +111,11 @@ class Shard extends EventEmitter {
if (this.worker) throw new Error('SHARDING_WORKER_EXISTS', this.id);
if (this.manager.mode === 'process') {
this.process = childProcess.fork(path.resolve(this.manager.file), this.args, {
env: this.env, execArgv: this.execArgv,
})
this.process = childProcess
.fork(path.resolve(this.manager.file), this.args, {
env: this.env,
execArgv: this.execArgv,
})
.on('message', this._handleMessage.bind(this))
.on('exit', this._exitListener);
} else if (this.manager.mode === 'worker') {
@@ -203,7 +205,8 @@ class Shard extends EventEmitter {
return new Promise((resolve, reject) => {
if (this.process) {
this.process.send(message, err => {
if (err) reject(err); else resolve(this);
if (err) reject(err);
else resolve(this);
});
} else {
this.worker.postMessage(message);
@@ -261,7 +264,8 @@ class Shard extends EventEmitter {
if (!message || message._eval !== script) return;
child.removeListener('message', listener);
this._evals.delete(script);
if (!message._error) resolve(message._result); else reject(Util.makeError(message._error));
if (!message._error) resolve(message._result);
else reject(Util.makeError(message._error));
};
child.on('message', listener);

View File

@@ -1,7 +1,7 @@
'use strict';
const Util = require('../util/Util');
const { Events } = require('../util/Constants');
const Util = require('../util/Util');
/**
* Helper class for sharded clients spawned as a child process/worker, such as from a {@link ShardingManager}.
@@ -33,15 +33,27 @@ class ShardClientUtil {
if (mode === 'process') {
process.on('message', this._handleMessage.bind(this));
client.on('ready', () => { process.send({ _ready: true }); });
client.on('disconnect', () => { process.send({ _disconnect: true }); });
client.on('reconnecting', () => { process.send({ _reconnecting: true }); });
client.on('ready', () => {
process.send({ _ready: true });
});
client.on('disconnect', () => {
process.send({ _disconnect: true });
});
client.on('reconnecting', () => {
process.send({ _reconnecting: true });
});
} else if (mode === 'worker') {
this.parentPort = require('worker_threads').parentPort;
this.parentPort.on('message', this._handleMessage.bind(this));
client.on('ready', () => { this.parentPort.postMessage({ _ready: true }); });
client.on('disconnect', () => { this.parentPort.postMessage({ _disconnect: true }); });
client.on('reconnecting', () => { this.parentPort.postMessage({ _reconnecting: true }); });
client.on('ready', () => {
this.parentPort.postMessage({ _ready: true });
});
client.on('disconnect', () => {
this.parentPort.postMessage({ _disconnect: true });
});
client.on('reconnecting', () => {
this.parentPort.postMessage({ _reconnecting: true });
});
}
}
@@ -72,7 +84,8 @@ class ShardClientUtil {
return new Promise((resolve, reject) => {
if (this.mode === 'process') {
process.send(message, err => {
if (err) reject(err); else resolve();
if (err) reject(err);
else resolve();
});
} else if (this.mode === 'worker') {
this.parentPort.postMessage(message);
@@ -98,7 +111,8 @@ class ShardClientUtil {
const listener = message => {
if (!message || message._sFetchProp !== prop) return;
parent.removeListener('message', listener);
if (!message._error) resolve(message._result); else reject(Util.makeError(message._error));
if (!message._error) resolve(message._result);
else reject(Util.makeError(message._error));
};
parent.on('message', listener);
@@ -127,7 +141,8 @@ class ShardClientUtil {
const listener = message => {
if (!message || message._sEval !== script) return;
parent.removeListener('message', listener);
if (!message._error) resolve(message._result); else reject(Util.makeError(message._error));
if (!message._error) resolve(message._result);
else reject(Util.makeError(message._error));
};
parent.on('message', listener);
@@ -201,8 +216,10 @@ class ShardClientUtil {
if (!this._singleton) {
this._singleton = new this(client, mode);
} else {
client.emit(Events.WARN,
'Multiple clients created in child process/worker; only the first will handle sharding helpers.');
client.emit(
Events.WARN,
'Multiple clients created in child process/worker; only the first will handle sharding helpers.',
);
}
return this._singleton;
}

View File

@@ -1,12 +1,12 @@
'use strict';
const path = require('path');
const fs = require('fs');
const EventEmitter = require('events');
const fs = require('fs');
const path = require('path');
const Shard = require('./Shard');
const { Error, TypeError, RangeError } = require('../errors');
const Collection = require('../util/Collection');
const Util = require('../util/Util');
const { Error, TypeError, RangeError } = require('../errors');
/**
* This is a utility class that makes multi-process sharding of a bot an easy and painless experience.
@@ -41,14 +41,17 @@ class ShardingManager extends EventEmitter {
*/
constructor(file, options = {}) {
super();
options = Util.mergeDefault({
totalShards: 'auto',
mode: 'process',
respawn: true,
shardArgs: [],
execArgv: [],
token: process.env.DISCORD_TOKEN,
}, options);
options = Util.mergeDefault(
{
totalShards: 'auto',
mode: 'process',
respawn: true,
shardArgs: [],
execArgv: [],
token: process.env.DISCORD_TOKEN,
},
options,
);
/**
* Path to the shard script file
@@ -71,8 +74,11 @@ class ShardingManager extends EventEmitter {
}
this.shardList = [...new Set(this.shardList)];
if (this.shardList.length < 1) throw new RangeError('CLIENT_INVALID_OPTION', 'shardList', 'at least 1 ID.');
if (this.shardList.some(shardID => typeof shardID !== 'number' || isNaN(shardID) ||
!Number.isInteger(shardID) || shardID < 0)) {
if (
this.shardList.some(
shardID => typeof shardID !== 'number' || isNaN(shardID) || !Number.isInteger(shardID) || shardID < 0,
)
) {
throw new TypeError('CLIENT_INVALID_OPTION', 'shardList', 'an array of positive integers.');
}
}
@@ -186,8 +192,11 @@ class ShardingManager extends EventEmitter {
}
if (this.shardList.some(shardID => shardID >= amount)) {
throw new RangeError('CLIENT_INVALID_OPTION', 'Amount of shards',
'bigger than the highest shardID in the shardList option.');
throw new RangeError(
'CLIENT_INVALID_OPTION',
'Amount of shards',
'bigger than the highest shardID in the shardList option.',
);
}
// Spawn the shards

View File

@@ -1,12 +1,12 @@
'use strict';
const DataResolver = require('../util/DataResolver');
const MessageEmbed = require('./MessageEmbed');
const MessageAttachment = require('./MessageAttachment');
const { browser } = require('../util/Constants');
const Util = require('../util/Util');
const MessageEmbed = require('./MessageEmbed');
const { RangeError } = require('../errors');
const { browser } = require('../util/Constants');
const DataResolver = require('../util/DataResolver');
const MessageFlags = require('../util/MessageFlags');
const Util = require('../util/Util');
/**
* Represents a message to be sent to the API.
@@ -78,7 +78,7 @@ class APIMessage {
* Makes the content of this message.
* @returns {?(string|string[])}
*/
makeContent() { // eslint-disable-line complexity
makeContent() {
const GuildMember = require('./GuildMember');
let content;
@@ -88,13 +88,14 @@ class APIMessage {
content = Util.resolveString(this.options.content);
}
const disableMentions = typeof this.options.disableMentions === 'undefined' ?
this.target.client.options.disableMentions :
this.options.disableMentions;
const disableMentions =
typeof this.options.disableMentions === 'undefined'
? this.target.client.options.disableMentions
: this.options.disableMentions;
if (disableMentions === 'all') {
content = Util.removeMentions(content || '');
} else if (disableMentions === 'everyone') {
content = (content || '').replace(/@([^<>@ ]*)/gsmu, (match, target) => {
content = (content || '').replace(/@([^<>@ ]*)/gmsu, (match, target) => {
if (target.match(/^[&!]?\d+$/)) {
return `@${target}`;
} else {
@@ -270,7 +271,8 @@ class APIMessage {
return 'file.jpg';
};
const ownAttachment = typeof fileLike === 'string' ||
const ownAttachment =
typeof fileLike === 'string' ||
fileLike instanceof (browser ? ArrayBuffer : Buffer) ||
typeof fileLike.pipe === 'function';
if (ownAttachment) {

View File

@@ -20,7 +20,9 @@ class Base {
return Object.assign(Object.create(this), this);
}
_patch(data) { return data; }
_patch(data) {
return data;
}
_update(data) {
const clone = this._clone();

View File

@@ -1,8 +1,8 @@
'use strict';
const Snowflake = require('../util/Snowflake');
const Base = require('./Base');
const { ChannelTypes } = require('../util/Constants');
const Snowflake = require('../util/Snowflake');
/**
* Represents any channel on Discord.
@@ -82,7 +82,10 @@ class Channel extends Base {
* .catch(console.error);
*/
delete() {
return this.client.api.channels(this.id).delete().then(() => this);
return this.client.api
.channels(this.id)
.delete()
.then(() => this);
}
/**

View File

@@ -1,9 +1,9 @@
'use strict';
const Snowflake = require('../util/Snowflake');
const { ClientApplicationAssetTypes, Endpoints } = require('../util/Constants');
const Base = require('./Base');
const Team = require('./Team');
const { ClientApplicationAssetTypes, Endpoints } = require('../util/Constants');
const Snowflake = require('../util/Snowflake');
const AssetTypes = Object.keys(ClientApplicationAssetTypes);
@@ -70,11 +70,7 @@ class ClientApplication extends Base {
* The owner of this OAuth application
* @type {?User|Team}
*/
this.owner = data.team ?
new Team(this.client, data.team) :
data.owner ?
this.client.users.add(data.owner) :
null;
this.owner = data.team ? new Team(this.client, data.team) : data.owner ? this.client.users.add(data.owner) : null;
}
/**
@@ -112,9 +108,7 @@ class ClientApplication extends Base {
*/
coverImage({ format, size } = {}) {
if (!this.cover) return null;
return Endpoints
.CDN(this.client.options.http.cdn)
.AppIcon(this.id, this.cover, { format, size });
return Endpoints.CDN(this.client.options.http.cdn).AppIcon(this.id, this.cover, { format, size });
}
/**
@@ -130,12 +124,16 @@ class ClientApplication extends Base {
* @returns {Promise<Array<ClientAsset>>}
*/
fetchAssets() {
return this.client.api.oauth2.applications(this.id).assets.get()
.then(assets => assets.map(a => ({
id: a.id,
name: a.name,
type: AssetTypes[a.type - 1],
})));
return this.client.api.oauth2
.applications(this.id)
.assets.get()
.then(assets =>
assets.map(a => ({
id: a.id,
name: a.name,
type: AssetTypes[a.type - 1],
})),
);
}
/**

View File

@@ -1,9 +1,9 @@
'use strict';
const { Presence } = require('./Presence');
const { TypeError } = require('../errors');
const Collection = require('../util/Collection');
const { ActivityTypes, OPCodes } = require('../util/Constants');
const { TypeError } = require('../errors');
class ClientPresence extends Presence {
/**
@@ -29,7 +29,7 @@ class ClientPresence extends Presence {
return this;
}
async _parse({ status, since, afk, activity }) { // eslint-disable-line complexity
async _parse({ status, since, afk, activity }) {
const applicationID = activity && (activity.application ? activity.application.id || activity.application : null);
let assets = new Collection();
if (activity) {
@@ -47,24 +47,28 @@ class ClientPresence extends Presence {
afk: afk != null ? afk : false, // eslint-disable-line eqeqeq
since: since != null ? since : null, // eslint-disable-line eqeqeq
status: status || this.status,
game: activity ? {
type: activity.type,
name: activity.name,
url: activity.url,
details: activity.details || undefined,
state: activity.state || undefined,
assets: activity.assets ? {
large_text: activity.assets.largeText || undefined,
small_text: activity.assets.smallText || undefined,
large_image: assets.get(activity.assets.largeImage) || activity.assets.largeImage,
small_image: assets.get(activity.assets.smallImage) || activity.assets.smallImage,
} : undefined,
timestamps: activity.timestamps || undefined,
party: activity.party || undefined,
application_id: applicationID || undefined,
secrets: activity.secrets || undefined,
instance: activity.instance || undefined,
} : null,
game: activity
? {
type: activity.type,
name: activity.name,
url: activity.url,
details: activity.details || undefined,
state: activity.state || undefined,
assets: activity.assets
? {
large_text: activity.assets.largeText || undefined,
small_text: activity.assets.smallText || undefined,
large_image: assets.get(activity.assets.largeImage) || activity.assets.largeImage,
small_image: assets.get(activity.assets.smallImage) || activity.assets.smallImage,
}
: undefined,
timestamps: activity.timestamps || undefined,
party: activity.party || undefined,
application_id: applicationID || undefined,
secrets: activity.secrets || undefined,
instance: activity.instance || undefined,
}
: null,
};
if ((status || afk || since) && !activity) {
@@ -72,8 +76,8 @@ class ClientPresence extends Presence {
}
if (packet.game) {
packet.game.type = typeof packet.game.type === 'number' ?
packet.game.type : ActivityTypes.indexOf(packet.game.type);
packet.game.type =
typeof packet.game.type === 'number' ? packet.game.type : ActivityTypes.indexOf(packet.game.type);
}
return packet;

View File

@@ -1,7 +1,7 @@
'use strict';
const Structures = require('../util/Structures');
const DataResolver = require('../util/DataResolver');
const Structures = require('../util/Structures');
/**
* Represents the logged in client's Discord user.
@@ -47,7 +47,9 @@ class ClientUser extends Structures.get('User') {
}
edit(data) {
return this.client.api.users('@me').patch({ data })
return this.client.api
.users('@me')
.patch({ data })
.then(newData => {
this.client.token = newData.token;
const { updated } = this.client.actions.UserUpdate.handle(newData);

View File

@@ -1,8 +1,7 @@
'use strict';
const Snowflake = require('../util/Snowflake');
const Base = require('./Base');
const Snowflake = require('../util/Snowflake');
/**
* Represents an emoji, see {@link GuildEmoji} and {@link ReactionEmoji}.

View File

@@ -1,10 +1,18 @@
'use strict';
const Invite = require('./Invite');
const Integration = require('./Integration');
const Base = require('./Base');
const GuildAuditLogs = require('./GuildAuditLogs');
const Webhook = require('./Webhook');
const Integration = require('./Integration');
const Invite = require('./Invite');
const VoiceRegion = require('./VoiceRegion');
const Webhook = require('./Webhook');
const GuildChannelManager = require('../src/managers/GuildChannelManager');
const GuildEmojiManager = require('../src/managers/GuildEmojiManager');
const GuildMemberManager = require('../src/managers/GuildMemberManager');
const PresenceManager = require('../src/managers/PresenceManager');
const RoleManager = require('../src/managers/RoleManager');
const VoiceStateManager = require('../src/managers/VoiceStateManager');
const Collection = require('../util/Collection');
const {
ChannelTypes,
DefaultMessageNotifications,
@@ -12,19 +20,10 @@ const {
VerificationLevels,
ExplicitContentFilterLevels,
} = require('../util/Constants');
const Collection = require('../util/Collection');
const Util = require('../util/Util');
const DataResolver = require('../util/DataResolver');
const Snowflake = require('../util/Snowflake');
const SystemChannelFlags = require('../util/SystemChannelFlags');
const GuildMemberManager = require('../managers/GuildMemberManager');
const RoleManager = require('../managers/RoleManager');
const GuildEmojiManager = require('../managers/GuildEmojiManager');
const GuildChannelManager = require('../managers/GuildChannelManager');
const PresenceManager = require('../managers/PresenceManager');
const VoiceStateManager = require('../managers/VoiceStateManager');
const Base = require('./Base');
const { Error, TypeError } = require('../errors');
const Util = require('../util/Util');
/**
* Represents a guild (or a server) on Discord.
@@ -110,7 +109,6 @@ class Guild extends Base {
return this.client.ws.shards.get(this.shardID);
}
/* eslint-disable complexity */
/**
* Sets up the guild.
* @param {*} data The raw data of the guild
@@ -279,8 +277,8 @@ class Guild extends Base {
* The value set for the guild's default message notifications
* @type {DefaultMessageNotifications|number}
*/
this.defaultMessageNotifications = DefaultMessageNotifications[data.default_message_notifications] ||
data.default_message_notifications;
this.defaultMessageNotifications =
DefaultMessageNotifications[data.default_message_notifications] || data.default_message_notifications;
/**
* The value set for the guild's system channel flags
@@ -483,9 +481,12 @@ class Guild extends Base {
* @readonly
*/
get owner() {
return this.members.cache.get(this.ownerID) || (this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) ?
this.members.add({ user: { id: this.ownerID } }, true) :
null);
return (
this.members.cache.get(this.ownerID) ||
(this.client.options.partials.includes(PartialTypes.GUILD_MEMBER)
? this.members.add({ user: { id: this.ownerID } }, true)
: null)
);
}
/**
@@ -550,10 +551,12 @@ class Guild extends Base {
* @readonly
*/
get me() {
return this.members.cache.get(this.client.user.id) ||
(this.client.options.partials.includes(PartialTypes.GUILD_MEMBER) ?
this.members.add({ user: { id: this.client.user.id } }, true) :
null);
return (
this.members.cache.get(this.client.user.id) ||
(this.client.options.partials.includes(PartialTypes.GUILD_MEMBER)
? this.members.add({ user: { id: this.client.user.id } }, true)
: null)
);
}
/**
@@ -582,10 +585,13 @@ class Guild extends Base {
* @returns {Promise<Guild>}
*/
fetch() {
return this.client.api.guilds(this.id).get().then(data => {
this._patch(data);
return this;
});
return this.client.api
.guilds(this.id)
.get()
.then(data => {
this._patch(data);
return this;
});
}
/**
@@ -596,14 +602,17 @@ class Guild extends Base {
*/
/**
* Fetches information on a banned user from this guild.
* Fetches information on a banned user from this guild.
* @param {UserResolvable} user The User to fetch the ban info of
* @returns {Promise<BanInfo>}
*/
fetchBan(user) {
const id = this.client.users.resolveID(user);
if (!id) throw new Error('FETCH_BAN_RESOLVE_ID');
return this.client.api.guilds(this.id).bans(id).get()
return this.client.api
.guilds(this.id)
.bans(id)
.get()
.then(ban => ({
reason: ban.reason,
user: this.client.users.add(ban.user),
@@ -615,15 +624,18 @@ class Guild extends Base {
* @returns {Promise<Collection<Snowflake, BanInfo>>}
*/
fetchBans() {
return this.client.api.guilds(this.id).bans.get().then(bans =>
bans.reduce((collection, ban) => {
collection.set(ban.user.id, {
reason: ban.reason,
user: this.client.users.add(ban.user),
});
return collection;
}, new Collection()),
);
return this.client.api
.guilds(this.id)
.bans.get()
.then(bans =>
bans.reduce((collection, ban) => {
collection.set(ban.user.id, {
reason: ban.reason,
user: this.client.users.add(ban.user),
});
return collection;
}, new Collection()),
);
}
/**
@@ -637,11 +649,15 @@ class Guild extends Base {
* .catch(console.error);
*/
fetchIntegrations() {
return this.client.api.guilds(this.id).integrations.get().then(data =>
data.reduce((collection, integration) =>
collection.set(integration.id, new Integration(this.client, integration, this)),
new Collection()),
);
return this.client.api
.guilds(this.id)
.integrations.get()
.then(data =>
data.reduce(
(collection, integration) => collection.set(integration.id, new Integration(this.client, integration, this)),
new Collection(),
),
);
}
/**
@@ -658,7 +674,9 @@ class Guild extends Base {
* @returns {Promise<Guild>}
*/
createIntegration(data, reason) {
return this.client.api.guilds(this.id).integrations.post({ data, reason })
return this.client.api
.guilds(this.id)
.integrations.post({ data, reason })
.then(() => this);
}
@@ -678,7 +696,9 @@ class Guild extends Base {
* .catch(console.error);
*/
fetchInvites() {
return this.client.api.guilds(this.id).invites.get()
return this.client.api
.guilds(this.id)
.invites.get()
.then(inviteItems => {
const invites = new Collection();
for (const inviteItem of inviteItems) {
@@ -705,7 +725,9 @@ class Guild extends Base {
if (!this.features.includes('VANITY_URL')) {
return Promise.reject(new Error('VANITY_URL'));
}
return this.client.api.guilds(this.id, 'vanity-url').get()
return this.client.api
.guilds(this.id, 'vanity-url')
.get()
.then(res => res.code);
}
@@ -719,11 +741,14 @@ class Guild extends Base {
* .catch(console.error);
*/
fetchWebhooks() {
return this.client.api.guilds(this.id).webhooks.get().then(data => {
const hooks = new Collection();
for (const hook of data) hooks.set(hook.id, new Webhook(this.client, hook));
return hooks;
});
return this.client.api
.guilds(this.id)
.webhooks.get()
.then(data => {
const hooks = new Collection();
for (const hook of data) hooks.set(hook.id, new Webhook(this.client, hook));
return hooks;
});
}
/**
@@ -731,11 +756,14 @@ class Guild extends Base {
* @returns {Promise<Collection<string, VoiceRegion>>}
*/
fetchVoiceRegions() {
return this.client.api.guilds(this.id).regions.get().then(res => {
const regions = new Collection();
for (const region of res) regions.set(region.id, new VoiceRegion(region));
return regions;
});
return this.client.api
.guilds(this.id)
.regions.get()
.then(res => {
const regions = new Collection();
for (const region of res) regions.set(region.id, new VoiceRegion(region));
return regions;
});
}
/**
@@ -755,10 +783,13 @@ class Guild extends Base {
* .catch(console.error);
*/
fetchEmbed() {
return this.client.api.guilds(this.id).embed.get().then(data => ({
enabled: data.enabled,
channel: data.channel_id ? this.channels.cache.get(data.channel_id) : null,
}));
return this.client.api
.guilds(this.id)
.embed.get()
.then(data => ({
enabled: data.enabled,
channel: data.channel_id ? this.channels.cache.get(data.channel_id) : null,
}));
}
/**
@@ -779,12 +810,16 @@ class Guild extends Base {
if (options.before && options.before instanceof GuildAuditLogs.Entry) options.before = options.before.id;
if (typeof options.type === 'string') options.type = GuildAuditLogs.Actions[options.type];
return this.client.api.guilds(this.id)['audit-logs'].get({ query: {
before: options.before,
limit: options.limit,
user_id: this.client.users.resolveID(options.user),
action_type: options.type,
} })
return this.client.api
.guilds(this.id)
['audit-logs'].get({
query: {
before: options.before,
limit: options.limit,
user_id: this.client.users.resolveID(options.user),
action_type: options.type,
},
})
.then(data => GuildAuditLogs.build(this, data));
}
@@ -811,14 +846,18 @@ class Guild extends Base {
for (let role of options.roles instanceof Collection ? options.roles.values() : options.roles) {
role = this.roles.resolve(role);
if (!role) {
return Promise.reject(new TypeError('INVALID_TYPE', 'options.roles',
'Array or Collection of Roles or Snowflakes', true));
return Promise.reject(
new TypeError('INVALID_TYPE', 'options.roles', 'Array or Collection of Roles or Snowflakes', true),
);
}
roles.push(role.id);
}
options.roles = roles;
}
return this.client.api.guilds(this.id).members(user).put({ data: options })
return this.client.api
.guilds(this.id)
.members(user)
.put({ data: options })
.then(data => this.members.add(data));
}
@@ -859,9 +898,10 @@ class Guild extends Base {
if (data.name) _data.name = data.name;
if (data.region) _data.region = data.region;
if (typeof data.verificationLevel !== 'undefined') {
_data.verification_level = typeof data.verificationLevel === 'number' ?
Number(data.verificationLevel) :
ExplicitContentFilterLevels.indexOf(data.verificationLevel);
_data.verification_level =
typeof data.verificationLevel === 'number'
? Number(data.verificationLevel)
: ExplicitContentFilterLevels.indexOf(data.verificationLevel);
}
if (typeof data.afkChannel !== 'undefined') {
_data.afk_channel_id = this.client.channels.resolveID(data.afkChannel);
@@ -875,19 +915,23 @@ class Guild extends Base {
if (data.splash) _data.splash = data.splash;
if (data.banner) _data.banner = data.banner;
if (typeof data.explicitContentFilter !== 'undefined') {
_data.explicit_content_filter = typeof data.explicitContentFilter === 'number' ?
data.explicitContentFilter :
ExplicitContentFilterLevels.indexOf(data.explicitContentFilter);
_data.explicit_content_filter =
typeof data.explicitContentFilter === 'number'
? data.explicitContentFilter
: ExplicitContentFilterLevels.indexOf(data.explicitContentFilter);
}
if (typeof data.defaultMessageNotifications !== 'undefined') {
_data.default_message_notifications = typeof data.defaultMessageNotifications === 'string' ?
DefaultMessageNotifications.indexOf(data.defaultMessageNotifications) :
data.defaultMessageNotifications;
_data.default_message_notifications =
typeof data.defaultMessageNotifications === 'string'
? DefaultMessageNotifications.indexOf(data.defaultMessageNotifications)
: data.defaultMessageNotifications;
}
if (typeof data.systemChannelFlags !== 'undefined') {
_data.system_channel_flags = SystemChannelFlags.resolve(data.systemChannelFlags);
}
return this.client.api.guilds(this.id).patch({ data: _data, reason })
return this.client.api
.guilds(this.id)
.patch({ data: _data, reason })
.then(newData => this.client.actions.GuildUpdate.handle(newData).updated);
}
@@ -1094,12 +1138,16 @@ class Guild extends Base {
position: r.position,
}));
return this.client.api.guilds(this.id).channels.patch({ data: updatedChannels }).then(() =>
this.client.actions.GuildChannelsPositionUpdate.handle({
guild_id: this.id,
channels: updatedChannels,
}).guild,
);
return this.client.api
.guilds(this.id)
.channels.patch({ data: updatedChannels })
.then(
() =>
this.client.actions.GuildChannelsPositionUpdate.handle({
guild_id: this.id,
channels: updatedChannels,
}).guild,
);
}
/**
@@ -1126,14 +1174,18 @@ class Guild extends Base {
}));
// Call the API to update role positions
return this.client.api.guilds(this.id).roles.patch({
data: rolePositions,
}).then(() =>
this.client.actions.GuildRolePositionUpdate.handle({
guild_id: this.id,
roles: rolePositions,
}).guild,
);
return this.client.api
.guilds(this.id)
.roles.patch({
data: rolePositions,
})
.then(
() =>
this.client.actions.GuildRolePositionUpdate.handle({
guild_id: this.id,
roles: rolePositions,
}).guild,
);
}
/**
@@ -1143,13 +1195,16 @@ class Guild extends Base {
* @returns {Promise<Guild>}
*/
setEmbed(embed, reason) {
return this.client.api.guilds(this.id).embed.patch({
data: {
enabled: embed.enabled,
channel_id: this.channels.resolveID(embed.channel),
},
reason,
}).then(() => this);
return this.client.api
.guilds(this.id)
.embed.patch({
data: {
enabled: embed.enabled,
channel_id: this.channels.resolveID(embed.channel),
},
reason,
})
.then(() => this);
}
/**
@@ -1163,7 +1218,10 @@ class Guild extends Base {
*/
leave() {
if (this.ownerID === this.client.user.id) return Promise.reject(new Error('GUILD_OWNED'));
return this.client.api.users('@me').guilds(this.id).delete()
return this.client.api
.users('@me')
.guilds(this.id)
.delete()
.then(() => this.client.actions.GuildDelete.handle({ id: this.id }).guild);
}
@@ -1177,7 +1235,9 @@ class Guild extends Base {
* .catch(console.error);
*/
delete() {
return this.client.api.guilds(this.id).delete()
return this.client.api
.guilds(this.id)
.delete()
.then(() => this.client.actions.GuildDelete.handle({ id: this.id }).guild);
}
@@ -1203,10 +1263,9 @@ class Guild extends Base {
this.ownerID === guild.ownerID &&
this.verificationLevel === guild.verificationLevel &&
this.embedEnabled === guild.embedEnabled &&
(this.features === guild.features || (
this.features.length === guild.features.length &&
this.features.every((feat, i) => feat === guild.features[i]))
);
(this.features === guild.features ||
(this.features.length === guild.features.length &&
this.features.every((feat, i) => feat === guild.features[i])));
if (equal) {
if (this.embedChannel) {
@@ -1261,9 +1320,9 @@ class Guild extends Base {
*/
_sortedChannels(channel) {
const category = channel.type === ChannelTypes.CATEGORY;
return Util.discordSort(this.channels.cache.filter(c =>
c.type === channel.type && (category || c.parent === channel.parent),
));
return Util.discordSort(
this.channels.cache.filter(c => c.type === channel.type && (category || c.parent === channel.parent)),
);
}
}

View File

@@ -1,11 +1,11 @@
'use strict';
const Collection = require('../util/Collection');
const Integration = require('./Integration');
const Snowflake = require('../util/Snowflake');
const Webhook = require('./Webhook');
const Util = require('../util/Util');
const Collection = require('../util/Collection');
const { PartialTypes } = require('../util/Constants');
const Snowflake = require('../util/Snowflake');
const Util = require('../util/Util');
/**
* The target type of an entry, e.g. `GUILD`. Here are the available types:
@@ -125,7 +125,6 @@ const Actions = {
INTEGRATION_DELETE: 82,
};
/**
* Audit logs entries are held in this class.
*/
@@ -223,49 +222,61 @@ class GuildAuditLogs {
* @returns {AuditLogActionType}
*/
static actionType(action) {
if ([
Actions.CHANNEL_CREATE,
Actions.CHANNEL_OVERWRITE_CREATE,
Actions.MEMBER_BAN_REMOVE,
Actions.BOT_ADD,
Actions.ROLE_CREATE,
Actions.INVITE_CREATE,
Actions.WEBHOOK_CREATE,
Actions.EMOJI_CREATE,
Actions.MESSAGE_PIN,
Actions.INTEGRATION_CREATE,
].includes(action)) return 'CREATE';
if (
[
Actions.CHANNEL_CREATE,
Actions.CHANNEL_OVERWRITE_CREATE,
Actions.MEMBER_BAN_REMOVE,
Actions.BOT_ADD,
Actions.ROLE_CREATE,
Actions.INVITE_CREATE,
Actions.WEBHOOK_CREATE,
Actions.EMOJI_CREATE,
Actions.MESSAGE_PIN,
Actions.INTEGRATION_CREATE,
].includes(action)
) {
return 'CREATE';
}
if ([
Actions.CHANNEL_DELETE,
Actions.CHANNEL_OVERWRITE_DELETE,
Actions.MEMBER_KICK,
Actions.MEMBER_PRUNE,
Actions.MEMBER_BAN_ADD,
Actions.MEMBER_DISCONNECT,
Actions.ROLE_DELETE,
Actions.INVITE_DELETE,
Actions.WEBHOOK_DELETE,
Actions.EMOJI_DELETE,
Actions.MESSAGE_DELETE,
Actions.MESSAGE_BULK_DELETE,
Actions.MESSAGE_UNPIN,
Actions.INTEGRATION_DELETE,
].includes(action)) return 'DELETE';
if (
[
Actions.CHANNEL_DELETE,
Actions.CHANNEL_OVERWRITE_DELETE,
Actions.MEMBER_KICK,
Actions.MEMBER_PRUNE,
Actions.MEMBER_BAN_ADD,
Actions.MEMBER_DISCONNECT,
Actions.ROLE_DELETE,
Actions.INVITE_DELETE,
Actions.WEBHOOK_DELETE,
Actions.EMOJI_DELETE,
Actions.MESSAGE_DELETE,
Actions.MESSAGE_BULK_DELETE,
Actions.MESSAGE_UNPIN,
Actions.INTEGRATION_DELETE,
].includes(action)
) {
return 'DELETE';
}
if ([
Actions.GUILD_UPDATE,
Actions.CHANNEL_UPDATE,
Actions.CHANNEL_OVERWRITE_UPDATE,
Actions.MEMBER_UPDATE,
Actions.MEMBER_ROLE_UPDATE,
Actions.MEMBER_MOVE,
Actions.ROLE_UPDATE,
Actions.INVITE_UPDATE,
Actions.WEBHOOK_UPDATE,
Actions.EMOJI_UPDATE,
Actions.INTEGRATION_UPDATE,
].includes(action)) return 'UPDATE';
if (
[
Actions.GUILD_UPDATE,
Actions.CHANNEL_UPDATE,
Actions.CHANNEL_OVERWRITE_UPDATE,
Actions.MEMBER_UPDATE,
Actions.MEMBER_ROLE_UPDATE,
Actions.MEMBER_MOVE,
Actions.ROLE_UPDATE,
Actions.INVITE_UPDATE,
Actions.WEBHOOK_UPDATE,
Actions.EMOJI_UPDATE,
Actions.INTEGRATION_UPDATE,
].includes(action)
) {
return 'UPDATE';
}
return 'ALL';
}
@@ -279,7 +290,7 @@ class GuildAuditLogs {
* Audit logs entry.
*/
class GuildAuditLogsEntry {
constructor(logs, guild, data) { // eslint-disable-line complexity
constructor(logs, guild, data) {
const targetType = GuildAuditLogs.targetType(data.action_type);
/**
* The target type of this entry
@@ -309,9 +320,9 @@ class GuildAuditLogsEntry {
* The user that executed this entry
* @type {User}
*/
this.executor = guild.client.options.partials.includes(PartialTypes.USER) ?
guild.client.users.add({ id: data.user_id }) :
guild.client.users.cache.get(data.user_id);
this.executor = guild.client.options.partials.includes(PartialTypes.USER)
? guild.client.users.add({ id: data.user_id })
: guild.client.users.cache.get(data.user_id);
/**
* An entry in the audit log representing a specific change.
@@ -374,13 +385,15 @@ class GuildAuditLogsEntry {
case Actions.CHANNEL_OVERWRITE_DELETE:
switch (data.options.type) {
case 'member':
this.extra = guild.members.cache.get(data.options.id) ||
{ id: data.options.id, type: 'member' };
this.extra = guild.members.cache.get(data.options.id) || { id: data.options.id, type: 'member' };
break;
case 'role':
this.extra = guild.roles.cache.get(data.options.id) ||
{ id: data.options.id, name: data.options.role_name, type: 'role' };
this.extra = guild.roles.cache.get(data.options.id) || {
id: data.options.id,
name: data.options.role_name,
type: 'role',
};
break;
default:
@@ -405,21 +418,27 @@ class GuildAuditLogsEntry {
this.target.id = data.target_id;
// MEMBER_DISCONNECT and similar types do not provide a target_id.
} else if (targetType === Targets.USER && data.target_id) {
this.target = guild.client.options.partials.includes(PartialTypes.USER) ?
guild.client.users.add({ id: data.target_id }) :
guild.client.users.cache.get(data.target_id);
this.target = guild.client.options.partials.includes(PartialTypes.USER)
? guild.client.users.add({ id: data.target_id })
: guild.client.users.cache.get(data.target_id);
} else if (targetType === Targets.GUILD) {
this.target = guild.client.guilds.cache.get(data.target_id);
} else if (targetType === Targets.WEBHOOK) {
this.target = logs.webhooks.get(data.target_id) ||
new Webhook(guild.client,
this.changes.reduce((o, c) => {
o[c.key] = c.new || c.old;
return o;
}, {
id: data.target_id,
guild_id: guild.id,
}));
this.target =
logs.webhooks.get(data.target_id) ||
new Webhook(
guild.client,
this.changes.reduce(
(o, c) => {
o[c.key] = c.new || c.old;
return o;
},
{
id: data.target_id,
guild_id: guild.id,
},
),
);
} else if (targetType === Targets.INVITE) {
this.target = guild.members.fetch(guild.client.user.id).then(me => {
if (me.permissions.has('MANAGE_GUILD')) {
@@ -437,15 +456,24 @@ class GuildAuditLogsEntry {
});
} else if (targetType === Targets.MESSAGE) {
// Discord sends a channel id for the MESSAGE_BULK_DELETE action type.
this.target = data.action_type === Actions.MESSAGE_BULK_DELETE ?
guild.channels.cache.get(data.target_id) || { id: data.target_id } :
guild.client.users.cache.get(data.target_id);
this.target =
data.action_type === Actions.MESSAGE_BULK_DELETE
? guild.channels.cache.get(data.target_id) || { id: data.target_id }
: guild.client.users.cache.get(data.target_id);
} else if (targetType === Targets.INTEGRATION) {
this.target = logs.integrations.get(data.target_id) ||
new Integration(guild.client, this.changes.reduce((o, c) => {
o[c.key] = c.new || c.old;
return o;
}, { id: data.target_id }), guild);
this.target =
logs.integrations.get(data.target_id) ||
new Integration(
guild.client,
this.changes.reduce(
(o, c) => {
o[c.key] = c.new || c.old;
return o;
},
{ id: data.target_id },
),
guild,
);
} else if (data.target_id) {
this.target = guild[`${targetType.toLowerCase()}s`].cache.get(data.target_id) || { id: data.target_id };
}

View File

@@ -1,13 +1,13 @@
'use strict';
const Channel = require('./Channel');
const Role = require('./Role');
const Invite = require('./Invite');
const PermissionOverwrites = require('./PermissionOverwrites');
const Util = require('../util/Util');
const Permissions = require('../util/Permissions');
const Collection = require('../util/Collection');
const Role = require('./Role');
const { Error, TypeError } = require('../errors');
const Collection = require('../util/Collection');
const Permissions = require('../util/Permissions');
const Util = require('../util/Util');
/**
* Represents a guild channel from any of the following:
@@ -85,9 +85,11 @@ class GuildChannel extends Channel {
if (this.permissionOverwrites.size !== this.parent.permissionOverwrites.size) return false;
return this.permissionOverwrites.every((value, key) => {
const testVal = this.parent.permissionOverwrites.get(key);
return testVal !== undefined &&
return (
testVal !== undefined &&
testVal.deny.bitfield === value.deny.bitfield &&
testVal.allow.bitfield === value.allow.bitfield;
testVal.allow.bitfield === value.allow.bitfield
);
});
}
@@ -202,12 +204,9 @@ class GuildChannel extends Channel {
*/
overwritePermissions(overwrites, reason) {
if (!Array.isArray(overwrites) && !(overwrites instanceof Collection)) {
return Promise.reject(new TypeError(
'INVALID_TYPE',
'overwrites',
'Array or Collection of Permission Overwrites',
true,
));
return Promise.reject(
new TypeError('INVALID_TYPE', 'overwrites', 'Array or Collection of Permission Overwrites', true),
);
}
return this.edit({ permissionOverwrites: overwrites, reason }).then(() => this);
}
@@ -256,8 +255,12 @@ class GuildChannel extends Channel {
const type = userOrRole instanceof Role ? 'role' : 'member';
const { allow, deny } = PermissionOverwrites.resolveOverwriteOptions(options);
return this.client.api.channels(this.id).permissions[userOrRole.id]
.put({ data: { id: userOrRole.id, type, allow: allow.bitfield, deny: deny.bitfield }, reason })
return this.client.api
.channels(this.id)
.permissions[userOrRole.id].put({
data: { id: userOrRole.id, type, allow: allow.bitfield, deny: deny.bitfield },
reason,
})
.then(() => this);
}
@@ -316,18 +319,23 @@ class GuildChannel extends Channel {
*/
async edit(data, reason) {
if (typeof data.position !== 'undefined') {
await Util.setPosition(this, data.position, false,
this.guild._sortedChannels(this), this.client.api.guilds(this.guild.id).channels, reason)
.then(updatedChannels => {
this.client.actions.GuildChannelsPositionUpdate.handle({
guild_id: this.guild.id,
channels: updatedChannels,
});
await Util.setPosition(
this,
data.position,
false,
this.guild._sortedChannels(this),
this.client.api.guilds(this.guild.id).channels,
reason,
).then(updatedChannels => {
this.client.actions.GuildChannelsPositionUpdate.handle({
guild_id: this.guild.id,
channels: updatedChannels,
});
});
}
const permission_overwrites = data.permissionOverwrites &&
data.permissionOverwrites.map(o => PermissionOverwrites.resolve(o, this.guild));
const permission_overwrites =
data.permissionOverwrites && data.permissionOverwrites.map(o => PermissionOverwrites.resolve(o, this.guild));
const newData = await this.client.api.channels(this.id).patch({
data: {
@@ -378,11 +386,14 @@ class GuildChannel extends Channel {
* .catch(console.error);
*/
setParent(channel, { lockPermissions = true, reason } = {}) {
return this.edit({
// eslint-disable-next-line no-prototype-builtins
parentID: channel !== null ? channel.hasOwnProperty('id') ? channel.id : channel : null,
lockPermissions,
}, reason);
return this.edit(
{
// eslint-disable-next-line no-prototype-builtins
parentID: channel !== null ? (channel.hasOwnProperty('id') ? channel.id : channel) : null,
lockPermissions,
},
reason,
);
}
/**
@@ -414,15 +425,20 @@ class GuildChannel extends Channel {
* .catch(console.error);
*/
setPosition(position, { relative, reason } = {}) {
return Util.setPosition(this, position, relative,
this.guild._sortedChannels(this), this.client.api.guilds(this.guild.id).channels, reason)
.then(updatedChannels => {
this.client.actions.GuildChannelsPositionUpdate.handle({
guild_id: this.guild.id,
channels: updatedChannels,
});
return this;
return Util.setPosition(
this,
position,
relative,
this.guild._sortedChannels(this),
this.client.api.guilds(this.guild.id).channels,
reason,
).then(updatedChannels => {
this.client.actions.GuildChannelsPositionUpdate.handle({
guild_id: this.guild.id,
channels: updatedChannels,
});
return this;
});
}
/**
@@ -442,9 +458,17 @@ class GuildChannel extends Channel {
* .catch(console.error);
*/
createInvite({ temporary = false, maxAge = 86400, maxUses = 0, unique, reason } = {}) {
return this.client.api.channels(this.id).invites.post({ data: {
temporary, max_age: maxAge, max_uses: maxUses, unique,
}, reason })
return this.client.api
.channels(this.id)
.invites.post({
data: {
temporary,
max_age: maxAge,
max_uses: maxUses,
unique,
},
reason,
})
.then(invite => new Invite(this.client, invite));
}
@@ -481,18 +505,21 @@ class GuildChannel extends Channel {
* @returns {Promise<GuildChannel>}
*/
clone(options = {}) {
Util.mergeDefault({
name: this.name,
permissionOverwrites: this.permissionOverwrites,
topic: this.topic,
type: this.type,
nsfw: this.nsfw,
parent: this.parent,
bitrate: this.bitrate,
userLimit: this.userLimit,
rateLimitPerUser: this.rateLimitPerUser,
reason: null,
}, options);
Util.mergeDefault(
{
name: this.name,
permissionOverwrites: this.permissionOverwrites,
topic: this.topic,
type: this.type,
nsfw: this.nsfw,
parent: this.parent,
bitrate: this.bitrate,
userLimit: this.userLimit,
rateLimitPerUser: this.rateLimitPerUser,
reason: null,
},
options,
);
return this.guild.channels.create(options.name, options);
}
/* eslint-enable max-len */
@@ -504,7 +531,8 @@ class GuildChannel extends Channel {
* @returns {boolean}
*/
equals(channel) {
let equal = channel &&
let equal =
channel &&
this.id === channel.id &&
this.type === channel.type &&
this.topic === channel.topic &&
@@ -565,7 +593,10 @@ class GuildChannel extends Channel {
* .catch(console.error);
*/
delete(reason) {
return this.client.api.channels(this.id).delete({ reason }).then(() => this);
return this.client.api
.channels(this.id)
.delete({ reason })
.then(() => this);
}
}

View File

@@ -1,9 +1,9 @@
'use strict';
const Emoji = require('./Emoji');
const { Error } = require('../errors');
const GuildEmojiRoleManager = require('../managers/GuildEmojiRoleManager');
const Permissions = require('../util/Permissions');
const { Error } = require('../errors');
const Emoji = require('./Emoji');
/**
* Represents a custom emoji.
@@ -74,8 +74,7 @@ class GuildEmoji extends Emoji {
*/
get deletable() {
if (!this.guild.me) throw new Error('GUILD_UNCACHED_ME');
return !this.managed &&
this.guild.me.hasPermission(Permissions.FLAGS.MANAGE_EMOJIS);
return !this.managed && this.guild.me.hasPermission(Permissions.FLAGS.MANAGE_EMOJIS);
}
/**
@@ -100,7 +99,10 @@ class GuildEmoji extends Emoji {
return Promise.reject(new Error('MISSING_MANAGE_EMOJIS_PERMISSION', this.guild));
}
}
return this.client.api.guilds(this.guild.id).emojis(this.id).get()
return this.client.api
.guilds(this.guild.id)
.emojis(this.id)
.get()
.then(emoji => this.client.users.add(emoji.user));
}
@@ -124,11 +126,16 @@ class GuildEmoji extends Emoji {
*/
edit(data, reason) {
const roles = data.roles ? data.roles.map(r => r.id || r) : undefined;
return this.client.api.guilds(this.guild.id).emojis(this.id)
.patch({ data: {
name: data.name,
roles,
}, reason })
return this.client.api
.guilds(this.guild.id)
.emojis(this.id)
.patch({
data: {
name: data.name,
roles,
},
reason,
})
.then(newData => {
const clone = this._clone();
clone._patch(newData);
@@ -152,7 +159,10 @@ class GuildEmoji extends Emoji {
* @returns {Promise<GuildEmoji>}
*/
delete(reason) {
return this.client.api.guilds(this.guild.id).emojis(this.id).delete({ reason })
return this.client.api
.guilds(this.guild.id)
.emojis(this.id)
.delete({ reason })
.then(() => this);
}

View File

@@ -1,13 +1,13 @@
'use strict';
const TextBasedChannel = require('./interfaces/TextBasedChannel');
const Role = require('./Role');
const Permissions = require('../util/Permissions');
const GuildMemberRoleManager = require('../managers/GuildMemberRoleManager');
const Base = require('./Base');
const VoiceState = require('./VoiceState');
const { Presence } = require('./Presence');
const Role = require('./Role');
const VoiceState = require('./VoiceState');
const TextBasedChannel = require('./interfaces/TextBasedChannel');
const { Error } = require('../errors');
const GuildMemberRoleManager = require('../managers/GuildMemberRoleManager');
const Permissions = require('../util/Permissions');
/**
* Represents a member of a guild on Discord.
@@ -152,12 +152,15 @@ class GuildMember extends Base {
* @readonly
*/
get presence() {
return this.guild.presences.cache.get(this.id) || new Presence(this.client, {
user: {
id: this.id,
},
guild: this.guild,
});
return (
this.guild.presences.cache.get(this.id) ||
new Presence(this.client, {
user: {
id: this.id,
},
guild: this.guild,
})
);
}
/**
@@ -293,7 +296,7 @@ class GuildMember extends Base {
data.channel_id = null;
data.channel = undefined;
}
if (data.roles) data.roles = data.roles.map(role => role instanceof Role ? role.id : role);
if (data.roles) data.roles = data.roles.map(role => (role instanceof Role ? role.id : role));
let endpoint = this.client.api.guilds(this.guild.id);
if (this.user.id === this.client.user.id) {
const keys = Object.keys(data);
@@ -342,7 +345,10 @@ class GuildMember extends Base {
* @returns {Promise<GuildMember>}
*/
kick(reason) {
return this.client.api.guilds(this.guild.id).members(this.user.id).delete({ reason })
return this.client.api
.guilds(this.guild.id)
.members(this.user.id)
.delete({ reason })
.then(() => this);
}

View File

@@ -98,7 +98,10 @@ class Integration extends Base {
*/
sync() {
this.syncing = true;
return this.client.api.guilds(this.guild.id).integrations(this.id).post()
return this.client.api
.guilds(this.guild.id)
.integrations(this.id)
.post()
.then(() => {
this.syncing = false;
this.syncedAt = Date.now();
@@ -129,7 +132,10 @@ class Integration extends Base {
data.expireGracePeriod = null;
}
// The option enable_emoticons is only available for Twitch at this moment
return this.client.api.guilds(this.guild.id).integrations(this.id).patch({ data, reason })
return this.client.api
.guilds(this.guild.id)
.integrations(this.id)
.patch({ data, reason })
.then(() => {
this._patch(data);
return this;
@@ -142,7 +148,10 @@ class Integration extends Base {
* @param {string} [reason] Reason for deleting this integration
*/
delete(reason) {
return this.client.api.guilds(this.guild.id).integrations(this.id).delete({ reason })
return this.client.api
.guilds(this.guild.id)
.integrations(this.id)
.delete({ reason })
.then(() => this);
}

View File

@@ -1,8 +1,8 @@
'use strict';
const Base = require('./Base');
const { Endpoints } = require('../util/Constants');
const Permissions = require('../util/Permissions');
const Base = require('./Base');
/**
* Represents an invitation to a guild channel.
@@ -119,8 +119,10 @@ class Invite extends Base {
const guild = this.guild;
if (!guild || !this.client.guilds.cache.has(guild.id)) return false;
if (!guild.me) throw new Error('GUILD_UNCACHED_ME');
return this.channel.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_CHANNELS, false) ||
guild.me.permissions.has(Permissions.FLAGS.MANAGE_GUILD);
return (
this.channel.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_CHANNELS, false) ||
guild.me.permissions.has(Permissions.FLAGS.MANAGE_GUILD)
);
}
/**
@@ -129,7 +131,7 @@ class Invite extends Base {
* @readonly
*/
get expiresTimestamp() {
return this.createdTimestamp && this.maxAge ? this.createdTimestamp + (this.maxAge * 1000) : null;
return this.createdTimestamp && this.maxAge ? this.createdTimestamp + this.maxAge * 1000 : null;
}
/**

View File

@@ -1,19 +1,19 @@
'use strict';
const Mentions = require('./MessageMentions');
const APIMessage = require('./APIMessage');
const Base = require('./Base');
const ClientApplication = require('./ClientApplication');
const MessageAttachment = require('./MessageAttachment');
const Embed = require('./MessageEmbed');
const Mentions = require('./MessageMentions');
const ReactionCollector = require('./ReactionCollector');
const ClientApplication = require('./ClientApplication');
const Util = require('../util/Util');
const Collection = require('../util/Collection');
const ReactionManager = require('../managers/ReactionManager');
const { MessageTypes } = require('../util/Constants');
const Permissions = require('../util/Permissions');
const Base = require('./Base');
const { Error, TypeError } = require('../errors');
const APIMessage = require('./APIMessage');
const ReactionManager = require('../managers/ReactionManager');
const Collection = require('../util/Collection');
const { MessageTypes } = require('../util/Constants');
const MessageFlags = require('../util/MessageFlags');
const Permissions = require('../util/Permissions');
const Util = require('../util/Util');
/**
* Represents a message on Discord.
@@ -43,7 +43,7 @@ class Message extends Base {
if (data) this._patch(data);
}
_patch(data) { // eslint-disable-line complexity
_patch(data) {
/**
* The ID of the message
* @type {Snowflake}
@@ -107,9 +107,7 @@ class Message extends Base {
this.attachments = new Collection();
if (data.attachments) {
for (const attachment of data.attachments) {
this.attachments.set(attachment.id, new MessageAttachment(
attachment.url, attachment.filename, attachment,
));
this.attachments.set(attachment.id, new MessageAttachment(attachment.url, attachment.filename, attachment));
}
}
@@ -158,10 +156,12 @@ class Message extends Base {
* Group activity
* @type {?MessageActivity}
*/
this.activity = data.activity ? {
partyID: data.activity.party_id,
type: data.activity.type,
} : null;
this.activity = data.activity
? {
partyID: data.activity.party_id,
type: data.activity.type,
}
: null;
/**
* The previous versions of the message, sorted with the most recent first
@@ -194,11 +194,13 @@ class Message extends Base {
* Message reference data
* @type {?MessageReference}
*/
this.reference = data.message_reference ? {
channelID: data.message_reference.channel_id,
guildID: data.message_reference.guild_id,
messageID: data.message_reference.message_id,
} : null;
this.reference = data.message_reference
? {
channelID: data.message_reference.channel_id,
guildID: data.message_reference.guild_id,
messageID: data.message_reference.message_id,
}
: null;
}
/**
@@ -229,9 +231,7 @@ class Message extends Base {
if ('attachments' in data) {
this.attachments = new Collection();
for (const attachment of data.attachments) {
this.attachments.set(attachment.id, new MessageAttachment(
attachment.url, attachment.filename, attachment,
));
this.attachments.set(attachment.id, new MessageAttachment(attachment.url, attachment.filename, attachment));
}
} else {
this.attachments = new Collection(this.attachments);
@@ -377,9 +377,11 @@ class Message extends Base {
* @readonly
*/
get deletable() {
return !this.deleted && (this.author.id === this.client.user.id || (this.guild &&
this.channel.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_MESSAGES, false)
));
return (
!this.deleted &&
(this.author.id === this.client.user.id ||
(this.guild && this.channel.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_MESSAGES, false)))
);
}
/**
@@ -388,8 +390,10 @@ class Message extends Base {
* @readonly
*/
get pinnable() {
return this.type === 'DEFAULT' && (!this.guild ||
this.channel.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_MESSAGES, false));
return (
this.type === 'DEFAULT' &&
(!this.guild || this.channel.permissionsFor(this.client.user).has(Permissions.FLAGS.MANAGE_MESSAGES, false))
);
}
/**
@@ -412,16 +416,13 @@ class Message extends Base {
* .catch(console.error);
*/
edit(content, options) {
const { data } = content instanceof APIMessage ?
content.resolveData() :
APIMessage.create(this, content, options).resolveData();
return this.client.api.channels[this.channel.id].messages[this.id]
.patch({ data })
.then(d => {
const clone = this._clone();
clone._patch(d);
return clone;
});
const { data } =
content instanceof APIMessage ? content.resolveData() : APIMessage.create(this, content, options).resolveData();
return this.client.api.channels[this.channel.id].messages[this.id].patch({ data }).then(d => {
const clone = this._clone();
clone._patch(d);
return clone;
});
}
/**
@@ -429,7 +430,10 @@ class Message extends Base {
* @returns {Promise<Message>}
*/
pin() {
return this.client.api.channels(this.channel.id).pins(this.id).put()
return this.client.api
.channels(this.channel.id)
.pins(this.id)
.put()
.then(() => this);
}
@@ -438,7 +442,10 @@ class Message extends Base {
* @returns {Promise<Message>}
*/
unpin() {
return this.client.api.channels(this.channel.id).pins(this.id).delete()
return this.client.api
.channels(this.channel.id)
.pins(this.id)
.delete()
.then(() => this);
}
@@ -461,14 +468,20 @@ class Message extends Base {
emoji = this.client.emojis.resolveIdentifier(emoji);
if (!emoji) throw new TypeError('EMOJI_TYPE');
return this.client.api.channels(this.channel.id).messages(this.id).reactions(emoji, '@me')
return this.client.api
.channels(this.channel.id)
.messages(this.id)
.reactions(emoji, '@me')
.put()
.then(() => this.client.actions.MessageReactionAdd.handle({
user: this.client.user,
channel: this.channel,
message: this,
emoji: Util.parseEmoji(emoji),
}).reaction);
.then(
() =>
this.client.actions.MessageReactionAdd.handle({
user: this.client.user,
channel: this.channel,
message: this,
emoji: Util.parseEmoji(emoji),
}).reaction,
);
}
/**
@@ -509,9 +522,10 @@ class Message extends Base {
* .catch(console.error);
*/
reply(content, options) {
return this.channel.send(content instanceof APIMessage ?
content :
APIMessage.transformOptions(content, options, { reply: this.member || this.author }),
return this.channel.send(
content instanceof APIMessage
? content
: APIMessage.transformOptions(content, options, { reply: this.member || this.author }),
);
}
@@ -562,16 +576,18 @@ class Message extends Base {
const embedUpdate = !message.author && !message.attachments;
if (embedUpdate) return this.id === message.id && this.embeds.length === message.embeds.length;
let equal = this.id === message.id &&
this.author.id === message.author.id &&
this.content === message.content &&
this.tts === message.tts &&
this.nonce === message.nonce &&
this.embeds.length === message.embeds.length &&
this.attachments.length === message.attachments.length;
let equal =
this.id === message.id &&
this.author.id === message.author.id &&
this.content === message.content &&
this.tts === message.tts &&
this.nonce === message.nonce &&
this.embeds.length === message.embeds.length &&
this.attachments.length === message.attachments.length;
if (equal && rawData) {
equal = this.mentions.everyone === message.mentions.everyone &&
equal =
this.mentions.everyone === message.mentions.everyone &&
this.createdTimestamp === new Date(rawData.timestamp).getTime() &&
this.editedTimestamp === new Date(rawData.edited_timestamp).getTime();
}

View File

@@ -1,7 +1,7 @@
'use strict';
const Util = require('../util/Util');
const { RangeError } = require('../errors');
const Util = require('../util/Util');
/**
* Represents an embed in a message (image/video preview, rich embed, etc.)
@@ -11,7 +11,7 @@ class MessageEmbed {
this.setup(data);
}
setup(data) { // eslint-disable-line complexity
setup(data) {
/**
* The type of this embed, either:
* * `rich` - a rich embed
@@ -79,12 +79,14 @@ class MessageEmbed {
* The thumbnail of this embed (if there is one)
* @type {?MessageEmbedThumbnail}
*/
this.thumbnail = data.thumbnail ? {
url: data.thumbnail.url,
proxyURL: data.thumbnail.proxyURL || data.thumbnail.proxy_url,
height: data.thumbnail.height,
width: data.thumbnail.width,
} : null;
this.thumbnail = data.thumbnail
? {
url: data.thumbnail.url,
proxyURL: data.thumbnail.proxyURL || data.thumbnail.proxy_url,
height: data.thumbnail.height,
width: data.thumbnail.width,
}
: null;
/**
* @typedef {Object} MessageEmbedImage
@@ -98,12 +100,14 @@ class MessageEmbed {
* The image of this embed, if there is one
* @type {?MessageEmbedImage}
*/
this.image = data.image ? {
url: data.image.url,
proxyURL: data.image.proxyURL || data.image.proxy_url,
height: data.image.height,
width: data.image.width,
} : null;
this.image = data.image
? {
url: data.image.url,
proxyURL: data.image.proxyURL || data.image.proxy_url,
height: data.image.height,
width: data.image.width,
}
: null;
/**
* @typedef {Object} MessageEmbedVideo
@@ -118,12 +122,14 @@ class MessageEmbed {
* @type {?MessageEmbedVideo}
* @readonly
*/
this.video = data.video ? {
url: data.video.url,
proxyURL: data.video.proxyURL || data.video.proxy_url,
height: data.video.height,
width: data.video.width,
} : null;
this.video = data.video
? {
url: data.video.url,
proxyURL: data.video.proxyURL || data.video.proxy_url,
height: data.video.height,
width: data.video.width,
}
: null;
/**
* @typedef {Object} MessageEmbedAuthor
@@ -137,12 +143,14 @@ class MessageEmbed {
* The author of this embed (if there is one)
* @type {?MessageEmbedAuthor}
*/
this.author = data.author ? {
name: data.author.name,
url: data.author.url,
iconURL: data.author.iconURL || data.author.icon_url,
proxyIconURL: data.author.proxyIconURL || data.author.proxy_icon_url,
} : null;
this.author = data.author
? {
name: data.author.name,
url: data.author.url,
iconURL: data.author.iconURL || data.author.icon_url,
proxyIconURL: data.author.proxyIconURL || data.author.proxy_icon_url,
}
: null;
/**
* @typedef {Object} MessageEmbedProvider
@@ -154,10 +162,12 @@ class MessageEmbed {
* The provider of this embed (if there is one)
* @type {?MessageEmbedProvider}
*/
this.provider = data.provider ? {
name: data.provider.name,
url: data.provider.name,
} : null;
this.provider = data.provider
? {
name: data.provider.name,
url: data.provider.name,
}
: null;
/**
* @typedef {Object} MessageEmbedFooter
@@ -170,11 +180,13 @@ class MessageEmbed {
* The footer of this embed
* @type {?MessageEmbedFooter}
*/
this.footer = data.footer ? {
text: data.footer.text,
iconURL: data.footer.iconURL || data.footer.icon_url,
proxyIconURL: data.footer.proxyIconURL || data.footer.proxy_icon_url,
} : null;
this.footer = data.footer
? {
text: data.footer.text,
iconURL: data.footer.iconURL || data.footer.icon_url,
proxyIconURL: data.footer.proxyIconURL || data.footer.proxy_icon_url,
}
: null;
/**
* The files of this embed
@@ -210,9 +222,11 @@ class MessageEmbed {
return (
(this.title ? this.title.length : 0) +
(this.description ? this.description.length : 0) +
(this.fields.length >= 1 ? this.fields.reduce((prev, curr) =>
prev + curr.name.length + curr.value.length, 0) : 0) +
(this.footer ? this.footer.text.length : 0));
(this.fields.length >= 1
? this.fields.reduce((prev, curr) => prev + curr.name.length + curr.value.length, 0)
: 0) +
(this.footer ? this.footer.text.length : 0)
);
}
/**
@@ -371,15 +385,19 @@ class MessageEmbed {
fields: this.fields,
thumbnail: this.thumbnail,
image: this.image,
author: this.author ? {
name: this.author.name,
url: this.author.url,
icon_url: this.author.iconURL,
} : null,
footer: this.footer ? {
text: this.footer.text,
icon_url: this.footer.iconURL,
} : null,
author: this.author
? {
name: this.author.name,
url: this.author.url,
icon_url: this.author.iconURL,
}
: null,
footer: this.footer
? {
text: this.footer.text,
icon_url: this.footer.iconURL,
}
: null,
};
}
@@ -399,11 +417,11 @@ class MessageEmbed {
}
/**
* @typedef {Object} EmbedFieldData
* @property {StringResolvable} name The name of this field
* @property {StringResolvable} value The value of this field
* @property {boolean} [inline=false] If this field will be displayed inline
*/
* @typedef {Object} EmbedFieldData
* @property {StringResolvable} name The name of this field
* @property {StringResolvable} value The value of this field
* @property {boolean} [inline] If this field will be displayed inline
*/
/**
* Normalizes field input and resolves strings.
@@ -411,13 +429,15 @@ class MessageEmbed {
* @returns {EmbedField[]}
*/
static normalizeFields(...fields) {
return fields.flat(2).map(field =>
this.normalizeField(
field && field.name,
field && field.value,
field && typeof field.inline === 'boolean' ? field.inline : false,
),
);
return fields
.flat(2)
.map(field =>
this.normalizeField(
field && field.name,
field && field.value,
field && typeof field.inline === 'boolean' ? field.inline : false,
),
);
}
}

View File

@@ -1,9 +1,9 @@
'use strict';
const Collection = require('../util/Collection');
const Util = require('../util/Util');
const GuildMember = require('./GuildMember');
const Collection = require('../util/Collection');
const { ChannelTypes } = require('../util/Constants');
const Util = require('../util/Util');
/**
* Keeps track of mentions in a {@link Message}.

View File

@@ -1,9 +1,9 @@
'use strict';
const GuildEmoji = require('./GuildEmoji');
const Util = require('../util/Util');
const ReactionEmoji = require('./ReactionEmoji');
const ReactionUserManager = require('../managers/ReactionUserManager');
const Util = require('../util/Util');
/**
* Represents a reaction to a message.
@@ -59,7 +59,10 @@ class MessageReaction {
* @returns {Promise<MessageReaction>}
*/
async remove() {
await this.client.api.channels(this.message.channel.id).messages(this.message.id).reactions(this._emoji.identifier)
await this.client.api
.channels(this.message.channel.id)
.messages(this.message.id)
.reactions(this._emoji.identifier)
.delete();
return this;
}

View File

@@ -1,9 +1,9 @@
'use strict';
const Role = require('./Role');
const { TypeError } = require('../errors');
const Permissions = require('../util/Permissions');
const Util = require('../util/Util');
const { TypeError } = require('../errors');
/**
* Represents a permission overwrite for a role or member in a guild channel.
@@ -70,8 +70,12 @@ class PermissionOverwrites {
update(options, reason) {
const { allow, deny } = this.constructor.resolveOverwriteOptions(options, this);
return this.channel.client.api.channels(this.channel.id).permissions[this.id]
.put({ data: { id: this.id, type: this.type, allow: allow.bitfield, deny: deny.bitfield }, reason })
return this.channel.client.api
.channels(this.channel.id)
.permissions[this.id].put({
data: { id: this.id, type: this.type, allow: allow.bitfield, deny: deny.bitfield },
reason,
})
.then(() => this);
}
@@ -81,9 +85,7 @@ class PermissionOverwrites {
* @returns {Promise<PermissionOverwrites>}
*/
delete(reason) {
return this.channel.client.api.channels[this.channel.id].permissions[this.id]
.delete({ reason })
.then(() => this);
return this.channel.client.api.channels[this.channel.id].permissions[this.id].delete({ reason }).then(() => this);
}
toJSON() {
@@ -168,10 +170,7 @@ class PermissionOverwrites {
static resolve(overwrite, guild) {
if (overwrite instanceof this) return overwrite.toJSON();
if (typeof overwrite.id === 'string' && ['role', 'member'].includes(overwrite.type)) {
return { ...overwrite,
allow: Permissions.resolve(overwrite.allow),
deny: Permissions.resolve(overwrite.deny),
};
return { ...overwrite, allow: Permissions.resolve(overwrite.allow), deny: Permissions.resolve(overwrite.deny) };
}
const userOrRole = guild.roles.resolve(overwrite.id) || guild.client.users.resolve(overwrite.id);

View File

@@ -1,9 +1,9 @@
'use strict';
const Util = require('../util/Util');
const Emoji = require('./Emoji');
const ActivityFlags = require('../util/ActivityFlags');
const { ActivityTypes } = require('../util/Constants');
const Emoji = require('./Emoji');
const Util = require('../util/Util');
/**
* Activity sent in a message.
@@ -121,14 +121,15 @@ class Presence {
* @returns {boolean}
*/
equals(presence) {
return this === presence || (
presence &&
this.status === presence.status &&
this.activities.length === presence.activities.length &&
this.activities.every((activity, index) => activity.equals(presence.activities[index])) &&
this.clientStatus.web === presence.clientStatus.web &&
this.clientStatus.mobile === presence.clientStatus.mobile &&
this.clientStatus.desktop === presence.clientStatus.desktop
return (
this === presence ||
(presence &&
this.status === presence.status &&
this.activities.length === presence.activities.length &&
this.activities.every((activity, index) => activity.equals(presence.activities[index])) &&
this.clientStatus.web === presence.clientStatus.web &&
this.clientStatus.mobile === presence.clientStatus.mobile &&
this.clientStatus.desktop === presence.clientStatus.desktop)
);
}
@@ -186,10 +187,12 @@ class Activity {
* @prop {?Date} start When the activity started
* @prop {?Date} end When the activity will end
*/
this.timestamps = data.timestamps ? {
start: data.timestamps.start ? new Date(Number(data.timestamps.start)) : null,
end: data.timestamps.end ? new Date(Number(data.timestamps.end)) : null,
} : null;
this.timestamps = data.timestamps
? {
start: data.timestamps.start ? new Date(Number(data.timestamps.start)) : null,
end: data.timestamps.end ? new Date(Number(data.timestamps.end)) : null,
}
: null;
/**
* Party of the activity
@@ -232,11 +235,9 @@ class Activity {
* @returns {boolean}
*/
equals(activity) {
return this === activity || (
activity &&
this.name === activity.name &&
this.type === activity.type &&
this.url === activity.url
return (
this === activity ||
(activity && this.name === activity.name && this.type === activity.type && this.url === activity.url)
);
}
@@ -303,8 +304,10 @@ class RichPresenceAssets {
*/
smallImageURL({ format, size } = {}) {
if (!this.smallImage) return null;
return this.activity.presence.client.rest.cdn
.AppAsset(this.activity.applicationID, this.smallImage, { format, size });
return this.activity.presence.client.rest.cdn.AppAsset(this.activity.applicationID, this.smallImage, {
format,
size,
});
}
/**
@@ -321,8 +324,10 @@ class RichPresenceAssets {
} else if (/^twitch:/.test(this.largeImage)) {
return `https://static-cdn.jtvnw.net/previews-ttv/live_user_${this.largeImage.slice(7)}.png`;
}
return this.activity.presence.client.rest.cdn
.AppAsset(this.activity.applicationID, this.largeImage, { format, size });
return this.activity.presence.client.rest.cdn.AppAsset(this.activity.applicationID, this.largeImage, {
format,
size,
});
}
}

View File

@@ -118,8 +118,7 @@ class ReactionCollector extends Collector {
* @param {MessageReaction} reaction The reaction that was removed
* @param {User} user The user that removed the reaction
*/
if (this.collected.has(ReactionCollector.key(reaction)) &&
this.users.has(user.id)) {
if (this.collected.has(ReactionCollector.key(reaction)) && this.users.has(user.id)) {
this.emit('remove', reaction, user);
}
return reaction.count ? null : ReactionCollector.key(reaction);

View File

@@ -1,7 +1,7 @@
'use strict';
const Util = require('../util/Util');
const Emoji = require('./Emoji');
const Util = require('../util/Util');
/**
* Represents a limited emoji set used for both custom and unicode emojis. Custom emojis

View File

@@ -1,10 +1,10 @@
'use strict';
const Snowflake = require('../util/Snowflake');
const Permissions = require('../util/Permissions');
const Util = require('../util/Util');
const Base = require('./Base');
const { Error, TypeError } = require('../errors');
const Permissions = require('../util/Permissions');
const Snowflake = require('../util/Snowflake');
const Util = require('../util/Util');
/**
* Represents a role on Discord.
@@ -180,25 +180,31 @@ class Role extends Base {
if (typeof data.permissions !== 'undefined') data.permissions = Permissions.resolve(data.permissions);
else data.permissions = this.permissions.bitfield;
if (typeof data.position !== 'undefined') {
await Util.setPosition(this, data.position, false, this.guild._sortedRoles(),
this.client.api.guilds(this.guild.id).roles, reason)
.then(updatedRoles => {
this.client.actions.GuildRolesPositionUpdate.handle({
guild_id: this.guild.id,
roles: updatedRoles,
});
await Util.setPosition(
this,
data.position,
false,
this.guild._sortedRoles(),
this.client.api.guilds(this.guild.id).roles,
reason,
).then(updatedRoles => {
this.client.actions.GuildRolesPositionUpdate.handle({
guild_id: this.guild.id,
roles: updatedRoles,
});
});
}
return this.client.api.guilds[this.guild.id].roles[this.id].patch({
data: {
name: data.name || this.name,
color: data.color !== null ? Util.resolveColor(data.color || this.color) : null,
hoist: typeof data.hoist !== 'undefined' ? data.hoist : this.hoist,
permissions: data.permissions,
mentionable: typeof data.mentionable !== 'undefined' ? data.mentionable : this.mentionable,
},
reason,
})
return this.client.api.guilds[this.guild.id].roles[this.id]
.patch({
data: {
name: data.name || this.name,
color: data.color !== null ? Util.resolveColor(data.color || this.color) : null,
hoist: typeof data.hoist !== 'undefined' ? data.hoist : this.hoist,
permissions: data.permissions,
mentionable: typeof data.mentionable !== 'undefined' ? data.mentionable : this.mentionable,
},
reason,
})
.then(role => {
const clone = this._clone();
clone._patch(role);
@@ -312,15 +318,20 @@ class Role extends Base {
* .catch(console.error);
*/
setPosition(position, { relative, reason } = {}) {
return Util.setPosition(this, position, relative,
this.guild._sortedRoles(), this.client.api.guilds(this.guild.id).roles, reason)
.then(updatedRoles => {
this.client.actions.GuildRolesPositionUpdate.handle({
guild_id: this.guild.id,
roles: updatedRoles,
});
return this;
return Util.setPosition(
this,
position,
relative,
this.guild._sortedRoles(),
this.client.api.guilds(this.guild.id).roles,
reason,
).then(updatedRoles => {
this.client.actions.GuildRolesPositionUpdate.handle({
guild_id: this.guild.id,
roles: updatedRoles,
});
return this;
});
}
/**
@@ -334,11 +345,10 @@ class Role extends Base {
* .catch(console.error);
*/
delete(reason) {
return this.client.api.guilds[this.guild.id].roles[this.id].delete({ reason })
.then(() => {
this.client.actions.GuildRoleDelete.handle({ guild_id: this.guild.id, role_id: this.id });
return this;
});
return this.client.api.guilds[this.guild.id].roles[this.id].delete({ reason }).then(() => {
this.client.actions.GuildRoleDelete.handle({ guild_id: this.guild.id, role_id: this.id });
return this;
});
}
/**
@@ -349,14 +359,16 @@ class Role extends Base {
* @returns {boolean}
*/
equals(role) {
return role &&
return (
role &&
this.id === role.id &&
this.name === role.name &&
this.color === role.color &&
this.hoist === role.hoist &&
this.position === role.position &&
this.permissions.bitfield === role.permissions.bitfield &&
this.managed === role.managed;
this.managed === role.managed
);
}
/**

View File

@@ -1,9 +1,9 @@
'use strict';
const Snowflake = require('../util/Snowflake');
const Collection = require('../util/Collection');
const Base = require('./Base');
const TeamMember = require('./TeamMember');
const Collection = require('../util/Collection');
const Snowflake = require('../util/Snowflake');
/**
* Represents a Client OAuth2 Application Team.

View File

@@ -3,9 +3,9 @@
const GuildChannel = require('./GuildChannel');
const Webhook = require('./Webhook');
const TextBasedChannel = require('./interfaces/TextBasedChannel');
const MessageManager = require('../managers/MessageManager');
const Collection = require('../util/Collection');
const DataResolver = require('../util/DataResolver');
const MessageManager = require('../managers/MessageManager');
/**
* Represents a guild text channel on Discord.
@@ -121,9 +121,15 @@ class TextChannel extends GuildChannel {
if (typeof avatar === 'string' && !avatar.startsWith('data:')) {
avatar = await DataResolver.resolveImage(avatar);
}
return this.client.api.channels[this.id].webhooks.post({ data: {
name, avatar,
}, reason }).then(data => new Webhook(this.client, data));
return this.client.api.channels[this.id].webhooks
.post({
data: {
name,
avatar,
},
reason,
})
.then(data => new Webhook(this.client, data));
}
// These are here only for documentation purposes - they are implemented by TextBasedChannel

View File

@@ -1,10 +1,10 @@
'use strict';
const TextBasedChannel = require('./interfaces/TextBasedChannel');
const { Presence } = require('./Presence');
const Snowflake = require('../util/Snowflake');
const Base = require('./Base');
const { Presence } = require('./Presence');
const TextBasedChannel = require('./interfaces/TextBasedChannel');
const { Error } = require('../errors');
const Snowflake = require('../util/Snowflake');
/**
* Represents a user on Discord.
@@ -219,9 +219,11 @@ class User extends Base {
async createDM() {
const { dmChannel } = this;
if (dmChannel && !dmChannel.partial) return dmChannel;
const data = await this.client.api.users(this.client.user.id).channels.post({ data: {
recipient_id: this.id,
} });
const data = await this.client.api.users(this.client.user.id).channels.post({
data: {
recipient_id: this.id,
},
});
return this.client.actions.ChannelCreate.handle(data).channel;
}
@@ -243,7 +245,8 @@ class User extends Base {
* @returns {boolean}
*/
equals(user) {
let equal = user &&
let equal =
user &&
this.id === user.id &&
this.username === user.username &&
this.discriminator === user.discriminator &&
@@ -272,13 +275,16 @@ class User extends Base {
}
toJSON(...props) {
const json = super.toJSON({
createdTimestamp: true,
defaultAvatarURL: true,
tag: true,
lastMessage: false,
lastMessageID: false,
}, ...props);
const json = super.toJSON(
{
createdTimestamp: true,
defaultAvatarURL: true,
tag: true,
lastMessage: false,
lastMessageID: false,
},
...props,
);
json.avatarURL = this.avatarURL();
json.displayAvatarURL = this.displayAvatarURL();
return json;

View File

@@ -1,10 +1,10 @@
'use strict';
const GuildChannel = require('./GuildChannel');
const { Error } = require('../errors');
const Collection = require('../util/Collection');
const { browser } = require('../util/Constants');
const Permissions = require('../util/Permissions');
const Collection = require('../util/Collection');
const { Error } = require('../errors');
/**
* Represents a guild voice channel on Discord.

View File

@@ -1,8 +1,8 @@
'use strict';
const Base = require('./Base');
const { browser } = require('../util/Constants');
const { Error, TypeError } = require('../errors');
const { browser } = require('../util/Constants');
/**
* Represents the voice state for a Guild Member.
@@ -119,9 +119,7 @@ class VoiceState extends Base {
* @readonly
*/
get speaking() {
return this.channel && this.channel.connection ?
Boolean(this.channel.connection._speaking.get(this.id)) :
null;
return this.channel && this.channel.connection ? Boolean(this.channel.connection._speaking.get(this.id)) : null;
}
/**
@@ -161,9 +159,9 @@ class VoiceState extends Base {
* @returns {Promise<GuildMember>}
*/
setChannel(channel, reason) {
return this.member ?
this.member.edit({ channel }, reason) :
Promise.reject(new Error('VOICE_STATE_UNCACHED_MEMBER'));
return this.member
? this.member.edit({ channel }, reason)
: Promise.reject(new Error('VOICE_STATE_UNCACHED_MEMBER'));
}
/**

View File

@@ -1,10 +1,10 @@
'use strict';
const APIMessage = require('./APIMessage');
const Channel = require('./Channel');
const { WebhookTypes } = require('../util/Constants');
const DataResolver = require('../util/DataResolver');
const Snowflake = require('../util/Snowflake');
const Channel = require('./Channel');
const APIMessage = require('./APIMessage');
/**
* Represents a webhook.
@@ -149,15 +149,19 @@ class Webhook {
}
const { data, files } = await apiMessage.resolveFiles();
return this.client.api.webhooks(this.id, this.token).post({
data, files,
query: { wait: true },
auth: false,
}).then(d => {
const channel = this.client.channels ? this.client.channels.cache.get(d.channel_id) : undefined;
if (!channel) return d;
return channel.messages.add(d, false);
});
return this.client.api
.webhooks(this.id, this.token)
.post({
data,
files,
query: { wait: true },
auth: false,
})
.then(d => {
const channel = this.client.channels ? this.client.channels.cache.get(d.channel_id) : undefined;
if (!channel) return d;
return channel.messages.add(d, false);
});
}
/**
@@ -178,11 +182,14 @@ class Webhook {
* }).catch(console.error);
*/
sendSlackMessage(body) {
return this.client.api.webhooks(this.id, this.token).slack.post({
query: { wait: true },
auth: false,
data: body,
}).then(data => data.toString() === 'ok');
return this.client.api
.webhooks(this.id, this.token)
.slack.post({
query: { wait: true },
auth: false,
data: body,
})
.then(data => data.toString() === 'ok');
}
/**
@@ -195,7 +202,7 @@ class Webhook {
* @returns {Promise<Webhook>}
*/
async edit({ name = this.name, avatar, channel }, reason) {
if (avatar && (typeof avatar === 'string' && !avatar.startsWith('data:'))) {
if (avatar && typeof avatar === 'string' && !avatar.startsWith('data:')) {
avatar = await DataResolver.resolveImage(avatar);
}
if (channel) channel = channel instanceof Channel ? channel.id : channel;
@@ -256,17 +263,8 @@ class Webhook {
}
static applyToClass(structure) {
for (const prop of [
'send',
'sendSlackMessage',
'edit',
'delete',
'createdTimestamp',
'createdAt',
'url',
]) {
Object.defineProperty(structure.prototype, prop,
Object.getOwnPropertyDescriptor(Webhook.prototype, prop));
for (const prop of ['send', 'sendSlackMessage', 'edit', 'delete', 'createdTimestamp', 'createdAt', 'url']) {
Object.defineProperty(structure.prototype, prop, Object.getOwnPropertyDescriptor(Webhook.prototype, prop));
}
}
}

View File

@@ -1,8 +1,8 @@
'use strict';
const EventEmitter = require('events');
const Collection = require('../../util/Collection');
const Util = require('../../util/Util');
const EventEmitter = require('events');
/**
* Filter to be applied to the collector.

View File

@@ -1,10 +1,11 @@
'use strict';
/* eslint-disable import/order */
const MessageCollector = require('../MessageCollector');
const APIMessage = require('../APIMessage');
const Snowflake = require('../../util/Snowflake');
const Collection = require('../../util/Collection');
const { RangeError, TypeError } = require('../../errors');
const APIMessage = require('../APIMessage');
/**
* Interface for classes that have text-channel-like features.
@@ -144,7 +145,8 @@ class TextBasedChannel {
}
const { data, files } = await apiMessage.resolveFiles();
return this.client.api.channels[this.id].messages.post({ data, files })
return this.client.api.channels[this.id].messages
.post({ data, files })
.then(d => this.client.actions.MessageCreate.handle(d).message);
}
@@ -299,23 +301,36 @@ class TextBasedChannel {
if (Array.isArray(messages) || messages instanceof Collection) {
let messageIDs = messages instanceof Collection ? messages.keyArray() : messages.map(m => m.id || m);
if (filterOld) {
messageIDs = messageIDs.filter(id =>
Date.now() - Snowflake.deconstruct(id).date.getTime() < 1209600000,
);
messageIDs = messageIDs.filter(id => Date.now() - Snowflake.deconstruct(id).date.getTime() < 1209600000);
}
if (messageIDs.length === 0) return new Collection();
if (messageIDs.length === 1) {
await this.client.api.channels(this.id).messages(messageIDs[0]).delete();
const message = this.client.actions.MessageDelete.getMessage({
message_id: messageIDs[0],
}, this);
await this.client.api
.channels(this.id)
.messages(messageIDs[0])
.delete();
const message = this.client.actions.MessageDelete.getMessage(
{
message_id: messageIDs[0],
},
this,
);
return message ? new Collection([[message.id, message]]) : new Collection();
}
await this.client.api.channels[this.id].messages['bulk-delete']
.post({ data: { messages: messageIDs } });
return messageIDs.reduce((col, id) => col.set(id, this.client.actions.MessageDeleteBulk.getMessage({
message_id: id,
}, this)), new Collection());
await this.client.api.channels[this.id].messages['bulk-delete'].post({ data: { messages: messageIDs } });
return messageIDs.reduce(
(col, id) =>
col.set(
id,
this.client.actions.MessageDeleteBulk.getMessage(
{
message_id: id,
},
this,
),
),
new Collection(),
);
}
if (!isNaN(messages)) {
const msgs = await this.messages.fetch({ limit: messages });
@@ -341,8 +356,11 @@ class TextBasedChannel {
}
for (const prop of props) {
if (ignore.includes(prop)) continue;
Object.defineProperty(structure.prototype, prop,
Object.getOwnPropertyDescriptor(TextBasedChannel.prototype, prop));
Object.defineProperty(
structure.prototype,
prop,
Object.getOwnPropertyDescriptor(TextBasedChannel.prototype, prop),
);
}
}
}

View File

@@ -10,7 +10,7 @@ const Util = require('./Util');
*/
class Collection extends BaseCollection {
toJSON() {
return this.map(e => typeof e.toJSON === 'function' ? e.toJSON() : Util.flatten(e));
return this.map(e => (typeof e.toJSON === 'function' ? e.toJSON() : Util.flatten(e)));
}
}

View File

@@ -1,8 +1,8 @@
'use strict';
const Package = exports.Package = require('../../package.json');
const Package = (exports.Package = require('../../package.json'));
const { Error, RangeError } = require('../errors');
const browser = exports.browser = typeof window !== 'undefined';
const browser = (exports.browser = typeof window !== 'undefined');
/**
* Options for a client.
@@ -90,8 +90,9 @@ exports.DefaultOptions = {
},
};
exports.UserAgent = browser ? null :
`DiscordBot (${Package.homepage.split('#')[0]}, ${Package.version}) Node.js/${process.version}`;
exports.UserAgent = browser
? null
: `DiscordBot (${Package.homepage.split('#')[0]}, ${Package.version}) Node.js/${process.version}`;
exports.WSCodes = {
1000: 'WS_CLOSE_REQUESTED',
@@ -100,12 +101,7 @@ exports.WSCodes = {
4011: 'SHARDING_REQUIRED',
};
const AllowedImageFormats = [
'webp',
'png',
'jpg',
'gif',
];
const AllowedImageFormats = ['webp', 'png', 'jpg', 'gif'];
const AllowedImageSizes = Array.from({ length: 8 }, (e, i) => 2 ** (i + 4));
@@ -303,13 +299,7 @@ exports.ShardEvents = {
* sidebar for more information.</warn>
* @typedef {string} PartialType
*/
exports.PartialTypes = keyMirror([
'USER',
'CHANNEL',
'GUILD_MEMBER',
'MESSAGE',
'REACTION',
]);
exports.PartialTypes = keyMirror(['USER', 'CHANNEL', 'GUILD_MEMBER', 'MESSAGE', 'REACTION']);
/**
* The type of a websocket message event, e.g. `MESSAGE_CREATE`. Here are the available events:
@@ -439,13 +429,7 @@ exports.MessageTypes = [
* * CUSTOM_STATUS
* @typedef {string} ActivityType
*/
exports.ActivityTypes = [
'PLAYING',
'STREAMING',
'LISTENING',
'WATCHING',
'CUSTOM_STATUS',
];
exports.ActivityTypes = ['PLAYING', 'STREAMING', 'LISTENING', 'WATCHING', 'CUSTOM_STATUS'];
exports.ChannelTypes = {
TEXT: 0,
@@ -464,34 +448,34 @@ exports.ClientApplicationAssetTypes = {
exports.Colors = {
DEFAULT: 0x000000,
WHITE: 0xFFFFFF,
AQUA: 0x1ABC9C,
GREEN: 0x2ECC71,
BLUE: 0x3498DB,
YELLOW: 0xFFFF00,
PURPLE: 0x9B59B6,
LUMINOUS_VIVID_PINK: 0xE91E63,
GOLD: 0xF1C40F,
ORANGE: 0xE67E22,
RED: 0xE74C3C,
GREY: 0x95A5A6,
NAVY: 0x34495E,
DARK_AQUA: 0x11806A,
DARK_GREEN: 0x1F8B4C,
WHITE: 0xffffff,
AQUA: 0x1abc9c,
GREEN: 0x2ecc71,
BLUE: 0x3498db,
YELLOW: 0xffff00,
PURPLE: 0x9b59b6,
LUMINOUS_VIVID_PINK: 0xe91e63,
GOLD: 0xf1c40f,
ORANGE: 0xe67e22,
RED: 0xe74c3c,
GREY: 0x95a5a6,
NAVY: 0x34495e,
DARK_AQUA: 0x11806a,
DARK_GREEN: 0x1f8b4c,
DARK_BLUE: 0x206694,
DARK_PURPLE: 0x71368A,
DARK_VIVID_PINK: 0xAD1457,
DARK_GOLD: 0xC27C0E,
DARK_ORANGE: 0xA84300,
DARK_RED: 0x992D22,
DARK_GREY: 0x979C9F,
DARKER_GREY: 0x7F8C8D,
LIGHT_GREY: 0xBCC0C0,
DARK_NAVY: 0x2C3E50,
BLURPLE: 0x7289DA,
GREYPLE: 0x99AAB5,
DARK_BUT_NOT_BLACK: 0x2C2F33,
NOT_QUITE_BLACK: 0x23272A,
DARK_PURPLE: 0x71368a,
DARK_VIVID_PINK: 0xad1457,
DARK_GOLD: 0xc27c0e,
DARK_ORANGE: 0xa84300,
DARK_RED: 0x992d22,
DARK_GREY: 0x979c9f,
DARKER_GREY: 0x7f8c8d,
LIGHT_GREY: 0xbcc0c0,
DARK_NAVY: 0x2c3e50,
BLURPLE: 0x7289da,
GREYPLE: 0x99aab5,
DARK_BUT_NOT_BLACK: 0x2c2f33,
NOT_QUITE_BLACK: 0x23272a,
};
/**
@@ -501,11 +485,7 @@ exports.Colors = {
* * ALL_MEMBERS
* @typedef {string} ExplicitContentFilterLevel
*/
exports.ExplicitContentFilterLevels = [
'DISABLED',
'MEMBERS_WITHOUT_ROLES',
'ALL_MEMBERS',
];
exports.ExplicitContentFilterLevels = ['DISABLED', 'MEMBERS_WITHOUT_ROLES', 'ALL_MEMBERS'];
/**
* The value set for the verification levels for a guild:
@@ -516,13 +496,7 @@ exports.ExplicitContentFilterLevels = [
* * VERY_HIGH
* @typedef {string} VerificationLevel
*/
exports.VerificationLevels = [
'NONE',
'LOW',
'MEDIUM',
'HIGH',
'VERY_HIGH',
];
exports.VerificationLevels = ['NONE', 'LOW', 'MEDIUM', 'HIGH', 'VERY_HIGH'];
/**
* An error encountered while performing an API request. Here are the potential errors:
@@ -641,10 +615,7 @@ exports.APIErrors = {
* * MENTIONS
* @typedef {string} DefaultMessageNotifications
*/
exports.DefaultMessageNotifications = [
'ALL',
'MENTIONS',
];
exports.DefaultMessageNotifications = ['ALL', 'MENTIONS'];
/**
* The value set for a team members's membership state:

View File

@@ -1,11 +1,11 @@
'use strict';
const path = require('path');
const fs = require('fs');
const path = require('path');
const fetch = require('node-fetch');
const Util = require('../util/Util');
const { Error: DiscordError, TypeError } = require('../errors');
const { browser } = require('../util/Constants');
const Util = require('../util/Util');
/**
* The DataResolver identifies different objects and tries to resolve a specific piece of information from them.
@@ -90,7 +90,7 @@ class DataResolver {
if (typeof resource === 'string') {
if (/^https?:\/\//.test(resource)) {
return fetch(resource).then(res => browser ? res.blob() : res.buffer());
return fetch(resource).then(res => (browser ? res.blob() : res.buffer()));
} else if (!browser) {
return new Promise((resolve, reject) => {
const file = browser ? resource : path.resolve(resource);

View File

@@ -41,7 +41,9 @@ class SnowflakeUtil {
}
if (INCREMENT >= 4095) INCREMENT = 0;
// eslint-disable-next-line max-len
const BINARY = `${(timestamp - EPOCH).toString(2).padStart(42, '0')}0000100000${(INCREMENT++).toString(2).padStart(12, '0')}`;
const BINARY = `${(timestamp - EPOCH).toString(2).padStart(42, '0')}0000100000${(INCREMENT++)
.toString(2)
.padStart(12, '0')}`;
return Util.binaryToID(BINARY);
}
@@ -62,7 +64,9 @@ class SnowflakeUtil {
* @returns {DeconstructedSnowflake} Deconstructed snowflake
*/
static deconstruct(snowflake) {
const BINARY = Util.idToBinary(snowflake).toString(2).padStart(64, '0');
const BINARY = Util.idToBinary(snowflake)
.toString(2)
.padStart(64, '0');
const res = {
timestamp: parseInt(BINARY.substring(0, 42), 2) + EPOCH,
workerID: parseInt(BINARY.substring(42, 47), 2),
@@ -71,7 +75,9 @@ class SnowflakeUtil {
binary: BINARY,
};
Object.defineProperty(res, 'date', {
get: function get() { return new Date(this.timestamp); },
get: function get() {
return new Date(this.timestamp);
},
enumerable: true,
});
return res;

View File

@@ -60,7 +60,7 @@ class Structures {
const received = `${extended.name || 'unnamed'}${prototype.name ? ` extends ${prototype.name}` : ''}`;
throw new Error(
'The class/prototype returned from the extender function must extend the existing structure class/prototype' +
` (received function ${received}; expected extension of ${structures[structure].name}).`,
` (received function ${received}; expected extension of ${structures[structure].name}).`,
);
}

View File

@@ -1,11 +1,11 @@
'use strict';
const { Colors, DefaultOptions, Endpoints } = require('./Constants');
const { parse } = require('path');
const fetch = require('node-fetch');
const { Colors, DefaultOptions, Endpoints } = require('./Constants');
const { Error: DiscordError, RangeError, TypeError } = require('../errors');
const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
const isObject = d => typeof d === 'object' && d !== null;
const { parse } = require('path');
/**
* Contains various general-purpose utility methods. These functions are also available on the base `Discord` object.
@@ -24,7 +24,12 @@ class Util {
static flatten(obj, ...props) {
if (!isObject(obj)) return obj;
props = Object.assign(...Object.keys(obj).filter(k => !k.startsWith('_')).map(k => ({ [k]: true })), ...props);
props = Object.assign(
...Object.keys(obj)
.filter(k => !k.startsWith('_'))
.map(k => ({ [k]: true })),
...props,
);
const out = {};
@@ -89,43 +94,52 @@ class Util {
* @param {boolean} [options.inlineCodeContent=true] Whether to escape text inside inline code or not
* @returns {string}
*/
static escapeMarkdown(text, {
codeBlock = true,
inlineCode = true,
bold = true,
italic = true,
underline = true,
strikethrough = true,
spoiler = true,
codeBlockContent = true,
inlineCodeContent = true,
} = {}) {
static escapeMarkdown(
text,
{
codeBlock = true,
inlineCode = true,
bold = true,
italic = true,
underline = true,
strikethrough = true,
spoiler = true,
codeBlockContent = true,
inlineCodeContent = true,
} = {},
) {
if (!codeBlockContent) {
return text.split('```').map((subString, index, array) => {
if ((index % 2) && index !== array.length - 1) return subString;
return Util.escapeMarkdown(subString, {
inlineCode,
bold,
italic,
underline,
strikethrough,
spoiler,
inlineCodeContent,
});
}).join(codeBlock ? '\\`\\`\\`' : '```');
return text
.split('```')
.map((subString, index, array) => {
if (index % 2 && index !== array.length - 1) return subString;
return Util.escapeMarkdown(subString, {
inlineCode,
bold,
italic,
underline,
strikethrough,
spoiler,
inlineCodeContent,
});
})
.join(codeBlock ? '\\`\\`\\`' : '```');
}
if (!inlineCodeContent) {
return text.split(/(?<=^|[^`])`(?=[^`]|$)/g).map((subString, index, array) => {
if ((index % 2) && index !== array.length - 1) return subString;
return Util.escapeMarkdown(subString, {
codeBlock,
bold,
italic,
underline,
strikethrough,
spoiler,
});
}).join(inlineCode ? '\\`' : '`');
return text
.split(/(?<=^|[^`])`(?=[^`]|$)/g)
.map((subString, index, array) => {
if (index % 2 && index !== array.length - 1) return subString;
return Util.escapeMarkdown(subString, {
codeBlock,
bold,
italic,
underline,
strikethrough,
spoiler,
});
})
.join(inlineCode ? '\\`' : '`');
}
if (inlineCode) text = Util.escapeInlineCode(text);
if (codeBlock) text = Util.escapeCodeBlock(text);
@@ -228,10 +242,12 @@ class Util {
return fetch(`${DefaultOptions.http.api}/v${DefaultOptions.http.version}${Endpoints.botGateway}`, {
method: 'GET',
headers: { Authorization: `Bot ${token.replace(/^Bot\s*/i, '')}` },
}).then(res => {
if (res.ok) return res.json();
throw res;
}).then(data => data.shards * (1000 / guildsPerShard));
})
.then(res => {
if (res.ok) return res.json();
throw res;
})
.then(data => data.shards * (1000 / guildsPerShard));
}
/**
@@ -415,14 +431,14 @@ class Util {
*/
static resolveColor(color) {
if (typeof color === 'string') {
if (color === 'RANDOM') return Math.floor(Math.random() * (0xFFFFFF + 1));
if (color === 'RANDOM') return Math.floor(Math.random() * (0xffffff + 1));
if (color === 'DEFAULT') return 0;
color = Colors[color] || parseInt(color.replace('#', ''), 16);
} else if (Array.isArray(color)) {
color = (color[0] << 16) + (color[1] << 8) + color[2];
}
if (color < 0 || color > 0xFFFFFF) throw new RangeError('COLOR_RANGE');
if (color < 0 || color > 0xffffff) throw new RangeError('COLOR_RANGE');
else if (color && isNaN(color)) throw new TypeError('COLOR_CONVERT');
return color;
@@ -434,10 +450,11 @@ class Util {
* @returns {Collection}
*/
static discordSort(collection) {
return collection.sorted((a, b) =>
a.rawPosition - b.rawPosition ||
parseInt(b.id.slice(0, -10)) - parseInt(a.id.slice(0, -10)) ||
parseInt(b.id.slice(10)) - parseInt(a.id.slice(10)),
return collection.sorted(
(a, b) =>
a.rawPosition - b.rawPosition ||
parseInt(b.id.slice(0, -10)) - parseInt(a.id.slice(0, -10)) ||
parseInt(b.id.slice(10)) - parseInt(a.id.slice(10)),
);
}
@@ -506,7 +523,11 @@ class Util {
const low = parseInt((high % 10).toString(2) + num.slice(-32), 2);
dec = (low % 10).toString() + dec;
num = Math.floor(high / 10).toString(2) + Math.floor(low / 10).toString(2).padStart(32, '0');
num =
Math.floor(high / 10).toString(2) +
Math.floor(low / 10)
.toString(2)
.padStart(32, '0');
}
num = parseInt(num, 2);
@@ -535,7 +556,7 @@ class Util {
*/
static cleanContent(str, message) {
if (message.client.options.disableMentions === 'everyone') {
str = str.replace(/@([^<>@ ]*)/gsmu, (match, target) => {
str = str.replace(/@([^<>@ ]*)/gmsu, (match, target) => {
if (target.match(/^[&!]?\d+$/)) {
return `@${target}`;
} else {
@@ -543,21 +564,22 @@ class Util {
}
});
}
str = str.replace(/<@!?[0-9]+>/g, input => {
const id = input.replace(/<|!|>|@/g, '');
if (message.channel.type === 'dm') {
const user = message.client.users.cache.get(id);
return user ? `@${user.username}` : input;
}
str = str
.replace(/<@!?[0-9]+>/g, input => {
const id = input.replace(/<|!|>|@/g, '');
if (message.channel.type === 'dm') {
const user = message.client.users.cache.get(id);
return user ? `@${user.username}` : input;
}
const member = message.channel.guild.members.cache.get(id);
if (member) {
return `@${member.displayName}`;
} else {
const user = message.client.users.cache.get(id);
return user ? `@${user.username}` : input;
}
})
const member = message.channel.guild.members.cache.get(id);
if (member) {
return `@${member.displayName}`;
} else {
const user = message.client.users.cache.get(id);
return user ? `@${user.username}` : input;
}
})
.replace(/<#[0-9]+>/g, input => {
const channel = message.client.channels.cache.get(input.replace(/<|#|>/g, ''));
return channel ? `#${channel.name}` : input;