UNPKG

djs-easy

Version:

djs-easy is a javascript package for discord with the a lot stuff you need to make your bot programming easy

127 lines (104 loc) 5.13 kB
const { Collection } = require('discord.js'); /** * @typedef {object} PromptOptions * Note: Setting the `time` option to `Infinity` is strongly disadvised, as it can cause confusion for the user, and may also cause the promise to * never be garbage collected if the prompt is never fulfilled. * @property {number} time The amount of milliseconds to wait before ending the prompt from time. Set this to `0` or `Infinity` for no time limit. * @property {?boolean} cancellable Whether or not the user should be able to reply with cancel to cancel the ongoing prompt. * @property {function(message: Discord.Message, prompt: Prompt): boolean} filter Called with the message and `Prompt` instance to determine whether a * message should be deleted or not. Should not include filtering the user (done internally). * @property {function(message: Discord.Message, prompt: Prompt): void} correct Called with the message and `Prompt` instance that should handle when * a message does not pass the filter. * @property {number} messages The amount of messages to accept before resolving the promise. * @property {number} attempts The amount of times the user is able to fail the filter before having the prompt cancelled. You can set this to `0` or * `Infinity` for infinite attempts permitted. * @property {?boolean} autoRespond Whether or not the bot should automatically respond when the prompt is cancelled/out of time with * `Cancelled prompt.`, or when the max attempts are exceeded, `Too many attempts..` If disabled, you should probably handle this on the promise's * rejection. * @property {?function(message: Discord.Message, prompt: Prompt): boolean} matchUntil Continues matching until the function provided returns true * or when the amount of messages matched is equal to options.messages. */ /** * An instance of this is created whenever `Call#prompt` is called successfully and then added to `handler#prompts` and removed once the prompt is * finished. All parameters translate directly into properties. * @property {Discord.User} user The user the prompt is based around. * @property {Discord.TextChannel} channel The channel the prompt is in. * @property {PromptOptions} options The options of the prompt. * @property {function(value: Discord.Collection|Discord.Message): any} resolve The function to resolve the promise. * @property {function(err: Error): any} reject The function to reject the promise. * @property {boolean} ended Whether or not the prompt has been ended. * @property {number} attempts The amount of attempts the user has made to complete the prompt. * @property {Discord.Collection} values The `Message` objects collected by the prompt. */ class Prompt { constructor(user, channel, options, resolve, reject, handler) { this.startedAt = Date.now(); this.user = user; this.channel = channel; this.options = options; this.resolve = resolve; this.reject = reject; this.ended = false; this.attempts = 0; this.values = new Collection(); this.handler = handler; if (options.time > 0 && options.time < Infinity) setTimeout(this.end.bind(this, 'time'), options.time); } /** * Adds a message object to the values if it passes the filter provided, otherwise calling the correct function provided. * @param {Discord.Message} message * @returns {any} */ async addInput(message) { if (this.ended) return; this.attempts++; // If cancelled. if (this.options.cancellable && message.content.toLowerCase() === 'cancel') return this.end('cancelled'); // Add value to result. if (await this.options.filter(message, this)) { // If matchUntil function returns true if (this.options.matchUntil && this.options.matchUntil(message, this)) { if (this.options.addLastMatch) this.values.set(message.id, message); return this.end('success'); } this.values.set(message.id, message); // Corrects user on invalid input. } else { await this.options.correct(message, this); } // Resolve if messages required obtained. if (this.values.size >= this.options.messages) return this.end('success'); // Attempts surpassed. if (this.options.attempts > 0 && this.attempts >= this.options.attempts) return this.end('attempts'); } /** * Ends the prompt for whatever reason, rejecting the promise if an unsuccessful completion. * @param {'time'|'cancelled'|'attempts'|'success'} reason * @returns {any} */ end(reason) { if (this.ended) return; this.ended = true; let index = this.handler.prompts.findIndex((p) => p.user.id === this.user.id && p.channel.id === this.channel.id); if (index !== -1) this.handler.prompts.splice(index, 1); // If permitted to respond. if (this.options.autoRespond) { if (['time', 'cancelled'].includes(reason)) this.channel.send('Cancelled prompt.'); if (reason === 'attempts') this.channel.send('Too many attempts.'); } if (reason !== 'success') return this.reject(new Error('Prompt ended: ' + reason)); return this.resolve(this.values.size > 1 ? this.values : this.values.first()); } } module.exports = Prompt;