From 6d184257b36bc66063d50ae38dbd4e13381e8ac2 Mon Sep 17 00:00:00 2001 From: bdistin Date: Fri, 21 Sep 2018 03:59:58 -0500 Subject: [PATCH] refactor: remove duplicate send checks (#2790) * re-direct pr code to master * fix Webhook send docs * requested changes * typings: Updated to latest commit * requested change * requested change --- src/structures/APIMessage.js | 59 +++++++++++++++++-- src/structures/Message.js | 13 ++-- src/structures/Webhook.js | 27 +++------ src/structures/interfaces/TextBasedChannel.js | 27 ++++----- typings/index.d.ts | 16 +++-- 5 files changed, 92 insertions(+), 50 deletions(-) diff --git a/src/structures/APIMessage.js b/src/structures/APIMessage.js index 77eb4234b..bb4d16179 100644 --- a/src/structures/APIMessage.js +++ b/src/structures/APIMessage.js @@ -25,6 +25,18 @@ class APIMessage { * @type {MessageOptions|WebhookMessageOptions} */ this.options = options; + + /** + * Data sendable to the API + * @type {?Object} + */ + this.data = null; + + /** + * Files sendable to the API + * @type {?Object[]} + */ + this.files = null; } /** @@ -100,9 +112,11 @@ class APIMessage { /** * Resolves data. - * @returns {Object} + * @returns {APIMessage} */ resolveData() { + if (this.data) return this; + const content = this.makeContent(); const tts = Boolean(this.options.tts); let nonce; @@ -128,7 +142,7 @@ class APIMessage { if (this.options.avatarURL) avatarURL = this.options.avatarURL; } - return { + this.data = { content, tts, nonce, @@ -137,13 +151,16 @@ class APIMessage { username, avatar_url: avatarURL, }; + return this; } /** * Resolves files. - * @returns {Promise} + * @returns {Promise} */ - resolveFiles() { + async resolveFiles() { + if (this.files) return this; + const embedLikes = []; if (this.isWebhook) { if (this.options.embeds) { @@ -163,7 +180,39 @@ class APIMessage { } } - return Promise.all(fileLikes.map(f => this.constructor.resolveFile(f))); + this.files = await Promise.all(fileLikes.map(f => this.constructor.resolveFile(f))); + return this; + } + + /** + * Converts this APIMessage into an array of APIMessages for each split content + * @returns {APIMessage[]} + */ + split() { + if (!this.data) this.resolveData(); + + if (!(this.data.content instanceof Array)) return [this]; + + const apiMessages = []; + + for (let i = 0; i < this.data.content.length; i++) { + let data; + let opt; + + if (i === this.data.content.length - 1) { + data = { ...this.data, content: this.data.content[i] }; + opt = { ...this.options, content: this.data.content[i] }; + } else { + data = { content: this.data.content[i], tts: this.data.tts }; + opt = { content: this.data.content[i], tts: this.data.tts }; + } + + const apiMessage = new APIMessage(this.target, opt); + apiMessage.data = data; + apiMessages.push(apiMessage); + } + + return apiMessages; } /** diff --git a/src/structures/Message.js b/src/structures/Message.js index e229e20cf..88a1707a9 100644 --- a/src/structures/Message.js +++ b/src/structures/Message.js @@ -359,7 +359,7 @@ class Message extends Base { /** * Edits the content of the message. - * @param {StringResolvable} [content=''] The new content for the message + * @param {StringResolvable|APIMessage} [content=''] The new content for the message * @param {MessageEditOptions|MessageEmbed} [options] The options to provide * @returns {Promise} * @example @@ -369,7 +369,9 @@ class Message extends Base { * .catch(console.error); */ edit(content, options) { - const data = APIMessage.create(this, content, options).resolveData(); + 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 => { @@ -458,7 +460,7 @@ class Message extends Base { /** * Replies to the message. - * @param {StringResolvable} [content=''] The content for the message + * @param {StringResolvable|APIMessage} [content=''] The content for the message * @param {MessageOptions|MessageAdditions} [options={}] The options to provide * @returns {Promise} * @example @@ -468,7 +470,10 @@ class Message extends Base { * .catch(console.error); */ reply(content, options) { - return this.channel.send(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 }) + ); } /** diff --git a/src/structures/Webhook.js b/src/structures/Webhook.js index 711b3db79..a719249ea 100644 --- a/src/structures/Webhook.js +++ b/src/structures/Webhook.js @@ -84,7 +84,7 @@ class Webhook { /** * Sends a message with this webhook. - * @param {StringResolvable} [content=''] The content to send + * @param {StringResolvable|APIMessage} [content=''] The content to send * @param {WebhookMessageOptions|MessageAdditions} [options={}] The options to provide * @returns {Promise} * @example @@ -126,27 +126,18 @@ class Webhook { * .catch(console.error); */ async send(content, options) { - const apiMessage = APIMessage.create(this, content, options); - const data = apiMessage.resolveData(); - if (data.content instanceof Array) { - const messages = []; - for (let i = 0; i < data.content.length; i++) { - let opt; - if (i === data.content.length - 1) { - opt = { embeds: data.embeds, files: apiMessage.options.files }; - } else { - opt = {}; - } + let apiMessage; - Object.assign(opt, { avatarURL: data.avatar_url, content: data.content[i], username: data.username }); - // eslint-disable-next-line no-await-in-loop - const message = await this.send(data.content[i], opt); - messages.push(message); + if (content instanceof apiMessage) { + apiMessage = content.resolveData(); + } else { + apiMessage = APIMessage.create(this, content, options).resolveData(); + if (apiMessage.data.content instanceof Array) { + return Promise.all(apiMessage.split().map(this.send.bind(this))); } - return messages; } - const files = await apiMessage.resolveFiles(); + const { data, files } = await apiMessage.resolveFiles(); return this.client.api.webhooks(this.id, this.token).post({ data, files, query: { wait: true }, diff --git a/src/structures/interfaces/TextBasedChannel.js b/src/structures/interfaces/TextBasedChannel.js index 45eecf750..7f9553f1e 100644 --- a/src/structures/interfaces/TextBasedChannel.js +++ b/src/structures/interfaces/TextBasedChannel.js @@ -81,7 +81,7 @@ class TextBasedChannel { /** * Sends a message to this channel. - * @param {StringResolvable} [content=''] The content to send + * @param {StringResolvable|APIMessage} [content=''] The content to send * @param {MessageOptions|MessageAdditions} [options={}] The options to provide * @returns {Promise} * @example @@ -125,30 +125,23 @@ class TextBasedChannel { async send(content, options) { const User = require('../User'); const GuildMember = require('../GuildMember'); + if (this instanceof User || this instanceof GuildMember) { return this.createDM().then(dm => dm.send(content, options)); } - const apiMessage = APIMessage.create(this, content, options); - const data = apiMessage.resolveData(); - if (data.content instanceof Array) { - const messages = []; - for (let i = 0; i < data.content.length; i++) { - let opt; - if (i === data.content.length - 1) { - opt = { tts: data.tts, embed: data.embed, files: apiMessage.options.files }; - } else { - opt = { tts: data.tts }; - } + let apiMessage; - // eslint-disable-next-line no-await-in-loop - const message = await this.send(data.content[i], opt); - messages.push(message); + if (content instanceof APIMessage) { + apiMessage = content.resolveData(); + } else { + apiMessage = APIMessage.create(this, content, options).resolveData(); + if (apiMessage.data.content instanceof Array) { + return Promise.all(apiMessage.split().map(this.send.bind(this))); } - return messages; } - const files = await apiMessage.resolveFiles(); + const { data, files } = await apiMessage.resolveFiles(); return this.client.api.channels[this.id].messages.post({ data, files }) .then(d => this.client.actions.MessageCreate.handle(d).message); } diff --git a/typings/index.d.ts b/typings/index.d.ts index a896dd5a0..39ddc2974 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -42,8 +42,10 @@ declare module 'discord.js' { export class APIMessage { constructor(target: MessageTarget, options: MessageOptions | WebhookMessageOptions); + public data?: object; public readonly isUser: boolean; public readonly isWebhook: boolean; + public files?: object[]; public options: MessageOptions | WebhookMessageOptions; public target: MessageTarget; @@ -63,8 +65,10 @@ declare module 'discord.js' { ): MessageOptions | WebhookMessageOptions; public makeContent(): string | string[]; - public resolveData(): object; - public resolveFiles(): Promise; + public resolve(): Promise; + public resolveData(): this; + public resolveFiles(): Promise; + public split(): APIMessage[]; } export class Base { @@ -663,13 +667,13 @@ declare module 'discord.js' { public createReactionCollector(filter: CollectorFilter, options?: ReactionCollectorOptions): ReactionCollector; public delete(options?: { timeout?: number, reason?: string }): Promise; public edit(content: StringResolvable, options?: MessageEditOptions | MessageEmbed): Promise; - public edit(options: MessageEditOptions | MessageEmbed): Promise; + public edit(options: MessageEditOptions | MessageEmbed | APIMessage): Promise; public equals(message: Message, rawData: object): boolean; public fetchWebhook(): Promise; public pin(): Promise; public react(emoji: EmojiIdentifierResolvable): Promise; public reply(content?: StringResolvable, options?: MessageOptions | MessageAdditions): Promise; - public reply(options?: MessageOptions | MessageAdditions): Promise; + public reply(options?: MessageOptions | MessageAdditions | APIMessage): Promise; public toJSON(): object; public toString(): string; public unpin(): Promise; @@ -1382,7 +1386,7 @@ declare module 'discord.js' { lastPinTimestamp: number; readonly lastPinAt: Date; send(content?: StringResolvable, options?: MessageOptions | MessageAdditions): Promise; - send(options?: MessageOptions | MessageAdditions): Promise; + send(options?: MessageOptions | MessageAdditions | APIMessage): Promise; }; type TextBasedChannelFields = { @@ -1404,7 +1408,7 @@ declare module 'discord.js' { delete(reason?: string): Promise; edit(options: WebhookEditData): Promise; send(content?: StringResolvable, options?: WebhookMessageOptions | MessageAdditions): Promise; - send(options?: WebhookMessageOptions | MessageAdditions): Promise; + send(options?: WebhookMessageOptions | MessageAdditions | APIMessage): Promise; sendSlackMessage(body: object): Promise; };