From bc30fdd8671d3a82ca90ede3c7df571ca3f0ecf2 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Thu, 26 Oct 2017 14:07:27 -0500 Subject: [PATCH 01/14] Fix Avatar URL generation bug (#2063) --- src/util/Constants.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/Constants.js b/src/util/Constants.js index aed65b8ee..7a0b262d3 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -114,6 +114,7 @@ exports.Endpoints = { Asset: name => `${root}/assets/${name}`, DefaultAvatar: number => `${root}/embed/avatars/${number}.png`, Avatar: (userID, hash, format = 'default', size) => { + if (userID === '1') return hash; if (format === 'default') format = hash.startsWith('a_') ? 'gif' : 'webp'; return makeImageUrl(`${root}/avatars/${userID}/${hash}`, { format, size }); }, From cd54e9317ff0396a34bafacce2ff2c056a4b0cee Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Fri, 27 Oct 2017 08:36:53 -0500 Subject: [PATCH 02/14] Time Difference in REST (#2057) --- src/rest/RESTManager.js | 10 ++++++++++ src/rest/handlers/RequestHandler.js | 7 +++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/rest/RESTManager.js b/src/rest/RESTManager.js index 48476cca6..d62423979 100644 --- a/src/rest/RESTManager.js +++ b/src/rest/RESTManager.js @@ -12,12 +12,22 @@ class RESTManager { this.globallyRateLimited = false; this.tokenPrefix = tokenPrefix; this.versioned = true; + this.timeDifferences = []; } get api() { return routeBuilder(this); } + get timeDifference() { + return Math.round(this.timeDifferences.reduce((a, b) => a + b, 0) / this.timeDifferences.length); + } + + set timeDifference(ms) { + this.timeDifferences.unshift(ms); + if (this.timeDifferences.length > 5) this.timeDifferences.length = 5; + } + getAuth() { const token = this.client.token || this.client.accessToken; const prefixed = !!this.client.application || (this.client.user && this.client.user.bot); diff --git a/src/rest/handlers/RequestHandler.js b/src/rest/handlers/RequestHandler.js index aaeed9d69..64e9ea72b 100644 --- a/src/rest/handlers/RequestHandler.js +++ b/src/rest/handlers/RequestHandler.js @@ -9,7 +9,6 @@ class RequestHandler { this.limit = Infinity; this.resetTime = null; this.remaining = 1; - this.timeDifference = 0; this.queue = []; } @@ -32,7 +31,7 @@ class RequestHandler { const finish = timeout => { if (timeout || this.limited) { if (!timeout) { - timeout = this.resetTime - Date.now() + this.timeDifference + this.client.options.restTimeOffset; + timeout = this.resetTime - Date.now() + this.manager.timeDifference + this.client.options.restTimeOffset; } // eslint-disable-next-line prefer-promise-reject-errors reject({ timeout }); @@ -50,7 +49,7 @@ class RequestHandler { this.client.emit(RATE_LIMIT, { timeout, limit: this.limit, - timeDifference: this.timeDifference, + timeDifference: this.manager.timeDifference, method: item.request.method, path: item.request.path, route: item.request.route, @@ -66,7 +65,7 @@ class RequestHandler { this.limit = Number(res.headers['x-ratelimit-limit']); this.resetTime = Number(res.headers['x-ratelimit-reset']) * 1000; this.remaining = Number(res.headers['x-ratelimit-remaining']); - this.timeDifference = Date.now() - new Date(res.headers.date).getTime(); + this.manager.timeDifference = Date.now() - new Date(res.headers.date).getTime(); } if (err) { if (err.status === 429) { From 0fc9459450341ae894dcbf62939f43bbca0d6c79 Mon Sep 17 00:00:00 2001 From: Schuyler Cebulskie Date: Fri, 27 Oct 2017 10:34:18 -0400 Subject: [PATCH 03/14] Add TextChannel#setNSFW method (#2050) * Add TextChannel#setNSFW method * Doesn't look like anything to me * butts --- src/structures/GuildChannel.js | 2 ++ src/structures/TextChannel.js | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/structures/GuildChannel.js b/src/structures/GuildChannel.js index 66efd8c2b..a1e8d53a0 100644 --- a/src/structures/GuildChannel.js +++ b/src/structures/GuildChannel.js @@ -248,6 +248,7 @@ class GuildChannel extends Channel { * @property {string} [name] The name of the channel * @property {number} [position] The position of the channel * @property {string} [topic] The topic of the text channel + * @property {boolean} [nsfw] Whether the channel is NSFW * @property {number} [bitrate] The bitrate of the voice channel * @property {number} [userLimit] The user limit of the voice channel * @property {Snowflake} [parentID] The parent ID of the channel @@ -290,6 +291,7 @@ class GuildChannel extends Channel { data: { name: (data.name || this.name).trim(), topic: data.topic, + nsfw: data.nsfw, bitrate: data.bitrate || (this.bitrate ? this.bitrate * 1000 : undefined), user_limit: data.userLimit != null ? data.userLimit : this.userLimit, // eslint-disable-line eqeqeq parent_id: data.parentID, diff --git a/src/structures/TextChannel.js b/src/structures/TextChannel.js index 6529f46b9..5679f841a 100644 --- a/src/structures/TextChannel.js +++ b/src/structures/TextChannel.js @@ -38,6 +38,16 @@ class TextChannel extends GuildChannel { if (data.messages) for (const message of data.messages) this.messages.create(message); } + /** + * Sets whether this channel is flagged as NSFW. + * @param {boolean} nsfw Whether the channel should be considered NSFW + * @param {string} [reason] Reason for changing the channel's NSFW flag + * @returns {Promise} + */ + setNSFW(nsfw, reason) { + return this.edit({ nsfw }, reason); + } + /** * Fetches all webhooks for the channel. * @returns {Promise>} From 291af7e845126d10a5fd95c6a6576e0e40a9e0ac Mon Sep 17 00:00:00 2001 From: Johnson Chen Date: Sat, 28 Oct 2017 20:35:38 +1100 Subject: [PATCH 04/14] Change recent to timestamp because DiscordAPIError (#2065) are lovely arn't they? --- src/structures/shared/Search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/shared/Search.js b/src/structures/shared/Search.js index 971f2483d..a852a5086 100644 --- a/src/structures/shared/Search.js +++ b/src/structures/shared/Search.js @@ -11,7 +11,7 @@ const { TypeError } = require('../../errors'); * @property {ChannelResolvable} [channel] Channel to limit search to (only for guild search endpoint) * @property {UserResolvable} [author] Author to limit search * @property {string} [authorType] One of `user`, `bot`, `webhook`, or add `-` to negate (e.g. `-webhook`) - * @property {string} [sortBy='recent'] `recent` or `relevant` + * @property {string} [sortBy='timestamp'] `timestamp` or `relevant` * @property {string} [sortOrder='descending'] `ascending` or `descending` * @property {number} [contextSize=2] How many messages to get around the matched message (0 to 2) * @property {number} [limit=25] Maximum number of results to get (1 to 25) From 0a05761b49dbd3970234ddaf80484fc78a1afbda Mon Sep 17 00:00:00 2001 From: SpaceEEC Date: Sat, 28 Oct 2017 18:55:59 +0200 Subject: [PATCH 05/14] Add new exports and remove a deprecated one (#2068) * add new exports and remove a deprecated one * fix incorrect require path --- src/index.js | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 746aab001..7bea36f1b 100644 --- a/src/index.js +++ b/src/index.js @@ -15,7 +15,6 @@ module.exports = { DataResolver: require('./util/DataResolver'), DataStore: require('./stores/DataStore'), DiscordAPIError: require('./rest/DiscordAPIError'), - EvaluatedPermissions: require('./util/Permissions'), Permissions: require('./util/Permissions'), Snowflake: require('./util/Snowflake'), SnowflakeUtil: require('./util/Snowflake'), @@ -23,15 +22,32 @@ module.exports = { util: Util, version: require('../package.json').version, + // Stores + ChannelStore: require('./stores/ChannelStore'), + ClientPresenceStore: require('./stores/ClientPresenceStore'), + EmojiStore: require('./stores/EmojiStore'), + GuildChannelStore: require('./stores/GuildChannelStore'), + GuildMemberStore: require('./stores/GuildMemberStore'), + GuildStore: require('./stores/GuildStore'), + MessageStore: require('./stores/MessageStore'), + PresenceStore: require('./stores/PresenceStore'), + RoleStore: require('./stores/RoleStore'), + UserStore: require('./stores/UserStore'), + // Shortcuts to Util methods escapeMarkdown: Util.escapeMarkdown, fetchRecommendedShards: Util.fetchRecommendedShards, splitMessage: Util.splitMessage, // Structures + Base: require('./structures/Base'), Activity: require('./structures/Presence').Activity, + CategoryChannel: require('./structures/CategoryChannel'), Channel: require('./structures/Channel'), + ClientApplication: require('./structures/ClientApplication'), ClientUser: require('./structures/ClientUser'), + ClientUserChannelOverride: require('./structures/ClientUserChannelOverride'), + ClientUserGuildSettings: require('./structures/ClientUserGuildSettings'), ClientUserSettings: require('./structures/ClientUserSettings'), Collector: require('./structures/interfaces/Collector'), DMChannel: require('./structures/DMChannel'), @@ -48,15 +64,17 @@ module.exports = { MessageEmbed: require('./structures/MessageEmbed'), MessageMentions: require('./structures/MessageMentions'), MessageReaction: require('./structures/MessageReaction'), - ClientApplication: require('./structures/ClientApplication'), PermissionOverwrites: require('./structures/PermissionOverwrites'), Presence: require('./structures/Presence').Presence, - ReactionEmoji: require('./structures/ReactionEmoji'), ReactionCollector: require('./structures/ReactionCollector'), + ReactionEmoji: require('./structures/ReactionEmoji'), + RichPresenceAssets: require('./structures/Presence').RichPresenceAssets, Role: require('./structures/Role'), TextChannel: require('./structures/TextChannel'), User: require('./structures/User'), + UserConnection: require('./structures/UserConnection'), VoiceChannel: require('./structures/VoiceChannel'), + VoiceRegion: require('./structures/VoiceRegion'), Webhook: require('./structures/Webhook'), WebSocket: require('./WebSocket'), From cd3d3344e8c34e0950584b20bbe984b411fc23c5 Mon Sep 17 00:00:00 2001 From: SpaceEEC Date: Sat, 28 Oct 2017 18:57:16 +0200 Subject: [PATCH 06/14] fix(GuildMember#hasPermission): pass correct parameters to Permissions#has (#2070) Also removed deprecated parameter of the method itself. --- src/structures/GuildMember.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index c4c2d6a81..935ba1084 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -294,19 +294,13 @@ class GuildMember extends Base { /** * Checks if any of the member's roles have a permission. * @param {PermissionResolvable|PermissionResolvable[]} permission Permission(s) to check for - * @param {boolean} [explicit=false] Whether to require the role to explicitly have the exact permission - * **(deprecated)** - * @param {boolean} [checkAdmin] Whether to allow the administrator permission to override - * (takes priority over `explicit`) - * @param {boolean} [checkOwner] Whether to allow being the guild's owner to override - * (takes priority over `explicit`) + * @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override + * @param {boolean} [checkOwner=true] Whether to allow being the guild's owner to override * @returns {boolean} */ - hasPermission(permission, explicit = false, checkAdmin, checkOwner) { - if (typeof checkAdmin === 'undefined') checkAdmin = !explicit; - if (typeof checkOwner === 'undefined') checkOwner = !explicit; + hasPermission(permission, checkAdmin = true, checkOwner = true) { if (checkOwner && this.user.id === this.guild.ownerID) return true; - return this.roles.some(r => r.permissions.has(permission, undefined, checkAdmin)); + return this.roles.some(r => r.permissions.has(permission, checkAdmin)); } /** From cda408534ada7f50b2d3a3a613b912b3548723d6 Mon Sep 17 00:00:00 2001 From: bdistin Date: Sat, 28 Oct 2017 11:57:50 -0500 Subject: [PATCH 07/14] user.patch shouldn't try to touch the token (#2072) --- src/structures/ClientUser.js | 2 ++ src/structures/User.js | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/structures/ClientUser.js b/src/structures/ClientUser.js index cc19ad58b..ce71d9bcf 100644 --- a/src/structures/ClientUser.js +++ b/src/structures/ClientUser.js @@ -88,6 +88,8 @@ class ClientUser extends User { this.guildSettings.set(settings.guild_id, new ClientUserGuildSettings(this.client, settings)); } } + + if (data.token) this.client.token = data.token; } /** diff --git a/src/structures/User.js b/src/structures/User.js index 814d3a90c..f12d67ffa 100644 --- a/src/structures/User.js +++ b/src/structures/User.js @@ -63,8 +63,6 @@ class User extends Base { * @type {?Message} */ this.lastMessage = null; - - if (data.token) this.client.token = data.token; } /** From b255af0825776eed430bbba0f96c4b8546bab926 Mon Sep 17 00:00:00 2001 From: bdistin Date: Sat, 28 Oct 2017 11:58:27 -0500 Subject: [PATCH 08/14] Fix user.bot (#2073) * fix user.bot * user.avatar is nullable (docs) --- src/structures/User.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/structures/User.js b/src/structures/User.js index f12d67ffa..2a184b1d4 100644 --- a/src/structures/User.js +++ b/src/structures/User.js @@ -20,6 +20,13 @@ class User extends Base { */ this.id = data.id; + /** + * Whether or not the user is a bot + * @type {boolean} + * @name User#bot + */ + this.bot = Boolean(data.bot); + this._patch(data); } @@ -40,18 +47,11 @@ class User extends Base { /** * The ID of the user's avatar - * @type {string} + * @type {?string} * @name User#avatar */ if (typeof data.avatar !== 'undefined') this.avatar = data.avatar; - /** - * Whether or not the user is a bot - * @type {boolean} - * @name User#bot - */ - if (typeof this.bot === 'undefined' && typeof data.bot !== 'undefined') this.bot = Boolean(data.bot); - /** * The ID of the last message sent by the user, if one was sent * @type {?Snowflake} From c495ea025a37b0d6e1f645407719573a1e6b9083 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Sat, 28 Oct 2017 11:58:46 -0500 Subject: [PATCH 09/14] fix raw event (#2074) --- src/client/websocket/WebSocketConnection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/websocket/WebSocketConnection.js b/src/client/websocket/WebSocketConnection.js index a30be35a8..4e3835ef0 100644 --- a/src/client/websocket/WebSocketConnection.js +++ b/src/client/websocket/WebSocketConnection.js @@ -272,7 +272,7 @@ class WebSocketConnection extends EventEmitter { try { const packet = WebSocket.unpack(this.inflate.result); this.onPacket(packet); - if (this.client.listenerCount('raw')) this.client.emit('raw', data); + if (this.client.listenerCount('raw')) this.client.emit('raw', packet); } catch (err) { this.client.emit('debug', err); } From 88719f0f4209fce2a4d08cecc90fa4c8e2bdde8d Mon Sep 17 00:00:00 2001 From: William Tran Date: Sat, 28 Oct 2017 10:01:17 -0700 Subject: [PATCH 10/14] Typos in docs (#2055) * Typo in Guild.createRole docs Added missing semicolon in example code. * consistent periods in docs --- src/client/voice/VoiceBroadcast.js | 2 +- src/structures/Guild.js | 4 ++-- src/structures/Presence.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/client/voice/VoiceBroadcast.js b/src/client/voice/VoiceBroadcast.js index 678045dca..5a2c54c73 100644 --- a/src/client/voice/VoiceBroadcast.js +++ b/src/client/voice/VoiceBroadcast.js @@ -236,7 +236,7 @@ class VoiceBroadcast extends VolumeInterface { } /** - * Plays an arbitrary input that can be [handled by ffmpeg](https://ffmpeg.org/ffmpeg-protocols.html#Description) + * Plays an arbitrary input that can be [handled by ffmpeg](https://ffmpeg.org/ffmpeg-protocols.html#Description). * @param {string} input The arbitrary input * @param {StreamOptions} [options] Options for playing the stream * @returns {VoiceBroadcast} diff --git a/src/structures/Guild.js b/src/structures/Guild.js index b3ea8535d..f3edd46ab 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -979,7 +979,7 @@ class Guild extends Base { } /** - * Creates a new role in the guild with given information + * Creates a new role in the guild with given information. * The position will silently reset to 1 if an invalid one is provided, or none. * @param {Object} [options] Options * @param {RoleData} [options.data] The data to update the role with @@ -1000,7 +1000,7 @@ class Guild extends Base { * reason: 'we needed a role for Super Cool People', * }) * .then(role => console.log(`Created role ${role}`)) - * .catch(console.error) + * .catch(console.error); */ createRole({ data = {}, reason } = {}) { if (data.color) data.color = Util.resolveColor(data.color); diff --git a/src/structures/Presence.js b/src/structures/Presence.js index 1eba8170c..91bee3ac3 100644 --- a/src/structures/Presence.js +++ b/src/structures/Presence.js @@ -38,7 +38,7 @@ class Presence { } /** - * Whether this presence is equal to another + * Whether this presence is equal to another. * @param {Presence} presence The presence to compare with * @returns {boolean} */ From 50ad66f5139b52bf057de0d2745d7ae73e4fa8f8 Mon Sep 17 00:00:00 2001 From: Gus Caplan Date: Sat, 28 Oct 2017 12:02:12 -0500 Subject: [PATCH 11/14] clean up readme a bit (#2054) * clean up readme a bit * Update README.md --- README.md | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 6b88f4370..989d2d652 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,7 @@ NPM downloads Build status Dependencies - Patreon + Patreon

NPM info @@ -31,9 +30,9 @@ discord.js is a powerful [node.js](https://nodejs.org) module that allows you to **Node.js 8.0.0 or newer is required.** Ignore any warnings about unmet peer dependencies, as they're all optional. -Without voice support: `npm install discord.js --save` -With voice support ([node-opus](https://www.npmjs.com/package/node-opus)): `npm install discord.js node-opus --save` -With voice support ([opusscript](https://www.npmjs.com/package/opusscript)): `npm install discord.js opusscript --save` +Without voice support: `npm i discord.js` +With voice support ([node-opus](https://www.npmjs.com/package/node-opus)): `npm i discord.js node-opus` +With voice support ([opusscript](https://www.npmjs.com/package/opusscript)): `npm i discord.js opusscript` ### Audio engines The preferred audio engine is node-opus, as it performs significantly better than opusscript. When both are available, discord.js will automatically choose node-opus. @@ -41,13 +40,13 @@ Using opusscript is only recommended for development environments where node-opu For production bots, using node-opus should be considered a necessity, especially if they're going to be running on multiple servers. ### Optional packages -- [zlib-sync](https://www.npmjs.com/package/zlib-sync) for significantly faster WebSocket data inflation (`npm install zlib-sync`) -- [bufferutil](https://www.npmjs.com/package/bufferutil) to greatly speed up the WebSocket when *not* using uws (`npm install bufferutil --save`) -- [erlpack](https://github.com/hammerandchisel/erlpack) for significantly faster WebSocket data (de)serialisation (`npm install discordapp/erlpack --save`) +- [zlib-sync](https://www.npmjs.com/package/zlib-sync) for significantly faster WebSocket data inflation (`npm i zlib-sync`) +- [erlpack](https://github.com/discordapp/erlpack) for significantly faster WebSocket data (de)serialisation (`npm i discordapp/erlpack`) - One of the following packages can be installed for faster voice packet encryption and decryption: - - [sodium](https://www.npmjs.com/package/sodium) (`npm install sodium --save`) - - [libsodium.js](https://www.npmjs.com/package/libsodium-wrappers) (`npm install libsodium-wrappers --save`) -- [uws](https://www.npmjs.com/package/uws) for a much faster WebSocket connection (`npm install uws --save`) + - [sodium](https://www.npmjs.com/package/sodium) (`npm i sodium`) + - [libsodium.js](https://www.npmjs.com/package/libsodium-wrappers) (`npm i libsodium-wrappers`) +- [uws](https://www.npmjs.com/package/uws) for a much faster WebSocket connection (`npm i uws`) +- [bufferutil](https://www.npmjs.com/package/bufferutil) for a much faster WebSocket connection when *not* using uws (`npm i bufferutil`) ## Example usage ```js @@ -70,11 +69,14 @@ client.login('your token'); ## Links * [Website](https://discord.js.org/) ([source](https://github.com/hydrabolt/discord.js-site)) * [Documentation](https://discord.js.org/#/docs) -* [Discord.js server](https://discord.gg/bRCvFy9) -* [Discord API server](https://discord.gg/rV4BwdK) +* [Discord.js Discord server](https://discord.gg/bRCvFy9) +* [Discord API Discord server](https://discord.gg/discord-api) * [GitHub](https://github.com/hydrabolt/discord.js) * [NPM](https://www.npmjs.com/package/discord.js) -* [Related libraries](https://discordapi.com/unofficial/libs.html) (see also [discord-rpc](https://www.npmjs.com/package/discord-rpc)) +* [Related libraries](https://discordapi.com/unofficial/libs.html) + +### Extensions +* [discord-rpc](https://www.npmjs.com/package/discord-rpc) ([github](https://github.com/devsnek/discord-rpc)) ## Contributing Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the From a62d1e954d9e8be0a8acf3802dd4f87c367ac2a5 Mon Sep 17 00:00:00 2001 From: SpaceEEC Date: Sat, 28 Oct 2017 19:03:27 +0200 Subject: [PATCH 12/14] fix(Presence): pass client and default to offline (#2071) --- src/structures/GuildMember.js | 2 +- src/structures/Presence.js | 2 +- src/structures/User.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index 935ba1084..8b83796cf 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -125,7 +125,7 @@ class GuildMember extends Base { * @readonly */ get presence() { - return this.frozenPresence || this.guild.presences.get(this.id) || new Presence(); + return this.frozenPresence || this.guild.presences.get(this.id) || new Presence(this.client); } /** diff --git a/src/structures/Presence.js b/src/structures/Presence.js index 91bee3ac3..e788124fc 100644 --- a/src/structures/Presence.js +++ b/src/structures/Presence.js @@ -19,7 +19,7 @@ class Presence { * * **`dnd`** - user is in Do Not Disturb * @type {string} */ - this.status = data.status || this.status; + this.status = data.status || this.status || 'offline'; const activity = data.game || data.activity; /** diff --git a/src/structures/User.js b/src/structures/User.js index 2a184b1d4..859cdeeb2 100644 --- a/src/structures/User.js +++ b/src/structures/User.js @@ -93,7 +93,7 @@ class User extends Base { for (const guild of this.client.guilds.values()) { if (guild.presences.has(this.id)) return guild.presences.get(this.id); } - return new Presence(); + return new Presence(this.client); } /** From 0101392334e48d144dda3bc1a127d1e9feb2555d Mon Sep 17 00:00:00 2001 From: SpaceEEC Date: Sat, 28 Oct 2017 19:04:03 +0200 Subject: [PATCH 13/14] Documentation improvements (#2069) * docs: fix documentation in various places All stores: resolveID returns a nullable Snowflake GuildAuditLogs: ActionType also can be ALL MessageEmbed: make files property show up in the docs ClientApplication: resetSecret and resetToken return a promise ClientManager: status is readonly Guild: features is an array of strings and ban no longer accepts a number or string Guild: ban method no longer accepts a string or number GuildMember: ^ RichPresenceAssets: small and large Image are Snowflakes, also fixed parameter documentation for small and large image url method WebhookMessageOptions: file property is no longer a thing * docs: improve GuildAuditLogs documentation Prefix types with AuditLog to avoid confusion Document GuildAuditLogs' static Targets and Actions properties and add necessary typedefs Use typdefs over primitives where possible. * fix documentation for Guild#defaultRole --- src/client/ClientManager.js | 1 + src/stores/ChannelStore.js | 2 +- src/stores/DataStore.js | 2 +- src/stores/EmojiStore.js | 2 +- src/stores/GuildChannelStore.js | 2 +- src/stores/GuildMemberStore.js | 2 +- src/stores/GuildStore.js | 2 +- src/stores/MessageStore.js | 2 +- src/stores/PresenceStore.js | 2 +- src/stores/ReactionStore.js | 2 +- src/stores/RoleStore.js | 2 +- src/stores/UserStore.js | 2 +- src/structures/ClientApplication.js | 4 +- src/structures/Guild.js | 6 +- src/structures/GuildAuditLogs.js | 93 +++++++++++++++++++++-------- src/structures/GuildMember.js | 2 +- src/structures/MessageEmbed.js | 12 ++-- src/structures/Presence.js | 14 +++-- src/structures/Webhook.js | 1 - 19 files changed, 100 insertions(+), 55 deletions(-) diff --git a/src/client/ClientManager.js b/src/client/ClientManager.js index 9e0d570d2..ad006b8fe 100644 --- a/src/client/ClientManager.js +++ b/src/client/ClientManager.js @@ -22,6 +22,7 @@ class ClientManager { /** * The status of the client + * @readonly * @type {number} */ get status() { diff --git a/src/stores/ChannelStore.js b/src/stores/ChannelStore.js index 5491b8e59..2ceee8000 100644 --- a/src/stores/ChannelStore.js +++ b/src/stores/ChannelStore.js @@ -95,7 +95,7 @@ class ChannelStore extends DataStore { * @memberof ChannelStore * @instance * @param {ChannelResolvable} channel The channel resolvable to resolve - * @returns {?string} + * @returns {?Snowflake} */ } diff --git a/src/stores/DataStore.js b/src/stores/DataStore.js index 85ce17c90..398910d50 100644 --- a/src/stores/DataStore.js +++ b/src/stores/DataStore.js @@ -37,7 +37,7 @@ class DataStore extends Collection { /** * Resolves a data entry to a instance ID. * @param {string|Instance} idOrInstance The id or instance of something in this DataStore - * @returns {?string} + * @returns {?Snowflake} */ resolveID(idOrInstance) { if (idOrInstance instanceof this.holds) return idOrInstance.id; diff --git a/src/stores/EmojiStore.js b/src/stores/EmojiStore.js index 83b4df812..035cc3d4d 100644 --- a/src/stores/EmojiStore.js +++ b/src/stores/EmojiStore.js @@ -38,7 +38,7 @@ class EmojiStore extends DataStore { /** * Resolves a EmojiResolvable to a Emoji ID string. * @param {EmojiResolvable} emoji The Emoji resolvable to identify - * @returns {?string} + * @returns {?Snowflake} */ resolveID(emoji) { if (emoji instanceof ReactionEmoji) return emoji.id; diff --git a/src/stores/GuildChannelStore.js b/src/stores/GuildChannelStore.js index 3e03c8110..0bc3e8c4e 100644 --- a/src/stores/GuildChannelStore.js +++ b/src/stores/GuildChannelStore.js @@ -42,7 +42,7 @@ class GuildChannelStore extends DataStore { * @memberof GuildChannelStore * @instance * @param {GuildChannelResolvable} channel The GuildChannel resolvable to resolve - * @returns {?string} + * @returns {?Snowflake} */ } diff --git a/src/stores/GuildMemberStore.js b/src/stores/GuildMemberStore.js index ba8cac903..ad0acbed9 100644 --- a/src/stores/GuildMemberStore.js +++ b/src/stores/GuildMemberStore.js @@ -41,7 +41,7 @@ class GuildMemberStore extends DataStore { /** * Resolves a GuildMemberResolvable to an member ID string. * @param {GuildMemberResolvable} member The user that is part of the guild - * @returns {?string} + * @returns {?Snowflake} */ resolveID(member) { const memberResolveable = super.resolveID(member); diff --git a/src/stores/GuildStore.js b/src/stores/GuildStore.js index 5e3e792a4..45e9c9cfc 100644 --- a/src/stores/GuildStore.js +++ b/src/stores/GuildStore.js @@ -33,7 +33,7 @@ class GuildStore extends DataStore { * @memberof GuildStore * @instance * @param {GuildResolvable} guild The guild resolvable to identify - * @returns {?string} + * @returns {?Snowflake} */ } diff --git a/src/stores/MessageStore.js b/src/stores/MessageStore.js index 75d01620c..cc0ff60b0 100644 --- a/src/stores/MessageStore.js +++ b/src/stores/MessageStore.js @@ -112,7 +112,7 @@ class MessageStore extends DataStore { * @memberof MessageStore * @instance * @param {MessageResolvable} message The message resolvable to resolve - * @returns {?string} + * @returns {?Snowflake} */ } diff --git a/src/stores/PresenceStore.js b/src/stores/PresenceStore.js index 1c2649712..8322c9c65 100644 --- a/src/stores/PresenceStore.js +++ b/src/stores/PresenceStore.js @@ -39,7 +39,7 @@ class PresenceStore extends DataStore { /** * Resolves a PresenceResolvable to a Presence ID string. * @param {PresenceResolvable} presence The presence resolvable to resolve - * @returns {?string} + * @returns {?Snowflake} */ resolveID(presence) { const presenceResolveable = super.resolveID(presence); diff --git a/src/stores/ReactionStore.js b/src/stores/ReactionStore.js index bcbca72ac..c11b4e176 100644 --- a/src/stores/ReactionStore.js +++ b/src/stores/ReactionStore.js @@ -38,7 +38,7 @@ class ReactionStore extends DataStore { * @memberof ReactionStore * @instance * @param {MessageReactionResolvable} role The role resolvable to resolve - * @returns {?string} + * @returns {?Snowflake} */ } diff --git a/src/stores/RoleStore.js b/src/stores/RoleStore.js index 7501cb459..bb8cd749d 100644 --- a/src/stores/RoleStore.js +++ b/src/stores/RoleStore.js @@ -38,7 +38,7 @@ class RoleStore extends DataStore { * @memberof RoleStore * @instance * @param {RoleResolvable} role The role resolvable to resolve - * @returns {?string} + * @returns {?Snowflake} */ } diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js index 6ee4909a3..432a0768a 100644 --- a/src/stores/UserStore.js +++ b/src/stores/UserStore.js @@ -35,7 +35,7 @@ class UserStore extends DataStore { /** * Resolves a UserResolvable to a user ID string. * @param {UserResolvable} user The UserResolvable to identify - * @returns {?string} + * @returns {?Snowflake} */ resolveID(user) { if (user instanceof GuildMember) return user.user.id; diff --git a/src/structures/ClientApplication.js b/src/structures/ClientApplication.js index 0d2646cee..494d8c1c3 100644 --- a/src/structures/ClientApplication.js +++ b/src/structures/ClientApplication.js @@ -177,7 +177,7 @@ class ClientApplication extends Base { /** * Resets the app's secret. * This is only available when using a user account. - * @returns {ClientApplication} + * @returns {Promise} */ resetSecret() { return this.client.api.oauth2.applications[this.id].reset.post() @@ -187,7 +187,7 @@ class ClientApplication extends Base { /** * Resets the app's bot token. * This is only available when using a user account. - * @returns {ClientApplication} + * @returns {Promise} */ resetToken() { return this.client.api.oauth2.applications[this.id].bot.reset.post() diff --git a/src/structures/Guild.js b/src/structures/Guild.js index f3edd46ab..1b9463b51 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -115,7 +115,7 @@ class Guild extends Base { /** * An array of guild features - * @type {Object[]} + * @type {string[]} */ this.features = data.features; @@ -401,7 +401,7 @@ class Guild extends Base { } } - /* + /** * The `@everyone` role of the guild * @type {Role} * @readonly @@ -802,7 +802,7 @@ class Guild extends Base { /** * Bans a user from the guild. * @param {UserResolvable} user The user to ban - * @param {Object|number|string} [options] Ban options. If a number, the number of days to delete messages for, if a + * @param {Object} [options] Ban options. If a number, the number of days to delete messages for, if a * string, the ban reason. Supplying an object allows you to do both. * @param {number} [options.days=0] Number of days of messages to delete * @param {string} [options.reason] Reason for banning diff --git a/src/structures/GuildAuditLogs.js b/src/structures/GuildAuditLogs.js index c48da00c0..d43a48b29 100644 --- a/src/structures/GuildAuditLogs.js +++ b/src/structures/GuildAuditLogs.js @@ -2,6 +2,24 @@ const Collection = require('../util/Collection'); const Snowflake = require('../util/Snowflake'); const Webhook = require('./Webhook'); +/** + * The target type of an entry, e.g. `GUILD`. Here are the available types: + * * GUILD + * * CHANNEL + * * USER + * * ROLE + * * INVITE + * * WEBHOOK + * * EMOJI + * * MESSAGE + * @typedef {string} AuditLogTargetType + */ + +/** + * Key mirror of all available audit log targets. + * @name GuildAuditLogs.Targets + * @type {AuditLogTargetType} + */ const Targets = { ALL: 'ALL', GUILD: 'GUILD', @@ -15,6 +33,43 @@ const Targets = { UNKNOWN: 'UNKNOWN', }; +/** + * The action of an entry. Here are the available actions: + * * ALL: null + * * GUILD_UPDATE: 1 + * * CHANNEL_CREATE: 10 + * * CHANNEL_UPDATE: 11 + * * CHANNEL_DELETE: 12 + * * CHANNEL_OVERWRITE_CREATE: 13 + * * CHANNEL_OVERWRITE_UPDATE: 14 + * * CHANNEL_OVERWRITE_DELETE: 15 + * * MEMBER_KICK: 20 + * * MEMBER_PRUNE: 21 + * * MEMBER_BAN_ADD: 22 + * * MEMBER_BAN_REMOVE: 23 + * * MEMBER_UPDATE: 24 + * * MEMBER_ROLE_UPDATE: 25 + * * ROLE_CREATE: 30 + * * ROLE_UPDATE: 31 + * * ROLE_DELETE: 32 + * * INVITE_CREATE: 40 + * * INVITE_UPDATE: 41 + * * INVITE_DELETE: 42 + * * WEBHOOK_CREATE: 50 + * * WEBHOOK_UPDATE: 51 + * * WEBHOOK_DELETE: 50 + * * EMOJI_CREATE: 60 + * * EMOJI_UPDATE: 61 + * * EMOJI_DELETE: 62 + * * MESSAGE_DELETE: 72 + * @typedef {?number|string} AuditLogAction + */ + +/** + * All available actions keyed under their names to their numeric values. + * @name GuildAuditLogs.Actions + * @type {AuditLogAction} + */ const Actions = { ALL: null, GUILD_UPDATE: 1, @@ -85,20 +140,7 @@ class GuildAuditLogs { } /** - * The target type of an entry, e.g. `GUILD`. Here are the available types: - * * GUILD - * * CHANNEL - * * USER - * * ROLE - * * INVITE - * * WEBHOOK - * * EMOJI - * * MESSAGE - * @typedef {string} TargetType - */ - - /** - * The target for an audit log entry. It can be one of: + * The target of an entry. It can be one of: * * A guild * * A user * * A role @@ -106,13 +148,13 @@ class GuildAuditLogs { * * An invite * * A webhook * * An object where the keys represent either the new value or the old value - * @typedef {?Object|Guild|User|Role|Emoji|Invite|Webhook} EntryTarget + * @typedef {?Object|Guild|User|Role|Emoji|Invite|Webhook} AuditLogEntryTarget */ /** * Finds the target type from the entry action. - * @param {number} target The action target - * @returns {?string} + * @param {AuditLogAction} target The action target + * @returns {AuditLogTargetType} */ static targetType(target) { if (target < 10) return Targets.GUILD; @@ -131,13 +173,14 @@ class GuildAuditLogs { * * CREATE * * DELETE * * UPDATE - * @typedef {string} ActionType + * * ALL + * @typedef {string} AuditLogActionType */ /** * Finds the action type from the entry action. - * @param {string} action The action target - * @returns {string} + * @param {AuditLogAction} action The action target + * @returns {AuditLogActionType} */ static actionType(action) { if ([ @@ -187,19 +230,19 @@ class GuildAuditLogsEntry { const targetType = GuildAuditLogs.targetType(data.action_type); /** * The target type of this entry - * @type {TargetType} + * @type {AuditLogTargetType} */ this.targetType = targetType; /** * The action type of this entry - * @type {ActionType} + * @type {AuditLogActionType} */ this.actionType = GuildAuditLogs.actionType(data.action_type); /** - * Specific action type of this entry - * @type {string} + * Specific action type of this entry in its string presentation + * @type {AuditLogAction} */ this.action = Object.keys(Actions).find(k => Actions[k] === data.action_type); @@ -271,7 +314,7 @@ class GuildAuditLogsEntry { if (targetType === Targets.UNKNOWN) { /** * The target of this entry - * @type {EntryTarget} + * @type {AuditLogEntryTarget} */ this.target = this.changes.reduce((o, c) => { o[c.key] = c.new || c.old; diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index 8b83796cf..010775e29 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -515,7 +515,7 @@ class GuildMember extends Base { /** * Bans this guild member. - * @param {Object|number|string} [options] Ban options. If a number, the number of days to delete messages for, if a + * @param {Object} [options] Ban options. If a number, the number of days to delete messages for, if a * string, the ban reason. Supplying an object allows you to do both. * @param {number} [options.days=0] Number of days of messages to delete * @param {string} [options.reason] Reason for banning diff --git a/src/structures/MessageEmbed.js b/src/structures/MessageEmbed.js index da55d6cee..b7f430b75 100644 --- a/src/structures/MessageEmbed.js +++ b/src/structures/MessageEmbed.js @@ -132,12 +132,12 @@ class MessageEmbed { proxyIconURL: data.footer.proxyIconURL || data.footer.proxy_icon_url, } : null; - /** - * The files of this embed - * @type {?Object} - * @property {Array} files Files to attach - */ if (data.files) { + /** + * The files of this embed + * @type {?Object} + * @property {Array} files Files to attach + */ this.files = data.files.map(file => { if (file instanceof MessageAttachment) { return typeof file.file === 'string' ? file.file : Util.cloneObject(file.file); @@ -158,7 +158,7 @@ class MessageEmbed { /** * The hexadecimal version of the embed color, with a leading hash - * @type {string} + * @type {?string} * @readonly */ get hexColor() { diff --git a/src/structures/Presence.js b/src/structures/Presence.js index e788124fc..535c7d11d 100644 --- a/src/structures/Presence.js +++ b/src/structures/Presence.js @@ -160,21 +160,22 @@ class RichPresenceAssets { /** * ID of the large image asset - * @type {?string} + * @type {?Snowflake} */ this.largeImage = assets.large_image || null; /** * ID of the small image asset - * @type {?string} + * @type {?Snowflake} */ this.smallImage = assets.small_image || null; } /** * Gets the URL of the small image asset - * @param {string} format Format of the image - * @param {number} size Size of the image + * @param {Object} [options] Options for the image url + * @param {string} [options.format] Format of the image + * @param {number} [options.size] Size of the image * @returns {?string} The small image URL */ smallImageURL({ format, size } = {}) { @@ -185,8 +186,9 @@ class RichPresenceAssets { /** * Gets the URL of the large image asset - * @param {string} format Format of the image - * @param {number} size Size of the image + * @param {Object} [options] Options for the image url + * @param {string} [options.format] Format of the image + * @param {number} [options.size] Size of the image * @returns {?string} The large image URL */ largeImageURL({ format, size } = {}) { diff --git a/src/structures/Webhook.js b/src/structures/Webhook.js index a781a25a8..f1a5c6a11 100644 --- a/src/structures/Webhook.js +++ b/src/structures/Webhook.js @@ -79,7 +79,6 @@ class Webhook { * (see [here](https://discordapp.com/developers/docs/resources/channel#embed-object) for more details) * @property {boolean} [disableEveryone=this.client.options.disableEveryone] Whether or not @everyone and @here * should be replaced with plain-text - * @property {FileOptions|BufferResolvable} [file] A file to send with the message * @property {FileOptions[]|string[]} [files] Files to send with the message * @property {string|boolean} [code] Language for optional codeblock formatting to apply * @property {boolean|SplitOptions} [split=false] Whether or not the message should be split into multiple messages if From 1a8e8c7a67b59242537a6c97e383bc6aa4e8c8dd Mon Sep 17 00:00:00 2001 From: Sanctuary Date: Sat, 28 Oct 2017 14:06:26 -0300 Subject: [PATCH 14/14] docs: Add/normalize .toString() docs on all classes (#2042) * docs: Add/normalize .toString() examples on all classes * docs: Remove exclamation point on ClientApplication#toString example * docs: Normalize .toString() descriptions on all classes * Use "returns" instead of "concatenates" --- src/structures/ClientApplication.js | 6 +++++- src/structures/DMChannel.js | 7 +++++-- src/structures/Emoji.js | 2 +- src/structures/GroupDMChannel.js | 6 ++---- src/structures/Guild.js | 5 +---- src/structures/GuildChannel.js | 7 ++----- src/structures/GuildMember.js | 4 ++-- src/structures/ReactionEmoji.js | 7 ++++--- src/structures/Role.js | 5 ++++- src/structures/User.js | 4 ++-- 10 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/structures/ClientApplication.js b/src/structures/ClientApplication.js index 494d8c1c3..ccca3f7e0 100644 --- a/src/structures/ClientApplication.js +++ b/src/structures/ClientApplication.js @@ -195,8 +195,12 @@ class ClientApplication extends Base { } /** - * When concatenated with a string, this automatically concatenates the app name rather than the app object. + * When concatenated with a string, this automatically returns the application's name instead of the + * ClientApplication object. * @returns {string} + * @example + * // Logs: Application name: My App + * console.log(`Application name: ${application}`); */ toString() { return this.name; diff --git a/src/structures/DMChannel.js b/src/structures/DMChannel.js index cdd4d2db8..fe6ba57c6 100644 --- a/src/structures/DMChannel.js +++ b/src/structures/DMChannel.js @@ -27,9 +27,12 @@ class DMChannel extends Channel { } /** - * When concatenated with a string, this automatically concatenates the recipient's mention instead of the - * DM channel object. + * When concatenated with a string, this automatically returns the recipient's mention instead of the + * DMChannel object. * @returns {string} + * @example + * // Logs: Hello from <@123456789012345678>! + * console.log(`Hello from ${channel}!`); */ toString() { return this.recipient.toString(); diff --git a/src/structures/Emoji.js b/src/structures/Emoji.js index 4b1ea2680..d1cca2843 100644 --- a/src/structures/Emoji.js +++ b/src/structures/Emoji.js @@ -190,7 +190,7 @@ class Emoji extends Base { } /** - * When concatenated with a string, this automatically returns the emoji mention rather than the object. + * When concatenated with a string, this automatically concatenates the emoji's mention instead of the Emoji object. * @returns {string} * @example * // Send an emoji: diff --git a/src/structures/GroupDMChannel.js b/src/structures/GroupDMChannel.js index e142b070d..2ade06b06 100644 --- a/src/structures/GroupDMChannel.js +++ b/src/structures/GroupDMChannel.js @@ -203,14 +203,12 @@ class GroupDMChannel extends Channel { } /** - * When concatenated with a string, this automatically concatenates the channel's name instead of the Channel object. + * When concatenated with a string, this automatically returns the channel's name instead of the + * GroupDMChannel object. * @returns {string} * @example * // Logs: Hello from My Group DM! * console.log(`Hello from ${channel}!`); - * @example - * // Logs: Hello from My Group DM! - * console.log(`Hello from ' + channel + '!'); */ toString() { return this.name; diff --git a/src/structures/Guild.js b/src/structures/Guild.js index 1b9463b51..73adbe1df 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -1123,14 +1123,11 @@ class Guild extends Base { } /** - * When concatenated with a string, this automatically concatenates the guild's name instead of the guild object. + * When concatenated with a string, this automatically returns the guild's name instead of the Guild object. * @returns {string} * @example * // Logs: Hello from My Guild! * console.log(`Hello from ${guild}!`); - * @example - * // Logs: Hello from My Guild! - * console.log('Hello from ' + guild + '!'); */ toString() { return this.name; diff --git a/src/structures/GuildChannel.js b/src/structures/GuildChannel.js index a1e8d53a0..896e2bdf8 100644 --- a/src/structures/GuildChannel.js +++ b/src/structures/GuildChannel.js @@ -493,11 +493,8 @@ class GuildChannel extends Channel { * When concatenated with a string, this automatically returns the channel's mention instead of the Channel object. * @returns {string} * @example - * // Outputs: Hello from #general - * console.log(`Hello from ${channel}`); - * @example - * // Outputs: Hello from #general - * console.log('Hello from ' + channel); + * // Logs: Hello from <#123456789012345678>! + * console.log(`Hello from ${channel}!`); */ toString() { return `<#${this.id}>`; diff --git a/src/structures/GuildMember.js b/src/structures/GuildMember.js index 010775e29..7ab2597fd 100644 --- a/src/structures/GuildMember.js +++ b/src/structures/GuildMember.js @@ -529,10 +529,10 @@ class GuildMember extends Base { } /** - * When concatenated with a string, this automatically concatenates the user's mention instead of the Member object. + * When concatenated with a string, this automatically returns the user's mention instead of the GuildMember object. * @returns {string} * @example - * // Logs: Hello from <@123456789>! + * // Logs: Hello from <@123456789012345678>! * console.log(`Hello from ${member}!`); */ toString() { diff --git a/src/structures/ReactionEmoji.js b/src/structures/ReactionEmoji.js index f550544c6..94ea38930 100644 --- a/src/structures/ReactionEmoji.js +++ b/src/structures/ReactionEmoji.js @@ -35,11 +35,12 @@ class ReactionEmoji { } /** - * Creates the text required to form a graphical emoji on Discord. + * When concatenated with a string, this automatically returns the text required to form a graphical emoji on Discord + * instead of the ReactionEmoji object. + * @returns {string} * @example * // Send the emoji used in a reaction to the channel the reaction is part of - * reaction.message.channel.send(`The emoji used is ${reaction.emoji}`); - * @returns {string} + * reaction.message.channel.send(`The emoji used was: ${reaction.emoji}`); */ toString() { return this.id ? `<:${this.name}:${this.id}>` : this.name; diff --git a/src/structures/Role.js b/src/structures/Role.js index eb60185db..39c28e11b 100644 --- a/src/structures/Role.js +++ b/src/structures/Role.js @@ -332,8 +332,11 @@ class Role extends Base { } /** - * When concatenated with a string, this automatically concatenates the role mention rather than the Role object. + * When concatenated with a string, this automatically returns the role's mention instead of the Role object. * @returns {string} + * @example + * // Logs: Role: <@&123456789012345678> + * console.log(`Role: ${role}`); */ toString() { if (this.id === this.guild.id) return '@everyone'; diff --git a/src/structures/User.js b/src/structures/User.js index 859cdeeb2..001a999be 100644 --- a/src/structures/User.js +++ b/src/structures/User.js @@ -248,10 +248,10 @@ class User extends Base { } /** - * When concatenated with a string, this automatically concatenates the user's mention instead of the User object. + * When concatenated with a string, this automatically returns the user's mention instead of the User object. * @returns {string} * @example - * // logs: Hello from <@123456789>! + * // Logs: Hello from <@123456789012345678>! * console.log(`Hello from ${user}!`); */ toString() {