Compare commits

..

2 Commits

Author SHA1 Message Date
f5ab2b4297 eslint 2022-02-13 21:39:29 -06:00
983f742f0d useless change 2022-02-13 21:04:40 -06:00
10 changed files with 2733 additions and 282 deletions

55
.eslintrc.json Normal file
View File

@@ -0,0 +1,55 @@
{
"root": true,
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": { "project": ["./tsconfig.json"] },
"plugins": [
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/strict-boolean-expressions": [
2,
{
"allowString" : false,
"allowNumber" : false
}
],
/* important */
"prefer-const": "error",
"quotes": ["error", "single"],
"block-scoped-var": "error",
"camelcase": "error",
"consistent-this": ["error", "that"],
"no-else-return": "error",
"no-eq-null": "error",
"no-floating-decimal": "error",
"no-implicit-coercion": "error",
"no-implied-eval": "error",
"no-invalid-this": "error",
"require-await": "error",
"yoda": "error",
"semi": ["error", "always"],
"semi-style": ["error", "last"],
/* less important */
"no-unreachable-loop": "error",
"no-unused-private-class-members": "error",
"no-use-before-define": "error",
"no-unmodified-loop-condition": "error",
"no-duplicate-imports": "error",
"no-promise-executor-return": "error",
"no-self-compare": "error",
"no-constructor-return": "error",
"no-template-curly-in-string": "error",
"array-callback-return": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "error"
},
"ignorePatterns": ["src/**/*.test.ts", "src/frontend/generated/*"]
}

2393
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,7 @@
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@types/node": "^17.0.17", "@types/node": "^17.0.17",
"@typescript-eslint/eslint-plugin": "^5.11.0",
"discord-api-types": "^0.26.1", "discord-api-types": "^0.26.1",
"npm-watch": "^0.11.0", "npm-watch": "^0.11.0",
"ts-node": "^10.4.0", "ts-node": "^10.4.0",

View File

