diff options
Diffstat (limited to 'node_modules/discord.js/src/structures/APIMessage.js')
| -rw-r--r-- | node_modules/discord.js/src/structures/APIMessage.js | 379 |
1 files changed, 379 insertions, 0 deletions
diff --git a/node_modules/discord.js/src/structures/APIMessage.js b/node_modules/discord.js/src/structures/APIMessage.js new file mode 100644 index 0000000..86dab74 --- /dev/null +++ b/node_modules/discord.js/src/structures/APIMessage.js @@ -0,0 +1,379 @@ +'use strict'; + +const MessageAttachment = require('./MessageAttachment'); +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. + */ +class APIMessage { + /** + * @param {MessageTarget} target - The target for this message to be sent to + * @param {MessageOptions|WebhookMessageOptions} options - Options passed in from send + */ + constructor(target, options) { + /** + * The target for this message to be sent to + * @type {MessageTarget} + */ + this.target = target; + + /** + * Options passed in from send + * @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; + } + + /** + * Whether or not the target is a webhook + * @type {boolean} + * @readonly + */ + get isWebhook() { + const Webhook = require('./Webhook'); + const WebhookClient = require('../client/WebhookClient'); + return this.target instanceof Webhook || this.target instanceof WebhookClient; + } + + /** + * Whether or not the target is a user + * @type {boolean} + * @readonly + */ + get isUser() { + const User = require('./User'); + const GuildMember = require('./GuildMember'); + return this.target instanceof User || this.target instanceof GuildMember; + } + + /** + * Whether or not the target is a message + * @type {boolean} + * @readonly + */ + get isMessage() { + const Message = require('./Message'); + return this.target instanceof Message; + } + + /** + * Makes the content of this message. + * @returns {?(string|string[])} + */ + makeContent() { + const GuildMember = require('./GuildMember'); + + let content; + if (this.options.content === null) { + content = ''; + } else if (typeof this.options.content !== 'undefined') { + content = Util.resolveString(this.options.content); + } + + 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(/@([^<>@ ]*)/gmsu, (match, target) => { + if (target.match(/^[&!]?\d+$/)) { + return `@${target}`; + } else { + return `@\u200b${target}`; + } + }); + } + + const isSplit = typeof this.options.split !== 'undefined' && this.options.split !== false; + const isCode = typeof this.options.code !== 'undefined' && this.options.code !== false; + const splitOptions = isSplit ? { ...this.options.split } : undefined; + + let mentionPart = ''; + if (this.options.reply && !this.isUser && this.target.type !== 'dm') { + const id = this.target.client.users.resolveID(this.options.reply); + mentionPart = `<@${this.options.reply instanceof GuildMember && this.options.reply.nickname ? '!' : ''}${id}>, `; + if (isSplit) { + splitOptions.prepend = `${mentionPart}${splitOptions.prepend || ''}`; + } + } + + if (content || mentionPart) { + if (isCode) { + const codeName = typeof this.options.code === 'string' ? this.options.code : ''; + content = `${mentionPart}\`\`\`${codeName}\n${Util.cleanCodeBlockContent(content || '')}\n\`\`\``; + if (isSplit) { + splitOptions.prepend = `${splitOptions.prepend || ''}\`\`\`${codeName}\n`; + splitOptions.append = `\n\`\`\`${splitOptions.append || ''}`; + } + } else if (mentionPart) { + content = `${mentionPart}${content || ''}`; + } + + if (isSplit) { + content = Util.splitMessage(content || '', splitOptions); + } + } + + return content; + } + + /** + * Resolves data. + * @returns {APIMessage} + */ + resolveData() { + if (this.data) return this; + + const content = this.makeContent(); + const tts = Boolean(this.options.tts); + + let nonce; + if (typeof this.options.nonce !== 'undefined') { + nonce = parseInt(this.options.nonce); + if (isNaN(nonce) || nonce < 0) throw new RangeError('MESSAGE_NONCE_TYPE'); + } + + const embedLikes = []; + if (this.isWebhook) { + if (this.options.embeds) { + embedLikes.push(...this.options.embeds); + } + } else if (this.options.embed) { + embedLikes.push(this.options.embed); + } + const embeds = embedLikes.map(e => new MessageEmbed(e).toJSON()); + + let username; + let avatarURL; + if (this.isWebhook) { + username = this.options.username || this.target.name; + if (this.options.avatarURL) avatarURL = this.options.avatarURL; + } + + let flags; + if (this.isMessage) { + // eslint-disable-next-line eqeqeq + flags = this.options.flags != null ? new MessageFlags(this.options.flags).bitfield : this.target.flags.bitfield; + } + + const allowedMentions = + typeof this.options.allowedMentions === 'undefined' + ? this.target.client.options.allowedMentions + : this.options.allowedMentions; + + this.data = { + content, + tts, + nonce, + embed: this.options.embed === null ? null : embeds[0], + embeds, + username, + avatar_url: avatarURL, + allowed_mentions: allowedMentions, + flags, + }; + return this; + } + + /** + * Resolves files. + * @returns {Promise<APIMessage>} + */ + async resolveFiles() { + if (this.files) return this; + + const embedLikes = []; + if (this.isWebhook) { + if (this.options.embeds) { + embedLikes.push(...this.options.embeds); + } + } else if (this.options.embed) { + embedLikes.push(this.options.embed); + } + + const fileLikes = []; + if (this.options.files) { + fileLikes.push(...this.options.files); + } + for (const embed of embedLikes) { + if (embed.files) { + fileLikes.push(...embed.files); + } + } + + 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 (!Array.isArray(this.data.content)) 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; + } + + /** + * Resolves a single file into an object sendable to the API. + * @param {BufferResolvable|Stream|FileOptions|MessageAttachment} fileLike Something that could be resolved to a file + * @returns {Object} + */ + static async resolveFile(fileLike) { + let attachment; + let name; + + const findName = thing => { + if (typeof thing === 'string') { + return Util.basename(thing); + } + + if (thing.path) { + return Util.basename(thing.path); + } + + return 'file.jpg'; + }; + + const ownAttachment = + typeof fileLike === 'string' || + fileLike instanceof (browser ? ArrayBuffer : Buffer) || + typeof fileLike.pipe === 'function'; + if (ownAttachment) { + attachment = fileLike; + name = findName(attachment); + } else { + attachment = fileLike.attachment; + name = fileLike.name || findName(attachment); + } + + const resource = await DataResolver.resolveFile(attachment); + return { attachment, name, file: resource }; + } + + /** + * Partitions embeds and attachments. + * @param {Array<MessageEmbed|MessageAttachment>} items Items to partition + * @returns {Array<MessageEmbed[], MessageAttachment[]>} + */ + static partitionMessageAdditions(items) { + const embeds = []; + const files = []; + for (const item of items) { + if (item instanceof MessageEmbed) { + embeds.push(item); + } else if (item instanceof MessageAttachment) { + files.push(item); + } + } + + return [embeds, files]; + } + + /** + * Transforms the user-level arguments into a final options object. Passing a transformed options object alone into + * this method will keep it the same, allowing for the reuse of the final options object. + * @param {StringResolvable} [content] Content to send + * @param {MessageOptions|WebhookMessageOptions|MessageAdditions} [options={}] Options to use + * @param {MessageOptions|WebhookMessageOptions} [extra={}] Extra options to add onto transformed options + * @param {boolean} [isWebhook=false] Whether or not to use WebhookMessageOptions as the result + * @returns {MessageOptions|WebhookMessageOptions} + */ + static transformOptions(content, options, extra = {}, isWebhook = false) { + if (!options && typeof content === 'object' && !Array.isArray(content)) { + options = content; + content = undefined; + } + + if (!options) { + options = {}; + } else if (options instanceof MessageEmbed) { + return isWebhook ? { content, embeds: [options], ...extra } : { content, embed: options, ...extra }; + } else if (options instanceof MessageAttachment) { + return { content, files: [options], ...extra }; + } + + if (Array.isArray(options)) { + const [embeds, files] = this.partitionMessageAdditions(options); + return isWebhook ? { content, embeds, files, ...extra } : { content, embed: embeds[0], files, ...extra }; + } else if (Array.isArray(content)) { + const [embeds, files] = this.partitionMessageAdditions(content); + if (embeds.length || files.length) { + return isWebhook ? { embeds, files, ...extra } : { embed: embeds[0], files, ...extra }; + } + } + + return { content, ...options, ...extra }; + } + + /** + * Creates an `APIMessage` from user-level arguments. + * @param {MessageTarget} target Target to send to + * @param {StringResolvable} [content] Content to send + * @param {MessageOptions|WebhookMessageOptions|MessageAdditions} [options={}] Options to use + * @param {MessageOptions|WebhookMessageOptions} [extra={}] - Extra options to add onto transformed options + * @returns {MessageOptions|WebhookMessageOptions} + */ + static create(target, content, options, extra = {}) { + const Webhook = require('./Webhook'); + const WebhookClient = require('../client/WebhookClient'); + + const isWebhook = target instanceof Webhook || target instanceof WebhookClient; + const transformed = this.transformOptions(content, options, extra, isWebhook); + return new this(target, transformed); + } +} + +module.exports = APIMessage; + +/** + * A target for a message. + * @typedef {TextChannel|DMChannel|User|GuildMember|Webhook|WebhookClient} MessageTarget + */ + +/** + * Additional items that can be sent with a message. + * @typedef {MessageEmbed|MessageAttachment|Array<MessageEmbed|MessageAttachment>} MessageAdditions + */ |