409 lines
14 KiB
JavaScript
409 lines
14 KiB
JavaScript
/* eslint-disable no-useless-escape */
|
|
class Resolver {
|
|
|
|
constructor(client) {
|
|
this.client = client;
|
|
}
|
|
|
|
components(str = '', type, exact = true) {
|
|
|
|
const string = str.toLowerCase();
|
|
|
|
const components = this.client.registry.components
|
|
.filter((c) => c.type === type)
|
|
.filter(exact ? filterExact(string) : filterInexact(string)) //eslint-disable-line no-use-before-define
|
|
.array();
|
|
|
|
return components || [];
|
|
|
|
}
|
|
|
|
resolveBoolean(input) {
|
|
input = input.toLowerCase();
|
|
const truthy = [ 'on', 'true', 'yes', 'enable', 'y' ];
|
|
const falsey = [ 'off', 'false', 'no', 'disable', 'n' ];
|
|
|
|
if(truthy.includes(input)) {
|
|
return true;
|
|
} else if (falsey.includes(input)) {
|
|
return false;
|
|
}
|
|
return null;
|
|
|
|
}
|
|
|
|
// resolveTrue(input) {
|
|
// return [ 'on', 'true' ].includes(input.toLowerCase());
|
|
// }
|
|
|
|
// resolveFalse(input) {
|
|
// return [].includes(input.toLowerCase());
|
|
// }
|
|
|
|
/**
|
|
* Resolves methods used primarily for settings, also deals with appending the arguments into existing lists
|
|
*
|
|
* @param {Array<String>} args The incoming arguments with the first element being the method ex. ['add','ban','kick']
|
|
* @param {Array<String>} valid An array of items to compare to, if an argument doesn't exist in this array it'll be skipped over
|
|
* @param {Array<String>} [existing=[]] Existing values in the array, valid elements will be appended to this
|
|
* @returns {Object}
|
|
* @memberof Resolver
|
|
*/
|
|
resolveMethod(args, valid, existing = []) {
|
|
|
|
const methods = {
|
|
list: ['view', 'list', '?'],
|
|
add: ['add', '+'],
|
|
remove: ['remove', 'delete', '-']
|
|
};
|
|
|
|
if (!args.length) return false;
|
|
// eslint-disable-next-line prefer-const
|
|
let [method, ...rest] = args;
|
|
method = method.toLowerCase();
|
|
|
|
if (!rest.length) {
|
|
if (methods.list.includes(method)) return { method: 'list', rest };
|
|
if (methods.add.includes(method)) return { method: 'add', rest };
|
|
if (methods.remove.includes(method)) return { method: 'remove', rest };
|
|
}
|
|
|
|
if (methods.list.includes(method)) {
|
|
return { method: 'list' };
|
|
} else if (methods.add.includes(method)) {
|
|
const added = [];
|
|
for (let elem of rest) {
|
|
elem = elem.toLowerCase();
|
|
if (existing.includes(elem) || valid && !valid.includes(elem)) continue;
|
|
added.push(elem);
|
|
existing.push(elem);
|
|
}
|
|
|
|
return { rest, method: 'add', changed: added, result: existing };
|
|
} else if (methods.remove.includes(method)) {
|
|
const removed = [];
|
|
for (let elem of rest) {
|
|
elem = elem.toLowerCase();
|
|
if (!existing.includes(elem) || removed.includes(elem) || valid && !valid.includes(elem)) continue;
|
|
removed.push(elem);
|
|
existing.splice(existing.indexOf(elem), 1);
|
|
}
|
|
|
|
return { rest, method: 'remove', changed: removed, result: existing };
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
async resolveMemberAndUser(string, guild) {
|
|
|
|
const str = string.toLowerCase();
|
|
const index = guild ? guild.members.cache : this.client.users.cache;
|
|
|
|
let member = null;
|
|
if((/<@!?(\d{17,21})>/iyu).test(str)) { //mentions
|
|
const matches = (/<@!?(\d{17,21})>/iuy).exec(str);
|
|
member = index.get(matches[1]);
|
|
if(!member) {
|
|
try {
|
|
member = await index.fetch(matches[1]);
|
|
} catch(e) {
|
|
try {
|
|
member = await this.client.users.cache.fetch(matches[1]);
|
|
} catch(e) {} //eslint-disable-line no-empty
|
|
} //eslint-disable-line no-empty
|
|
}
|
|
} else if((/\d{17,21}/iuy).test(str)) { //id
|
|
const matches = (/(\d{17,21})/iuy).exec(str);
|
|
member = index.get(matches[1]);
|
|
if(!member) {
|
|
try {
|
|
member = await index.fetch(matches[1]);
|
|
} catch(e) {
|
|
try {
|
|
member = await this.client.users.cache.fetch(matches[1]);
|
|
} catch(e) {} //eslint-disable-line no-empty
|
|
} //eslint-disable-line no-empty
|
|
}
|
|
} else if((/(.{2,32})#(\d{4})/iuy).test(str)) { //username#discrim
|
|
const matches = (/(.{2,32})#(\d{4})/iuy).exec(str);
|
|
member = guild
|
|
? guild.members.cache.filter((m) => m.user.username === matches[1] && m.user.discriminator === matches[2]).first()
|
|
: this.client.users.cache.filter((u) => u.username === matches[1] && u.discriminator === matches[2]).first();
|
|
}
|
|
|
|
return member || null;
|
|
|
|
}
|
|
|
|
/**
|
|
* Resolve several user resolveables
|
|
*
|
|
* @param {array<string>} [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;
|
|
const { users } = this.client;
|
|
const resolved = [];
|
|
|
|
for(const resolveable of resolveables) {
|
|
|
|
if((/<@!?([0-9]{17,21})>/u).test(resolveable)) {
|
|
|
|
const [, id] = resolveable.match(/<@!?([0-9]{17,21})>/u);
|
|
const user = await users.fetch(id).catch((err) => {
|
|
if(err.code === 10013) return false;
|
|
this.client.logger.warn(err); return false;
|
|
|
|
});
|
|
if(user) resolved.push(user);
|
|
|
|
} else if((/(id:)?([0-9]{17,21})/u).test(resolveable)) {
|
|
|
|
const [,, id] = resolveable.match(/(id:)?([0-9]{17,21})/u);
|
|
const user = await users.fetch(id).catch((err) => {
|
|
if(err.code === 10013) return false;
|
|
this.client.logger.warn(err); return false;
|
|
|
|
});
|
|
if(user) resolved.push(user);
|
|
|
|
} else if((/^@?([\S\s]{1,32})#([0-9]{4})/u).test(resolveable)) {
|
|
|
|
const m = resolveable.match(/^@?([\S\s]{1,32})#([0-9]{4})/u);
|
|
const username = m[1].toLowerCase();
|
|
const discrim = m[2].toLowerCase();
|
|
const user = users.cache.filter((u) => u.username.toLowerCase() === username && u.discriminator === discrim).first();
|
|
if(user) resolved.push(user);
|
|
|
|
} else if(!strict) {
|
|
|
|
const name = resolveable.toLowerCase();
|
|
const user = users.cache.filter((u) => u.username.toLowerCase().includes(name)).first();
|
|
if(user) resolved.push(user);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return resolved.length ? resolved : false;
|
|
|
|
}
|
|
|
|
async resolveUser(resolveable, strict) {
|
|
|
|
if (!resolveable) return false;
|
|
const result = await this.resolveUsers([ resolveable ], strict);
|
|
return result ? result[0] : false;
|
|
|
|
}
|
|
|
|
/**
|
|
* Resolve multiple member resolveables
|
|
*
|
|
* @param {array<string>} [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<GuildMember> || 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;
|
|
const { members } = guild;
|
|
const resolved = [];
|
|
|
|
for(const resolveable of resolveables) {
|
|
|
|
if((/<@!?([0-9]{17,21})>/u).test(resolveable)) {
|
|
|
|
const [, id] = resolveable.match(/<@!?([0-9]{17,21})>/u);
|
|
const member = await members.fetch(id).catch((err) => {
|
|
if(err.code === 10007) return false;
|
|
this.client.logger.warn(err); return false;
|
|
|
|
});
|
|
if(member) resolved.push(member);
|
|
|
|
} else if((/(id:)?([0-9]{17,21})/u).test(resolveable)) {
|
|
|
|
const [,, id] = resolveable.match(/(id:)?([0-9]{17,21})/u);
|
|
const member = await members.fetch(id).catch((err) => {
|
|
if(err.code === 10007) return false;
|
|
this.client.logger.warn(err); return false;
|
|
|
|
});
|
|
if(member) resolved.push(member);
|
|
|
|
} else if((/^@?([\S\s]{1,32})#([0-9]{4})/u).test(resolveable)) {
|
|
|
|
const m = resolveable.match(/^@?([\S\s]{1,32})#([0-9]{4})/u);
|
|
const username = m[1].toLowerCase();
|
|
const discrim = m[2].toLowerCase();
|
|
const member = members.cache.filter((m) => m.user.username.toLowerCase() === username && m.user.discriminator === discrim).first();
|
|
if(member) resolved.push(member);
|
|
|
|
} else if((/^@?([\S\s]{1,32})/u).test(resolveable) && guild && !strict) {
|
|
|
|
const nickname = resolveable.match(/^@?([\S\s]{1,32})/u)[0].toLowerCase();
|
|
const member = members.cache.filter((m) => 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();
|
|
if(member) resolved.push(member);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return resolved.length > 0 ? resolved : false;
|
|
|
|
}
|
|
|
|
async resolveMember(resolveable, guild, strict) {
|
|
|
|
if (!resolveable) return false;
|
|
const result = await this.resolveMembers([ resolveable ], guild, strict);
|
|
return result ? result[0] : false;
|
|
|
|
}
|
|
|
|
/**
|
|
* Resolve multiple channels
|
|
*
|
|
* @param {array<string>} [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<GuildChannel> || false} an array of guild channels or false if none were resolved
|
|
* @memberof Resolver
|
|
*/
|
|
resolveChannels(resolveables = [], guild, strict = false) {
|
|
|
|
if(typeof resolveables === 'string') resolveables = [ resolveables ];
|
|
if(resolveables.length === 0) return false;
|
|
const { channels } = guild;
|
|
const resolved = [];
|
|
|
|
for(const resolveable of resolveables) {
|
|
|
|
const channel = channels.resolve(resolveable);
|
|
if(channel) {
|
|
resolved.push(channel);
|
|
continue;
|
|
}
|
|
|
|
const name = /^#?([a-z0-9\-_0]*)/iu;
|
|
const id = /^<#([0-9]*)>/iu;
|
|
|
|
if (id.test(resolveable)) {
|
|
|
|
const match = resolveable.match(id);
|
|
const [, ch] = match;
|
|
|
|
const channel = channels.resolve(ch);
|
|
|
|
if (channel) resolved.push(channel);
|
|
|
|
} else if (name.test(resolveable)) {
|
|
|
|
const match = resolveable.match(name);
|
|
const ch = match[1].toLowerCase();
|
|
|
|
const [ 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return resolved.length > 0 ? resolved : false;
|
|
|
|
}
|
|
|
|
resolveChannel(resolveable, guild, strict) {
|
|
|
|
if (!resolveable) return false;
|
|
const result = this.resolveChannels([resolveable], guild, strict);
|
|
return result ? result[0] : false;
|
|
|
|
}
|
|
|
|
/**
|
|
* Resolve multiple roles
|
|
*
|
|
* @param {array<string>} [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<GuildRole> || 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;
|
|
const { roles } = guild;
|
|
const resolved = [];
|
|
|
|
for(const resolveable of resolveables) {
|
|
|
|
const id = /^(<@&)?([0-9]{16,22})>?/iu;
|
|
|
|
if(id.test(resolveable)) {
|
|
|
|
const match = resolveable.match(id);
|
|
const [,, rId] = match;
|
|
|
|
const role = await roles.fetch(rId).catch(this.client.logger.error);
|
|
|
|
if(role) resolved.push(role);
|
|
|
|
} else {
|
|
|
|
const role = roles.cache.filter((r) => {
|
|
if(!strict) return r.name.toLowerCase().includes(resolveable.toLowerCase());
|
|
return r.name.toLowerCase() === resolveable.toLowerCase();
|
|
}).first();
|
|
|
|
if(role) resolved.push(role);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return resolved.length > 0 ? resolved : false;
|
|
|
|
}
|
|
|
|
async resolveRole(resolveable, guild, strict) {
|
|
|
|
if (!resolveable) return false;
|
|
const result = await this.resolveRoles([resolveable], guild, strict);
|
|
return result ? result[0] : false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
module.exports = Resolver;
|
|
|
|
const filterExact = (search) => (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) => (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))); |