class Resolver { constructor(client) { this.client = client; } components(str = '', type, exact = true) { //used for CommandHandler const string = str.toLowerCase(); const components = this.client.registry.components .filter(c => c.type === type) .filter(exact ? filterExact(string) : filterInexact(string)) .array(); return components || []; } async resolveMemberAndUser(string, guild) { const str = string.toLowerCase(); const index = guild ? guild.members : this.client.users; let member = null; if(/<@!?(\d{17,21})>/iy.test(str)) { //mentions const matches = /<@!?(\d{17,21})>/iy.exec(str); member = index.get(matches[1]); if(!member) { try { member = await index.fetch(matches[1]); } catch(e) { try { member = await this.client.users.fetch(matches[1]); } catch(e) {} //eslint-disable-line no-empty } //eslint-disable-line no-empty } } else if(/\d{17,21}/iy.test(str)) { //id const matches = /(\d{17,21})/iy.exec(str); member = index.get(matches[1]); if(!member) { try { member = await index.fetch(matches[1]); } catch(e) { try { member = await this.client.users.fetch(matches[1]); } catch(e) {} //eslint-disable-line no-empty } //eslint-disable-line no-empty } } else if(/(.{2,32})#(\d{4})/iy.test(str)) { //username#discrim const matches = /(.{2,32})#(\d{4})/iy.exec(str); member = guild ? guild.members.filter(m=>m.user.username === matches[1] && m.user.discriminator === matches[2]).first() : this.client.users.filter(u=>u.username === matches[1] && u.discriminator === matches[2]).first(); } return member || null; } /** * Resolve several user resolveables * * @param {array} [resolveables=[]] an array of user resolveables (name, id, tag) * @param {boolean} [strict=false] whether or not to attempt resolving by partial usernames * @returns {array || boolean} Array of resolved users or false if none were resolved * @memberof Resolver */ async resolveUsers(resolveables = [], strict = false) { if(typeof resolveables === 'string') resolveables = [ resolveables ]; if(resolveables.length === 0) return false; let users = this.client.users; let resolved = []; for(let resolveable of resolveables) { if(/<@!?([0-9]{17,21})>/.test(resolveable)) { let id = resolveable.match(/<@!?([0-9]{17,21})>/)[1]; let user = await users.fetch(id).catch(err => { if(err.code === 10013) return false; else { console.warn(err); return false; } }); if(user) resolved.push(user); } else if(/(id\:)?([0-9]{17,21})/.test(resolveable)) { let id = resolveable.match(/(id\:)?([0-9]{17,21})/)[2]; let user = await users.fetch(id).catch(err => { if(err.code === 10013) return false; else { console.warn(err); return false; } }); if(user) resolved.push(user); } else if(/^\@?([\S\s]{1,32})\#([0-9]{4})/.test(resolveable)) { let m = resolveable.match(/^\@?([\S\s]{1,32})\#([0-9]{4})/); let username = m[1].toLowerCase(); let discrim = m[2].toLowerCase(); let user = users.cache.filter(u => { return u.username.toLowerCase() === username && u.discriminator === discrim }).first(1); if(user) resolved.push(user); } else if(!strict) { let name = resolveable.toLowerCase(); let user = users.cache.filter(u => { return u.username.toLowerCase().includes(name); }).first(1); if(user) resolved.push(user); } } return resolved.length > 0 ? resolved : false; } /** * Resolve multiple member resolveables * * @param {array} [resolveables=[]] an array of member resolveables (name, nickname, tag, id) * @param {boolean} [strict=false] whether or not to attempt resolving by partial matches * @param {Guild} guild the guild in which to look for members * @returns {array || boolean} an array of resolved members or false if none were resolved * @memberof Resolver */ async resolveMembers(resolveables = [], guild, strict = false) { if(typeof resolveables === 'string') resolveables = [ resolveables ]; if(resolveables.length === 0) return false; let members = guild.members; let resolved = []; for(let resolveable of resolveables) { if(/<@!?([0-9]{17,21})>/.test(resolveable)) { let id = resolveable.match(/<@!?([0-9]{17,21})>/)[1]; let member = await members.fetch(id).catch(err => { if(err.code === 10007) return false; else { console.warn(err); return false; } }); if(member) resolved.push(member); } else if(/(id\:)?([0-9]{17,21})/.test(resolveable)) { let id = resolveable.match(/(id\:)?([0-9]{17,21})/)[2]; let member = await members.fetch(id).catch(err => { if(err.code === 10007) return false; else { console.warn(err); return false; } }); if(member) resolved.push(member); } else if(/^\@?([\S\s]{1,32})\#([0-9]{4})/.test(resolveable)) { let m = resolveable.match(/^\@?([\S\s]{1,32})\#([0-9]{4})/); let username = m[1].toLowerCase(); let discrim = m[2].toLowerCase(); let member = members.cache.filter(m => { return m.user.username.toLowerCase() === username && m.user.discriminator === discrim }).first(1); if(member) resolved.push(member); } else if(/^\@?([\S\s]{1,32})/.test(resolveable) && guild && !strict) { let nickname = resolveable.match(/^\@?([\S\s]{1,32})/)[0].toLowerCase(); let member = members.cache.filter((m) => { return (m && m.user) && ((!m.nickname ? false : m.nickname.toLowerCase() == nickname ) || (!m.nickname ? false : m.nickname.toLowerCase().includes(nickname)) || m.user.username.toLowerCase().includes(nickname) || m.user.username.toLowerCase() == nickname); }).first(1); if(member) resolved.push(member); } } return resolved.length > 0 ? resolved : false; } /** * Resolve multiple channels * * @param {array} [resolveables=[]] an array of channel resolveables (name, id) * @param {guild} guild the guild in which to look for channels * @param {boolean} [strict=false] whether or not partial names are resolved * @returns {array || false} an array of guild channels or false if none were resolved * @memberof Resolver */ async resolveChannels(resolveables = [], guild, strict = false) { if(typeof resolveables === 'string') resolveables = [ resolveables ]; if(resolveables.length === 0) return false; let channels = guild.channels; let resolved = []; for(let resolveable of resolveables) { let channel = channels.resolve(resolveable); if(channel) { resolved.push(channel); continue; } let name = /^\#?([a-z0-9\-\_0]*)/i; let id = /^\<\#([0-9]*)\>/i; if(name.test(resolveable)) { let match = resolveable.match(name); let ch = match[1].toLowerCase(); let channel = channels.cache.filter(c => { if(!strict) return c.name.toLowerCase().includes(ch) return c.name.toLowerCase() === ch; }).first(1); if(channel) resolved.push(channel); } else if(id.test(resolveable)) { let match = resolveable.match(id); let ch = match[1]; let channel = channels.resolve(ch); if(channel) resolved.push(channel); } } return resolved.length > 0 ? resolved : false; } /** * Resolve multiple roles * * @param {array} [resolveables=[]] an array of roles resolveables (name, id) * @param {Guild} guild the guild in which to look for roles * @param {boolean} [strict=false] whether or not partial names are resolved * @returns {array || false} an array of roles or false if none were resolved * @memberof Resolver */ async resolveRoles(resolveables = [], guild, strict = false) { if(typeof resolveables === 'string') resolveables = [ resolveables ]; if(resolveables.length === 0) return false; let roles = guild.roles; let resolved = []; for(let resolveable of resolveables) { let id = /^(<@&)?([0-9]{16,22})>?/i; if(id.test(resolveable)) { let match = resolveable.match(id); let r_id = match[2]; let role = await roles.fetch(r_id).catch(console.error); if(role) resolved.push(role); } else { let role = roles.cache.filter(r => { if(!strict) return r.name.toLowerCase().includes(resolveable.toLowerCase()); return r.name.toLowerCase() === resolveable.toLowerCase(); }).first(1); if(role) resolved.push(role); } } return resolved.length > 0 ? reoslved : false; } } module.exports = Resolver; const filterExact = (search) => { return comp => comp.id.toLowerCase() === search || comp.resolveable.toLowerCase() === search || (comp.aliases && (comp.aliases.some(ali => `${comp.type}:${ali}`.toLowerCase() === search) || comp.aliases.some(ali => ali.toLowerCase() === search))); }; const filterInexact = (search) => { return comp => comp.id.toLowerCase().includes(search) || comp.resolveable.toLowerCase().includes(search) || (comp.aliases && (comp.aliases.some(ali => `${comp.type}:${ali}`.toLowerCase().includes(search)) || comp.aliases.some(ali => ali.toLowerCase().includes(search)))); };