summaryrefslogtreecommitdiff
path: root/node_modules/discord.js/src/structures/interfaces
diff options
context:
space:
mode:
author8cy <[email protected]>2020-04-30 15:46:16 -0700
committer8cy <[email protected]>2020-04-30 15:46:16 -0700
commit3a4deac89054021b56ad5bd8005b2044cc085c98 (patch)
tree3dd6af8503e497e46180b6b5231674f36bdce9f2 /node_modules/discord.js/src/structures/interfaces
downloaduppity-3a4deac89054021b56ad5bd8005b2044cc085c98.tar.xz
uppity-3a4deac89054021b56ad5bd8005b2044cc085c98.zip
Up, up, uppity.
Diffstat (limited to 'node_modules/discord.js/src/structures/interfaces')
-rw-r--r--node_modules/discord.js/src/structures/interfaces/Collector.js281
-rw-r--r--node_modules/discord.js/src/structures/interfaces/TextBasedChannel.js396
2 files changed, 677 insertions, 0 deletions
diff --git a/node_modules/discord.js/src/structures/interfaces/Collector.js b/node_modules/discord.js/src/structures/interfaces/Collector.js
new file mode 100644
index 0000000..21d01ca
--- /dev/null
+++ b/node_modules/discord.js/src/structures/interfaces/Collector.js
@@ -0,0 +1,281 @@
+'use strict';
+
+const EventEmitter = require('events');
+const Collection = require('../../util/Collection');
+const Util = require('../../util/Util');
+
+/**
+ * Filter to be applied to the collector.
+ * @typedef {Function} CollectorFilter
+ * @param {...*} args Any arguments received by the listener
+ * @param {Collection} collection The items collected by this collector
+ * @returns {boolean}
+ */
+
+/**
+ * Options to be applied to the collector.
+ * @typedef {Object} CollectorOptions
+ * @property {number} [time] How long to run the collector for in milliseconds
+ * @property {number} [idle] How long to stop the collector after inactivity in milliseconds
+ * @property {boolean} [dispose=false] Whether to dispose data when it's deleted
+ */
+
+/**
+ * Abstract class for defining a new Collector.
+ * @abstract
+ */
+class Collector extends EventEmitter {
+ constructor(client, filter, options = {}) {
+ super();
+
+ /**
+ * The client that instantiated this Collector
+ * @name Collector#client
+ * @type {Client}
+ * @readonly
+ */
+ Object.defineProperty(this, 'client', { value: client });
+
+ /**
+ * The filter applied to this collector
+ * @type {CollectorFilter}
+ */
+ this.filter = filter;
+
+ /**
+ * The options of this collector
+ * @type {CollectorOptions}
+ */
+ this.options = options;
+
+ /**
+ * The items collected by this collector
+ * @type {Collection}
+ */
+ this.collected = new Collection();
+
+ /**
+ * Whether this collector has finished collecting
+ * @type {boolean}
+ */
+ this.ended = false;
+
+ /**
+ * Timeout for cleanup
+ * @type {?Timeout}
+ * @private
+ */
+ this._timeout = null;
+
+ /**
+ * Timeout for cleanup due to inactivity
+ * @type {?Timeout}
+ * @private
+ */
+ this._idletimeout = null;
+
+ this.handleCollect = this.handleCollect.bind(this);
+ this.handleDispose = this.handleDispose.bind(this);
+
+ if (options.time) this._timeout = this.client.setTimeout(() => this.stop('time'), options.time);
+ if (options.idle) this._idletimeout = this.client.setTimeout(() => this.stop('idle'), options.idle);
+ }
+
+ /**
+ * Call this to handle an event as a collectable element. Accepts any event data as parameters.
+ * @param {...*} args The arguments emitted by the listener
+ * @emits Collector#collect
+ */
+ handleCollect(...args) {
+ const collect = this.collect(...args);
+
+ if (collect && this.filter(...args, this.collected)) {
+ this.collected.set(collect, args[0]);
+
+ /**
+ * Emitted whenever an element is collected.
+ * @event Collector#collect
+ * @param {...*} args The arguments emitted by the listener
+ */
+ this.emit('collect', ...args);
+
+ if (this._idletimeout) {
+ this.client.clearTimeout(this._idletimeout);
+ this._idletimeout = this.client.setTimeout(() => this.stop('idle'), this.options.idle);
+ }
+ }
+ this.checkEnd();
+ }
+
+ /**
+ * Call this to remove an element from the collection. Accepts any event data as parameters.
+ * @param {...*} args The arguments emitted by the listener
+ * @emits Collector#dispose
+ */
+ handleDispose(...args) {
+ if (!this.options.dispose) return;
+
+ const dispose = this.dispose(...args);
+ if (!dispose || !this.filter(...args) || !this.collected.has(dispose)) return;
+ this.collected.delete(dispose);
+
+ /**
+ * Emitted whenever an element is disposed of.
+ * @event Collector#dispose
+ * @param {...*} args The arguments emitted by the listener
+ */
+ this.emit('dispose', ...args);
+ this.checkEnd();
+ }
+
+ /**
+ * Returns a promise that resolves with the next collected element;
+ * rejects with collected elements if the collector finishes without receiving a next element
+ * @type {Promise}
+ * @readonly
+ */
+ get next() {
+ return new Promise((resolve, reject) => {
+ if (this.ended) {
+ reject(this.collected);
+ return;
+ }
+
+ const cleanup = () => {
+ this.removeListener('collect', onCollect);
+ this.removeListener('end', onEnd);
+ };
+
+ const onCollect = item => {
+ cleanup();
+ resolve(item);
+ };
+
+ const onEnd = () => {
+ cleanup();
+ reject(this.collected); // eslint-disable-line prefer-promise-reject-errors
+ };
+
+ this.on('collect', onCollect);
+ this.on('end', onEnd);
+ });
+ }
+
+ /**
+ * Stops this collector and emits the `end` event.
+ * @param {string} [reason='user'] The reason this collector is ending
+ * @emits Collector#end
+ */
+ stop(reason = 'user') {
+ if (this.ended) return;
+
+ if (this._timeout) {
+ this.client.clearTimeout(this._timeout);
+ this._timeout = null;
+ }
+ if (this._idletimeout) {
+ this.client.clearTimeout(this._idletimeout);
+ this._idletimeout = null;
+ }
+ this.ended = true;
+
+ /**
+ * Emitted when the collector is finished collecting.
+ * @event Collector#end
+ * @param {Collection} collected The elements collected by the collector
+ * @param {string} reason The reason the collector ended
+ */
+ this.emit('end', this.collected, reason);
+ }
+
+ /**
+ * Resets the collectors timeout and idle timer.
+ * @param {Object} [options] Options
+ * @param {number} [options.time] How long to run the collector for in milliseconds
+ * @param {number} [options.idle] How long to stop the collector after inactivity in milliseconds
+ */
+ resetTimer({ time, idle } = {}) {
+ if (this._timeout) {
+ this.client.clearTimeout(this._timeout);
+ this._timeout = this.client.setTimeout(() => this.stop('time'), time || this.options.time);
+ }
+ if (this._idletimeout) {
+ this.client.clearTimeout(this._idletimeout);
+ this._idletimeout = this.client.setTimeout(() => this.stop('idle'), idle || this.options.idle);
+ }
+ }
+
+ /**
+ * Checks whether the collector should end, and if so, ends it.
+ */
+ checkEnd() {
+ const reason = this.endReason();
+ if (reason) this.stop(reason);
+ }
+
+ /**
+ * Allows collectors to be consumed with for-await-of loops
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of}
+ */
+ async *[Symbol.asyncIterator]() {
+ const queue = [];
+ const onCollect = item => queue.push(item);
+ this.on('collect', onCollect);
+
+ try {
+ while (queue.length || !this.ended) {
+ if (queue.length) {
+ yield queue.shift();
+ } else {
+ // eslint-disable-next-line no-await-in-loop
+ await new Promise(resolve => {
+ const tick = () => {
+ this.removeListener('collect', tick);
+ this.removeListener('end', tick);
+ return resolve();
+ };
+ this.on('collect', tick);
+ this.on('end', tick);
+ });
+ }
+ }
+ } finally {
+ this.removeListener('collect', onCollect);
+ }
+ }
+
+ toJSON() {
+ return Util.flatten(this);
+ }
+
+ /* eslint-disable no-empty-function, valid-jsdoc */
+ /**
+ * Handles incoming events from the `handleCollect` function. Returns null if the event should not
+ * be collected, or returns an object describing the data that should be stored.
+ * @see Collector#handleCollect
+ * @param {...*} args Any args the event listener emits
+ * @returns {?{key, value}} Data to insert into collection, if any
+ * @abstract
+ */
+ collect() {}
+
+ /**
+ * Handles incoming events from the `handleDispose`. Returns null if the event should not
+ * be disposed, or returns the key that should be removed.
+ * @see Collector#handleDispose
+ * @param {...*} args Any args the event listener emits
+ * @returns {?*} Key to remove from the collection, if any
+ * @abstract
+ */
+ dispose() {}
+
+ /**
+ * The reason this collector has ended or will end with.
+ * @returns {?string} Reason to end the collector, if any
+ * @abstract
+ */
+ endReason() {}
+ /* eslint-enable no-empty-function, valid-jsdoc */
+}
+
+module.exports = Collector;
diff --git a/node_modules/discord.js/src/structures/interfaces/TextBasedChannel.js b/node_modules/discord.js/src/structures/interfaces/TextBasedChannel.js
new file mode 100644
index 0000000..b63c92a
--- /dev/null
+++ b/node_modules/discord.js/src/structures/interfaces/TextBasedChannel.js
@@ -0,0 +1,396 @@
+'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');
+
+/**
+ * Interface for classes that have text-channel-like features.
+ * @interface
+ */
+class TextBasedChannel {
+ constructor() {
+ /**
+ * A manager of the messages sent to this channel
+ * @type {MessageManager}
+ */
+ this.messages = new MessageManager(this);
+
+ /**
+ * The ID of the last message in the channel, if one was sent
+ * @type {?Snowflake}
+ */
+ this.lastMessageID = null;
+
+ /**
+ * The timestamp when the last pinned message was pinned, if there was one
+ * @type {?number}
+ */
+ this.lastPinTimestamp = null;
+ }
+
+ /**
+ * The Message object of the last message in the channel, if one was sent
+ * @type {?Message}
+ * @readonly
+ */
+ get lastMessage() {
+ return this.messages.cache.get(this.lastMessageID) || null;
+ }
+
+ /**
+ * The date when the last pinned message was pinned, if there was one
+ * @type {?Date}
+ * @readonly
+ */
+ get lastPinAt() {
+ return this.lastPinTimestamp ? new Date(this.lastPinTimestamp) : null;
+ }
+
+ /**
+ * Options provided when sending or editing a message.
+ * @typedef {Object} MessageOptions
+ * @property {boolean} [tts=false] Whether or not the message should be spoken aloud
+ * @property {string} [nonce=''] The nonce for the message
+ * @property {string} [content=''] The content for the message
+ * @property {MessageEmbed|Object} [embed] An embed for the message
+ * (see [here](https://discordapp.com/developers/docs/resources/channel#embed-object) for more details)
+ * @property {MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the message content
+ * @property {DisableMentionType} [disableMentions=this.client.options.disableMentions] Whether or not all mentions or
+ * everyone/here mentions should be sanitized to prevent unexpected mentions
+ * @property {FileOptions[]|BufferResolvable[]} [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
+ * it exceeds the character limit. If an object is provided, these are the options for splitting the message
+ * @property {UserResolvable} [reply] User to reply to (prefixes the message with a mention, except in DMs)
+ */
+
+ /**
+ * Options provided to control parsing of mentions by Discord
+ * @typedef {Object} MessageMentionOptions
+ * @property {MessageMentionTypes[]} [parse] Types of mentions to be parsed
+ * @property {Snowflake[]} [users] Snowflakes of Users to be parsed as mentions
+ * @property {Snowflake[]} [roles] Snowflakes of Roles to be parsed as mentions
+ */
+
+ /**
+ * Types of mentions to enable in MessageMentionOptions.
+ * - `roles`
+ * - `users`
+ * - `everyone`
+ * @typedef {string} MessageMentionTypes
+ */
+
+ /**
+ * The type of mentions to disable.
+ * - `none`
+ * - `all`
+ * - `everyone`
+ * @typedef {string} DisableMentionType
+ */
+
+ /**
+ * @typedef {Object} FileOptions
+ * @property {BufferResolvable} attachment File to attach
+ * @property {string} [name='file.jpg'] Filename of the attachment
+ */
+
+ /**
+ * Options for splitting a message.
+ * @typedef {Object} SplitOptions
+ * @property {number} [maxLength=2000] Maximum character length per message piece
+ * @property {string} [char='\n'] Character to split the message with
+ * @property {string} [prepend=''] Text to prepend to every piece except the first
+ * @property {string} [append=''] Text to append to every piece except the last
+ */
+
+ /**
+ * Sends a message to this channel.
+ * @param {StringResolvable|APIMessage} [content=''] The content to send
+ * @param {MessageOptions|MessageAdditions} [options={}] The options to provide
+ * @returns {Promise<Message|Message[]>}
+ * @example
+ * // Send a basic message
+ * channel.send('hello!')
+ * .then(message => console.log(`Sent message: ${message.content}`))
+ * .catch(console.error);
+ * @example
+ * // Send a remote file
+ * channel.send({
+ * files: ['https://cdn.discordapp.com/icons/222078108977594368/6e1019b3179d71046e463a75915e7244.png?size=2048']
+ * })
+ * .then(console.log)
+ * .catch(console.error);
+ * @example
+ * // Send a local file
+ * channel.send({
+ * files: [{
+ * attachment: 'entire/path/to/file.jpg',
+ * name: 'file.jpg'
+ * }]
+ * })
+ * .then(console.log)
+ * .catch(console.error);
+ * @example
+ * // Send an embed with a local image inside
+ * channel.send('This is an embed', {
+ * embed: {
+ * thumbnail: {
+ * url: 'attachment://file.jpg'
+ * }
+ * },
+ * files: [{
+ * attachment: 'entire/path/to/file.jpg',
+ * name: 'file.jpg'
+ * }]
+ * })
+ * .then(console.log)
+ * .catch(console.error);
+ */
+ 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));
+ }
+
+ let apiMessage;
+
+ if (content instanceof APIMessage) {
+ apiMessage = content.resolveData();
+ } else {
+ apiMessage = APIMessage.create(this, content, options).resolveData();
+ if (Array.isArray(apiMessage.data.content)) {
+ return Promise.all(apiMessage.split().map(this.send.bind(this)));
+ }
+ }
+
+ 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);
+ }
+
+ /**
+ * Starts a typing indicator in the channel.
+ * @param {number} [count=1] The number of times startTyping should be considered to have been called
+ * @returns {Promise} Resolves once the bot stops typing gracefully, or rejects when an error occurs
+ * @example
+ * // Start typing in a channel, or increase the typing count by one
+ * channel.startTyping();
+ * @example
+ * // Start typing in a channel with a typing count of five, or set it to five
+ * channel.startTyping(5);
+ */
+ startTyping(count) {
+ if (typeof count !== 'undefined' && count < 1) throw new RangeError('TYPING_COUNT');
+ if (this.client.user._typing.has(this.id)) {
+ const entry = this.client.user._typing.get(this.id);
+ entry.count = count || entry.count + 1;
+ return entry.promise;
+ }
+
+ const entry = {};
+ entry.promise = new Promise((resolve, reject) => {
+ const endpoint = this.client.api.channels[this.id].typing;
+ Object.assign(entry, {
+ count: count || 1,
+ interval: this.client.setInterval(() => {
+ endpoint.post().catch(error => {
+ this.client.clearInterval(entry.interval);
+ this.client.user._typing.delete(this.id);
+ reject(error);
+ });
+ }, 9000),
+ resolve,
+ });
+ endpoint.post().catch(error => {
+ this.client.clearInterval(entry.interval);
+ this.client.user._typing.delete(this.id);
+ reject(error);
+ });
+ this.client.user._typing.set(this.id, entry);
+ });
+ return entry.promise;
+ }
+
+ /**
+ * Stops the typing indicator in the channel.
+ * The indicator will only stop if this is called as many times as startTyping().
+ * <info>It can take a few seconds for the client user to stop typing.</info>
+ * @param {boolean} [force=false] Whether or not to reset the call count and force the indicator to stop
+ * @example
+ * // Reduce the typing count by one and stop typing if it reached 0
+ * channel.stopTyping();
+ * @example
+ * // Force typing to fully stop regardless of typing count
+ * channel.stopTyping(true);
+ */
+ stopTyping(force = false) {
+ if (this.client.user._typing.has(this.id)) {
+ const entry = this.client.user._typing.get(this.id);
+ entry.count--;
+ if (entry.count <= 0 || force) {
+ this.client.clearInterval(entry.interval);
+ this.client.user._typing.delete(this.id);
+ entry.resolve();
+ }
+ }
+ }
+
+ /**
+ * Whether or not the typing indicator is being shown in the channel
+ * @type {boolean}
+ * @readonly
+ */
+ get typing() {
+ return this.client.user._typing.has(this.id);
+ }
+
+ /**
+ * Number of times `startTyping` has been called
+ * @type {number}
+ * @readonly
+ */
+ get typingCount() {
+ if (this.client.user._typing.has(this.id)) return this.client.user._typing.get(this.id).count;
+ return 0;
+ }
+
+ /**
+ * Creates a Message Collector.
+ * @param {CollectorFilter} filter The filter to create the collector with
+ * @param {MessageCollectorOptions} [options={}] The options to pass to the collector
+ * @returns {MessageCollector}
+ * @example
+ * // Create a message collector
+ * const filter = m => m.content.includes('discord');
+ * const collector = channel.createMessageCollector(filter, { time: 15000 });
+ * collector.on('collect', m => console.log(`Collected ${m.content}`));
+ * collector.on('end', collected => console.log(`Collected ${collected.size} items`));
+ */
+ createMessageCollector(filter, options = {}) {
+ return new MessageCollector(this, filter, options);
+ }
+
+ /**
+ * An object containing the same properties as CollectorOptions, but a few more:
+ * @typedef {MessageCollectorOptions} AwaitMessagesOptions
+ * @property {string[]} [errors] Stop/end reasons that cause the promise to reject
+ */
+
+ /**
+ * Similar to createMessageCollector but in promise form.
+ * Resolves with a collection of messages that pass the specified filter.
+ * @param {CollectorFilter} filter The filter function to use
+ * @param {AwaitMessagesOptions} [options={}] Optional options to pass to the internal collector
+ * @returns {Promise<Collection<Snowflake, Message>>}
+ * @example
+ * // Await !vote messages
+ * const filter = m => m.content.startsWith('!vote');
+ * // Errors: ['time'] treats ending because of the time limit as an error
+ * channel.awaitMessages(filter, { max: 4, time: 60000, errors: ['time'] })
+ * .then(collected => console.log(collected.size))
+ * .catch(collected => console.log(`After a minute, only ${collected.size} out of 4 voted.`));
+ */
+ awaitMessages(filter, options = {}) {
+ return new Promise((resolve, reject) => {
+ const collector = this.createMessageCollector(filter, options);
+ collector.once('end', (collection, reason) => {
+ if (options.errors && options.errors.includes(reason)) {
+ reject(collection);
+ } else {
+ resolve(collection);
+ }
+ });
+ });
+ }
+
+ /**
+ * Bulk deletes given messages that are newer than two weeks.
+ * @param {Collection<Snowflake, Message>|Message[]|Snowflake[]|number} messages
+ * Messages or number of messages to delete
+ * @param {boolean} [filterOld=false] Filter messages to remove those which are older than two weeks automatically
+ * @returns {Promise<Collection<Snowflake, Message>>} Deleted messages
+ * @example
+ * // Bulk delete messages
+ * channel.bulkDelete(5)
+ * .then(messages => console.log(`Bulk deleted ${messages.size} messages`))
+ * .catch(console.error);
+ */
+ async bulkDelete(messages, filterOld = false) {
+ 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);
+ }
+ 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,
+ );
+ 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(),
+ );
+ }
+ if (!isNaN(messages)) {
+ const msgs = await this.messages.fetch({ limit: messages });
+ return this.bulkDelete(msgs, filterOld);
+ }
+ throw new TypeError('MESSAGE_BULK_DELETE_TYPE');
+ }
+
+ static applyToClass(structure, full = false, ignore = []) {
+ const props = ['send'];
+ if (full) {
+ props.push(
+ 'lastMessage',
+ 'lastPinAt',
+ 'bulkDelete',
+ 'startTyping',
+ 'stopTyping',
+ 'typing',
+ 'typingCount',
+ 'createMessageCollector',
+ 'awaitMessages',
+ );
+ }
+ for (const prop of props) {
+ if (ignore.includes(prop)) continue;
+ Object.defineProperty(
+ structure.prototype,
+ prop,
+ Object.getOwnPropertyDescriptor(TextBasedChannel.prototype, prop),
+ );
+ }
+ }
+}
+
+module.exports = TextBasedChannel;
+
+// Fixes Circular
+const MessageManager = require('../../managers/MessageManager');