@@ -1,3 +1,4 @@
/*eslint prefer-const: "error"*/
import * as cheerio from 'cheerio'; import * as cheerio from 'cheerio';
import { CommandInteraction, MessageEmbed } from 'discord.js'; import { CommandInteraction, MessageEmbed } from 'discord.js';
import { IncomingMessage } from 'http'; import { IncomingMessage } from 'http';
@@ -12,7 +13,7 @@ const uniteApiRegex = {
/lv\.(\d+) (\w+) \((\d+)\)/i, //master /lv\.(\d+) (\w+) \((\d+)\)/i, //master
/lv\.(\d+) (\w+): class (\d+)/i //other /lv\.(\d+) (\w+): class (\d+)/i //other
] ]
} };
type uniteApiData = { type uniteApiData = {
name: string, name: string,
@@ -76,30 +77,30 @@ function getHTML(name: string): Promise<string> {
* @throws errorMessage class if the request fails * @throws errorMessage class if the request fails
*/ */
function readHTML(html: string): uniteApiData { function readHTML(html: string): uniteApiData {
let $ = cheerio.load(html) const $ = cheerio.load(html),
let metaElems = $('meta').toArray(),
foundData: uniteApiData = { foundData: uniteApiData = {
name: "", name: '',
id: "", id: '',
avatar: "", avatar: '',
level: "", level: '',
rank: "", rank: '',
elo: null, elo: null,
class: null, class: null,
battles: "", battles: '',
wins: "", wins: '',
winrate: "" winrate: ''
}; };
let metaElems = $('meta').toArray();
//filter down to just ones named "og:..." //filter down to just ones named "og:..."
metaElems = metaElems.filter((el: cheerio.Element) => el.attribs.property?.startsWith('og:')); metaElems = metaElems.filter(el => el.attribs.property?.startsWith('og:'));
metaElems.forEach((el: cheerio.Element) => { metaElems.forEach(el => {
let attr = el.attribs; const attr = el.attribs;
if (attr.property === 'og:title') { if (attr.property === 'og:title') {
let data = uniteApiRegex.ogtitle.exec(attr.content); const data = uniteApiRegex.ogtitle.exec(attr.content);
if (data !== null && data.length >= 3) { if (data !== null && data.length >= 3) {
foundData.name = data[1]; foundData.name = data[1];
foundData.id = data[2]; foundData.id = data[2];
@@ -107,17 +108,17 @@ function readHTML(html: string): uniteApiData {
} else if (attr.property === 'og:description') { } else if (attr.property === 'og:description') {
//all lines //all lines
let lines = attr.content.split('\n').map((l: string) => l.trim()), let lines = attr.content.split('\n').map(l => l.trim());
extraLines: string[] = []; const extraLines: string[] = [];
//ensure first line is correct //ensure first line is correct
while (lines.length && !/pok.mon unite/i.test(lines[0])) { while ((lines.length > 0) && !/pok.mon unite/i.test(lines[0])) {
let line = lines.shift(); const line = lines.shift();
if (line) if (line !== undefined)
extraLines.push(line); extraLines.push(line);
} }
if (!lines.length) if (lines.length === 0)
throw emsg('Unable to read data, please try again'); throw emsg('Unable to read data, please try again');
//bring the first lines removed back into the data //bring the first lines removed back into the data
@@ -129,13 +130,12 @@ function readHTML(html: string): uniteApiData {
//first line //first line
{ {
//will be only text after "pokemon unite:" //will be only text after "pokemon unite:"
let line = lines[0].split(':').slice(1).join(':').trim(); const line = lines[0].split(':').slice(1).join(':').trim(),
regex = uniteApiRegex.ogdescription;
let regex = uniteApiRegex.ogdescription;
if (regex[0].test(line)) { //is master/has elo if (regex[0].test(line)) { //is master/has elo
let regexData = line.match(regex[0]); const regexData = line.match(regex[0]);
if (!regexData || regexData.length < 4) if (!regexData || regexData.length < 4)
throw emsg('Unable to read data, please try again'); throw emsg('Unable to read data, please try again');
@@ -146,7 +146,7 @@ function readHTML(html: string): uniteApiData {
} else { //is not master/has a class } else { //is not master/has a class
let regexData = line.match(regex[1]); const regexData = line.match(regex[1]);
if (!regexData || regexData.length < 4) if (!regexData || regexData.length < 4)
throw emsg('Unable to read data, please try again'); throw emsg('Unable to read data, please try again');
@@ -162,9 +162,9 @@ function readHTML(html: string): uniteApiData {
lines.shift(); lines.shift();
//rest of lines //rest of lines
lines.forEach((line: string) => { lines.forEach(line => {
let split = line.split(':').map((l: string) => l.trim()), const split = line.split(':').map(l => l.trim()),
key = split[0].toLowerCase().replace(/[^\w]/g, ''), key = split[0].toLowerCase().replace(/[^\w]/g, ''),
value = split[1]; value = split[1];
@@ -186,7 +186,9 @@ function readHTML(html: string): uniteApiData {
}); });
foundData.avatar = $('.player-card-image img').attr('src') || ""; const imgSrc = $('.player-card-image img').attr('src');
foundData.avatar = imgSrc !== undefined ? imgSrc : '';
foundData.avatar = foundData.avatar.replace('../', 'https://uniteapi.dev/'); foundData.avatar = foundData.avatar.replace('../', 'https://uniteapi.dev/');
return foundData; return foundData;
@@ -199,7 +201,7 @@ function readHTML(html: string): uniteApiData {
* @returns boolean, valid or invalid * @returns boolean, valid or invalid
*/ */
function verifyData(data: uniteApiData): boolean { function verifyData(data: uniteApiData): boolean {
if (data.id.length) if (data.id.length > 0)
return true; return true;
return false; return false;
} }
@@ -210,8 +212,8 @@ function verifyData(data: uniteApiData): boolean {
* @returns player data * @returns player data
*/ */
export async function getPlayer(name: string): Promise<uniteApiData|null> { export async function getPlayer(name: string): Promise<uniteApiData|null> {
let html = await getHTML(name); const html = await getHTML(name),
let data = readHTML(html); data = readHTML(html);
if (verifyData(data)) if (verifyData(data))
return data; return data;
return null; return null;
@@ -219,13 +221,19 @@ export async function getPlayer(name: string): Promise<uniteApiData|null> {
async function sendPlayerEmbed(interaction: CommandInteraction, data: uniteApiData) { async function sendPlayerEmbed(interaction: CommandInteraction, data: uniteApiData) {
let embed = new MessageEmbed() let eloStr: string;
if (data.elo !== null)
eloStr = `(${data.elo})`;
else
eloStr = `Class ${data.class}`;
const embed = new MessageEmbed()
.setTitle(`${data.name} (${data.id})`) .setTitle(`${data.name} (${data.id})`)
.setURL(`https://uniteapi.dev/p/${encodeURIComponent(data.name)}`) .setURL(`https://uniteapi.dev/p/${encodeURIComponent(data.name)}`)
.setTimestamp() .setTimestamp()
.setThumbnail(data.avatar) .setThumbnail(data.avatar)
.setDescription(`Level ${data.level} .setDescription(`Level ${data.level}
${data.rank} ${data.elo ? `(${data.elo})` : `Class ${data.class}`} ${data.rank} ${eloStr}
**Battles** ${data.battles} **Battles** ${data.battles}
**Wins** ${data.wins} **Wins** ${data.wins}
@@ -240,10 +248,10 @@ ${data.rank} ${data.elo ? `(${data.elo})` : `Class ${data.class}`}
* @throws errorMessage class if the user cannot be found * @throws errorMessage class if the user cannot be found
*/ */
export async function getPlayerInteraction(interaction: CommandInteraction) { export async function getPlayerInteraction(interaction: CommandInteraction) {
let username = interaction.options.getString('username', true); const username = interaction.options.getString('username', true);
await interaction.deferReply(); await interaction.deferReply();
let data = await getPlayer(username); const data = await getPlayer(username);
if (data === null) if (data === null)
throw emsg('api.noUser'); throw emsg('api.noUser');
else else

View File

@@ -1,3 +1,4 @@
/* eslint-disable camelcase */
import { REST } from '@discordjs/rest'; import { REST } from '@discordjs/rest';
import { Routes } from 'discord-api-types/v9'; import { Routes } from 'discord-api-types/v9';
@@ -45,8 +46,8 @@ const commands = [
} }
] ]
} }
]/*, ];
commandNames = commands.map(c => c.name);*/ /*commandNames = commands.map(c => c.name);*/
/** /**
* register/reload commands on guild(s) * register/reload commands on guild(s)

View File

@@ -3,7 +3,7 @@ import { Client, Intents } from 'discord.js';
import * as fs from 'fs'; import * as fs from 'fs';
import { getPlayerInteraction } from './api'; import { getPlayerInteraction } from './api';
import { registerCommands } from './discord'; import { registerCommands } from './discord';
import { Lang } from './lang'; import * as Lang from './lang';
import { discordInit, QueueCommands } from './queue'; import { discordInit, QueueCommands } from './queue';
import { errorMessage } from './util'; import { errorMessage } from './util';
const CLIENT = new Client({ intents: [Intents.FLAGS.GUILDS] }); const CLIENT = new Client({ intents: [Intents.FLAGS.GUILDS] });

View File

@@ -26,7 +26,7 @@ const LANG: LangObjWhole = {
discord: { discord: {
noQueue: 'There is not an active queue in this channel, type `/open` to create one', noQueue: 'There is not an active queue in this channel, type `/open` to create one',
noChannel: 'Unable to find channel {channelId} for teams of {teamsize}', noChannel: 'Unable to find channel {channelId} for teams of {teamsize}',
noCreate: 'There is already an active queue in this channel for teams of ${teamsize}', noCreate: 'There is already an active queue in this channel for teams of {teamsize}',
inQueue: 'You are already in the queue', inQueue: 'You are already in the queue',
notInQueue: 'You aren\'t in the queue', notInQueue: 'You aren\'t in the queue',
notMod: 'Member is not a moderator' notMod: 'Member is not a moderator'
@@ -45,64 +45,61 @@ const LANG: LangObjWhole = {
} }
} };
export namespace Lang {
var LANGID = 'en'; let LANGID = 'en';
if (!(LANGID in LANG)) if (!(LANGID in LANG))
throw 'language id does not exist';
export function setLang(langid: string) {
if (langid in LANG)
LANGID = langid;
else
throw 'language id does not exist'; throw 'language id does not exist';
}
export function setLang(langid: string) { function template(str: string, args: {[keys: string]: string}): string {
if (langid in LANG)
LANGID = langid;
else
throw 'language id does not exist';
}
function template(str: string, args: {[keys: string]: string}): string { return str.replace(/{\w+}/g, str => {
return str.replace(/{\w+}/g, str => { const key = str.substring(1, str.length-1);
let key = str.substring(1, str.length-1); if (key in args)
return args[key];
if (key in args) return key;
return args[key];
return key; });
});
}
/**
* reads language json
* @param id ex: discord.error.noActiveQueue
* @returns language value, defaults to `id` parameter
*/
export function get(id: string, args: {[keys: string]: string} = {}): string {//discord.error.noActiveQueue
let keySpl = id.split('.').map(k => k.trim()).filter(k => k);
let finding = LANG[LANGID];
for (let key of keySpl) {
if (key in finding) {
let found = finding[key];
if (typeof found === 'string')
return template(found, args);
finding = found;
} else
break;
}
return id;
}
} }
/**
* reads language json
* @param id ex: discord.error.noActiveQueue
* @returns language value, defaults to `id` parameter
*/
export function get(id: string, args: {[keys: string]: string} = {}): string {//discord.error.noActiveQueue
const keySpl = id.split('.').map(k => k.trim()).filter(k => k);
let finding = LANG[LANGID];
for (const key of keySpl) {
if (key in finding) {
const found = finding[key];
if (typeof found === 'string')
return template(found, args);
finding = found;
} else
break;
}
return id;
}

View File

@@ -3,10 +3,10 @@
join message should contain your current position in the queue, editing it to keep it current join message should contain your current position in the queue, editing it to keep it current
*/ */
import { Client, CommandInteraction, MessageEmbed, TextChannel } from "discord.js"; import { Client, CommandInteraction, MessageEmbed, TextChannel } from 'discord.js';
import * as fs from 'fs'; import * as fs from 'fs';
import { emsg, getChannel, getMember, memberIsModThrow, queueInfo, queueInfoBase } from "./util"; import { emsg, getChannel, getMember, memberIsModThrow, queueInfo, queueInfoBase } from './util';
import { Lang } from './lang'; import * as Lang from './lang';
//load queues from file //load queues from file
if (!fs.existsSync('./queues.json')) if (!fs.existsSync('./queues.json'))
@@ -17,22 +17,24 @@ const _QUEUE = fs.readFileSync('./queues.json').toString(),
try { try {
let queueJson = JSON.parse(_QUEUE); const queueJson = JSON.parse(_QUEUE);
for (let channelId in queueJson) { for (const channelId in queueJson) {
let {teamsize} = queueJson[channelId] as queueInfoBase; const {teamsize} = queueJson[channelId] as queueInfoBase;
if (teamsize) if (teamsize !== 0)
QUEUE.set(channelId, { teamsize, players: [] }) QUEUE.set(channelId, { teamsize, players: [] });
} }
} catch(e) {} } catch(e) {
//do nothing
}
function SaveQueue() { function SaveQueue() {
let queueJson = Object.fromEntries(QUEUE), const queueJson = Object.fromEntries(QUEUE),
queueFileJson: {[keys: string]: queueInfoBase} = {}; queueFileJson: {[keys: string]: queueInfoBase} = {};
for (let channelId of QUEUE.keys()) for (const channelId of QUEUE.keys())
queueFileJson[channelId] = { teamsize: queueJson[channelId].teamsize }; queueFileJson[channelId] = { teamsize: queueJson[channelId].teamsize };
fs.writeFileSync('./queues.json', JSON.stringify(queueFileJson, null, 2)); fs.writeFileSync('./queues.json', JSON.stringify(queueFileJson, null, 2));
@@ -40,17 +42,17 @@ function SaveQueue() {
} }
async function checkQueue(channel: TextChannel) { async function checkQueue(channel: TextChannel) {
let info = QUEUE.get(channel.id); const info = QUEUE.get(channel.id);
if (!info) if (!info)
return; return;
if (info.players.length >= info.teamsize) { if (info.players.length >= info.teamsize) {
let team = info.players.splice(0, info.teamsize).map(m => m.toString()); const team = info.players.splice(0, info.teamsize).map(m => m.toString());
//TODO add embeds to lang.ts //TODO add embeds to lang.ts
let embed = new MessageEmbed() const embed = new MessageEmbed()
.setTitle('Team') .setTitle('Team')
.setDescription(team.join('\n')); .setDescription(team.join('\n'));
@@ -59,35 +61,33 @@ async function checkQueue(channel: TextChannel) {
} }
} }
namespace Queue {
export function create(channelId: string, teamsize: number) {
if (!QUEUE.has(channelId)) { export function queueCreate(channelId: string, teamsize: number) {
QUEUE.set(channelId, {teamsize, players: []}); if (!QUEUE.has(channelId)) {
SaveQueue(); QUEUE.set(channelId, {teamsize, players: []});
} SaveQueue();
} }
}
export function remove(channelId: string) { export function queueRemove(channelId: string) {
if (QUEUE.has(channelId)) { if (QUEUE.has(channelId)) {
QUEUE.delete(channelId); QUEUE.delete(channelId);
SaveQueue(); SaveQueue();
}
} }
} }
SaveQueue(); SaveQueue();
export async function discordInit(client: Client) { export async function discordInit(client: Client) {
for (let channelId of QUEUE.keys()) { for (const channelId of QUEUE.keys()) {
let info = QUEUE.get(channelId), const info = QUEUE.get(channelId),
channel = await client.channels.fetch(channelId); channel = await client.channels.fetch(channelId);
if (!info) { //no idea what could cause this but TS complains if (!info) { //no idea what could cause this but TS complains
Queue.remove(channelId); queueRemove(channelId);
continue; continue;
} }
@@ -96,7 +96,7 @@ export async function discordInit(client: Client) {
channelId, channelId,
teamsize: info.teamsize teamsize: info.teamsize
}); });
Queue.remove(channelId); queueRemove(channelId);
continue; continue;
} }
@@ -105,160 +105,155 @@ export async function discordInit(client: Client) {
} }
} }
export namespace QueueCommands {
/** /**
* get the queueInfo of an interaction * get the queueInfo of an interaction
* @param interaction * @param interaction
* @throws errorMessage class if it does not exist * @throws errorMessage class if it does not exist
* @returns queue info * @returns queue info
*/ */
function getInfo(interaction: CommandInteraction): queueInfo { function getInfo(interaction: CommandInteraction): queueInfo {
let info = QUEUE.get(interaction.channelId); const info = QUEUE.get(interaction.channelId);
if (!info) if (!info)
throw emsg('discord.noQueue'); throw emsg('discord.noQueue');
return info; return info;
} }
/** /**
* compiles all the get functions above * compiles all the get functions above
* @param interaction * @param interaction
* @throws if another get function throws * @throws if another get function throws
* @returns object containing each * @returns object containing each
*/ */
const getAll = (interaction: CommandInteraction) => ({ const getAll = (interaction: CommandInteraction) => ({
member: getMember(interaction), member: getMember(interaction),
channel: getChannel(interaction), channel: getChannel(interaction),
info: getInfo(interaction) info: getInfo(interaction)
}); });
/** /**
* checks if the interaction data is already in the queue * checks if the interaction data is already in the queue
* @param interaction * @param interaction
* @returns boolean * @returns boolean
*/ */
export function queueContains(interaction: CommandInteraction): boolean { export function queueContains(interaction: CommandInteraction): boolean {
let {member, info} = getAll(interaction); const {member, info} = getAll(interaction);
if (info.players.map(m=>m.id).includes(member.id)) if (info.players.map(m=>m.id).includes(member.id))
return true; return true;
return false; return false;
}
/**
* creates a queue from an interaction
* @param interaction
* @throws errorMessage class if it cannot be left
*/
export function queueCreate(interaction: CommandInteraction) {
memberIsModThrow(interaction);
let {channelId} = interaction,
teamsize = interaction.options.getInteger('teamsize', true);
let existing = QUEUE.get(channelId)
if (existing)
throw emsg(Lang.get('error.discord.noCreate', {
teamsize: existing.teamsize.toString()
}));
Queue.create(channelId, teamsize);
interaction.reply(Lang.get('discord.create', {
teamsize: teamsize.toString()
}))
}
/**
* opens a queue
* @param interaction
* @throws errorMessage class if it cannot be left
*/
export async function open(interaction: CommandInteraction) {
queueCreate(interaction);
}
/**
* closes a queue
* @param interaction
* @throws errorMessage class if it cannot be joined
*/
export async function close(interaction: CommandInteraction) {
memberIsModThrow(interaction);
QUEUE.delete(interaction.channelId);
await interaction.reply(Lang.get('discord.close'));
}
/**
* gives info about the queue
* @param interaction
* @throws errorMessage class if it cannot be left
*/
export async function queue(interaction: CommandInteraction) {
let info = getInfo(interaction);
let embed = new MessageEmbed()
.setTitle('Active Queue')
.addField('Team Size', info.teamsize.toString(), true)
.addField('Players Joined', info.players.length.toString(), true)
.setFooter({text: 'type /join'}); //TODO
await interaction.reply({embeds: [embed], ephemeral: true});
}
/**
* joins a queue
* @param interaction
* @throws errorMessage class if it cannot be readied
*/
export async function join(interaction: CommandInteraction) {
let {member, info, channel} = getAll(interaction);
if (queueContains(interaction))
throw emsg('discord.inQueue');
info.players.push(member);
QUEUE.set(interaction.channelId, info);
await interaction.reply(Lang.get('discord.join'));
checkQueue(channel);
}
/**
* leaves a queue
* @param interaction
* @throws errorMessage class if it cannot be reset
*/
export async function leave(interaction: CommandInteraction) {
let {member, info} = getAll(interaction);
if (!queueContains(interaction))
throw emsg('discord.notInQueue');
info.players.splice(info.players.indexOf(member), 1);
QUEUE.set(interaction.channelId, info);
await interaction.reply(Lang.get('discord.leave'));
}
} }
/**
* opens a queue
* @param interaction
* @throws errorMessage class if it cannot be left
*/
function open(interaction: CommandInteraction) {
memberIsModThrow(interaction);
const {channelId} = interaction,
teamsize = interaction.options.getInteger('teamsize', true);
const existing = QUEUE.get(channelId);
if (existing)
throw emsg(Lang.get('error.discord.noCreate', {
teamsize: existing.teamsize.toString()
}));
queueCreate(channelId, teamsize);
interaction.reply(Lang.get('discord.create', {
teamsize: teamsize.toString()
}));
}
/**
* closes a queue
* @param interaction
* @throws errorMessage class if it cannot be joined
*/
async function close(interaction: CommandInteraction) {
memberIsModThrow(interaction);
QUEUE.delete(interaction.channelId);
await interaction.reply(Lang.get('discord.close'));
}
/**
* gives info about the queue
* @param interaction
* @throws errorMessage class if it cannot be left
*/
async function queue(interaction: CommandInteraction) {
const info = getInfo(interaction);
const embed = new MessageEmbed()
.setTitle('Active Queue')
.addField('Team Size', info.teamsize.toString(), true)
.addField('Players Joined', info.players.length.toString(), true)
.setFooter({text: 'type /join'}); //TODO
await interaction.reply({embeds: [embed], ephemeral: true});
}
/**
* joins a queue
* @param interaction
* @throws errorMessage class if it cannot be readied
*/
async function join(interaction: CommandInteraction) {
const {member, info, channel} = getAll(interaction);
if (queueContains(interaction))
throw emsg('discord.inQueue');
info.players.push(member);
QUEUE.set(interaction.channelId, info);
await interaction.reply(Lang.get('discord.join'));
checkQueue(channel);
}
/**
* leaves a queue
* @param interaction
* @throws errorMessage class if it cannot be reset
*/
async function leave(interaction: CommandInteraction) {
const {member, info} = getAll(interaction);
if (!queueContains(interaction))
throw emsg('discord.notInQueue');
info.players.splice(info.players.indexOf(member), 1);
QUEUE.set(interaction.channelId, info);
await interaction.reply(Lang.get('discord.leave'));
}
export const QueueCommands = {
open,
close,
queue,
join,
leave
};

0
src/queueCommands.ts Normal file
View File

View File

@@ -1,5 +1,5 @@
import { CommandInteraction, GuildMember, TextChannel } from "discord.js"; import { CommandInteraction, GuildMember, TextChannel } from 'discord.js';
import { Lang } from "./lang"; import * as Lang from './lang';
/** /**
* shuffles an array * shuffles an array
@@ -7,6 +7,7 @@ import { Lang } from "./lang";
* @param array an array * @param array an array
* @returns an array but shuffled * @returns an array but shuffled
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function shuffle(array: any[]) { export function shuffle(array: any[]) {
let currentIndex = array.length, randomIndex; let currentIndex = array.length, randomIndex;
@@ -31,7 +32,7 @@ export class errorMessage {
public msg: string; public msg: string;
public ephemeral: boolean; public ephemeral: boolean;
constructor(msg: string, ephemeral: boolean = true) { constructor(msg: string, ephemeral = true) {
this.msg = msg; this.msg = msg;
this.ephemeral = ephemeral; this.ephemeral = ephemeral;
} }
@@ -43,7 +44,7 @@ export class errorMessage {
* @param ephemeral (default=true) * @param ephemeral (default=true)
* @returns new errorMessage * @returns new errorMessage
*/ */
export const emsg = (msg: string, ephemeral: boolean = true) => new errorMessage(Lang.get(`error.${msg}`), ephemeral); export const emsg = (msg: string, ephemeral = true) => new errorMessage(Lang.get(`error.${msg}`), ephemeral);
@@ -61,7 +62,7 @@ export interface queueInfo extends queueInfoBase{
* @returns member * @returns member
*/ */
export function getMember(interaction: CommandInteraction): GuildMember { export function getMember(interaction: CommandInteraction): GuildMember {
let member = interaction.member; const member = interaction.member;
if (!(member instanceof GuildMember)) if (!(member instanceof GuildMember))
throw emsg('general.noMember'); throw emsg('general.noMember');
@@ -76,7 +77,7 @@ export function getMember(interaction: CommandInteraction): GuildMember {
* @returns member * @returns member
*/ */
export function getChannel(interaction: CommandInteraction): TextChannel { export function getChannel(interaction: CommandInteraction): TextChannel {
let channel = interaction.channel; const channel = interaction.channel;
if (!(channel instanceof TextChannel)) if (!(channel instanceof TextChannel))
throw emsg('general.noChannel'); throw emsg('general.noChannel');
@@ -86,7 +87,7 @@ export function getChannel(interaction: CommandInteraction): TextChannel {
export function memberIsMod(interaction: CommandInteraction): boolean { export function memberIsMod(interaction: CommandInteraction): boolean {
let member = getMember(interaction); const member = getMember(interaction);
return member.permissionsIn(interaction.channelId).has('MANAGE_MESSAGES'); return member.permissionsIn(interaction.channelId).has('MANAGE_MESSAGES');
} }