diff --git a/src/Util.js b/src/Util.js index b7081d5..5f5b155 100644 --- a/src/Util.js +++ b/src/Util.js @@ -1,11 +1,34 @@ -const moment = require('moment'); -const fs = require('fs'); const path = require('path'); +const fs = require('fs'); +const fetch = require('node-fetch'); +const { Util: DiscordUtil } = require('discord.js'); class Util { constructor() { - throw new Error(`Class ${this.constructor.name} may not be instantiated.`); + throw new Error("Class may not be instantiated."); + } + + static paginate(items, page = 1, pageLength = 10) { + const maxPage = Math.ceil(items.length / pageLength); + if (page < 1) page = 1; + if (page > maxPage) page = maxPage; + const startIndex = (page - 1) * pageLength; + return { + items: items.length > pageLength ? items.slice(startIndex, startIndex + pageLength) : items, + page, + maxPage, + pageLength + }; + } + + static downloadAsBuffer(source) { + return new Promise((resolve, reject) => { + fetch(source).then((res) => { + if (res.ok) resolve(res.buffer()); + else reject(res.statusText); + }); + }); } static readdirRecursive(directory) { @@ -14,10 +37,10 @@ class Util { (function read(directory) { const files = fs.readdirSync(directory); - for(const file of files) { + for (const file of files) { const filePath = path.join(directory, file); - if(fs.statSync(filePath).isDirectory()) { + if (fs.statSync(filePath).isDirectory()) { read(filePath); } else { result.push(filePath); @@ -29,8 +52,79 @@ class Util { } - static get date() { - return moment().format("YYYY-MM-DD hh:mm:ss"); + static wait(ms) { + return this.delayFor(ms); + } + + static delayFor(ms) { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); + } + + static escapeMarkdown(text, options) { + if (typeof text !== 'string') return text; + return DiscordUtil.escapeMarkdown(text, options); + } + + static get formattingPatterns() { + return [ + ['\\*{1,3}([^*]*)\\*{1,3}', '$1'], + ['_{1,3}([^_]*)_{1,3}', '$1'], + ['`{1,3}([^`]*)`{1,3}', '$1'], + ['~~([^~])~~', '$1'] + ]; + } + + static removeMarkdown(content) { + if (!content) throw new Error('Missing content'); + this.formattingPatterns.forEach(([pattern, replacer]) => { + content = content.replace(new RegExp(pattern, 'gu'), replacer); + }); + return content.trim(); + } + + /** + * Sanitise user given regex; escapes unauthorised characters + * + * @static + * @param {string} input + * @param {string[]} [allowed=['?', '\\', '(', ')', '|']] + * @return {string} The sanitised expression + * @memberof Util + */ + static sanitiseRegex(input, allowed = ['?', '\\', '(', ')', '|']) { + if (!input) throw new Error('Missing input'); + const reg = new RegExp(`[${this.regChars.filter((char) => !allowed.includes(char)).join('')}]`, 'gu'); + return input.replace(reg, '\\$&'); + } + + static get regChars() { + return ['.', '+', '*', '?', '\\[', '\\]', '^', '$', '(', ')', '{', '}', '|', '\\\\', '-']; + } + + static duration(seconds) { + const { plural } = this; + let s = 0, + m = 0, + h = 0, + d = 0, + w = 0; + s = Math.floor(seconds); + m = Math.floor(s / 60); + s %= 60; + h = Math.floor(m / 60); + m %= 60; + d = Math.floor(h / 24); + h %= 24; + w = Math.floor(d / 7); + d %= 7; + return `${w ? `${w} ${plural(w, 'week')} ` : ''}${d ? `${d} ${plural(d, 'day')} ` : ''}${h ? `${h} ${plural(h, 'hour')} ` : ''}${m ? `${m} ${plural(m, 'minute')} ` : ''}${s ? `${s} ${plural(s, 'second')} ` : ''}`.trim(); + } + + static plural(amt, word) { + if (amt === 1) return word; + return `${word}s`; } }