From bca21ea74a5ca64c6dc1cee2d442909e1e99404f Mon Sep 17 00:00:00 2001 From: Abheek Dhawan Date: Mon, 21 Mar 2022 02:48:44 -0500 Subject: [PATCH 1/3] Begin TypeScript migration --- .gitignore | 1 + commands/about.js | 78 -------- commands/help.js | 16 -- commands/rounds.js | 113 ------------ commands/top.js | 40 ---- commands/train.js | 172 ------------------ events/interactionCreate.js | 21 --- events/messageCreate.js | 35 ---- events/ready.js | 16 -- helpers/db.js | 45 ----- helpers/env.js | 8 - helpers/log.js | 31 ---- index.js | 34 ---- package.json | 3 +- src/commands/about.ts | 77 ++++++++ src/commands/help.ts | 15 ++ src/commands/rounds.ts | 112 ++++++++++++ src/commands/top.ts | 39 ++++ src/commands/train.ts | 171 +++++++++++++++++ deploy-commands.js => src/deploy-commands.ts | 16 +- src/events/interactionCreate.ts | 21 +++ src/events/messageCreate.ts | 36 ++++ src/events/ready.ts | 16 ++ src/helpers/db.ts | 44 +++++ src/helpers/env.ts | 6 + src/helpers/log.ts | 29 +++ src/index.ts | 38 ++++ .../models/generateRound.ts | 4 +- .../userScore.js => src/models/userScore.ts | 4 +- tsconfig.json | 101 ++++++++++ yarn.lock | 5 + 31 files changed, 726 insertions(+), 621 deletions(-) delete mode 100644 commands/about.js delete mode 100644 commands/help.js delete mode 100644 commands/rounds.js delete mode 100644 commands/top.js delete mode 100644 commands/train.js delete mode 100644 events/interactionCreate.js delete mode 100644 events/messageCreate.js delete mode 100644 events/ready.js delete mode 100644 helpers/db.js delete mode 100644 helpers/env.js delete mode 100644 helpers/log.js delete mode 100755 index.js create mode 100644 src/commands/about.ts create mode 100644 src/commands/help.ts create mode 100644 src/commands/rounds.ts create mode 100644 src/commands/top.ts create mode 100644 src/commands/train.ts rename deploy-commands.js => src/deploy-commands.ts (56%) create mode 100644 src/events/interactionCreate.ts create mode 100644 src/events/messageCreate.ts create mode 100644 src/events/ready.ts create mode 100644 src/helpers/db.ts create mode 100644 src/helpers/env.ts create mode 100644 src/helpers/log.ts create mode 100755 src/index.ts rename models/generateRound.js => src/models/generateRound.ts (70%) rename models/userScore.js => src/models/userScore.ts (59%) create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index 86a0176..d989dc4 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ config.json .DS_Store data/ *.patch +built/ diff --git a/commands/about.js b/commands/about.js deleted file mode 100644 index dfede13..0000000 --- a/commands/about.js +++ /dev/null @@ -1,78 +0,0 @@ -const { SlashCommandBuilder } = require('@discordjs/builders'); -const { MessageEmbed } = require('discord.js'); - -const gitlog = require('gitlog').default; - -const userScore = require('../models/userScore'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('about') - .setDescription('Commands regarding the creation/development of the bot') - .addSubcommand(subcommand => { - subcommand - .setName('contributors') - .setDescription('Lists contributors to the AwesomeSciBo bot'); - return subcommand; - }) - .addSubcommand(subcommand => { - subcommand - .setName('changelog') - .setDescription('Lists the 5 most recent changes in a "git log" type format'); - return subcommand; - }) - .addSubcommand(subcommand => { - subcommand - .setName('bot') - .setDescription('Lists information about AwesomeSciBo'); - return subcommand; - }), - async execute(interaction) { - await interaction.deferReply(); - - const client = interaction.client; - const action = interaction.options.getSubcommand(); - if (action === 'contributors') { - const contributorEmbed = new MessageEmbed().setTitle('Contributors') - .addField('Creator', '<@745063586422063214> [ADawesomeguy#3602]', true) - .addField('Contributors', '<@650525101048987649> [tEjAs#8127]\n<@426864344463048705> [tetrident#9396]', true) // Add more contributors here, first one is Abheek, second one is Tejas - .setTimestamp() - .setColor('#ffffff'); - - interaction.followUp({ embeds: [contributorEmbed] }); - } - else if (action === 'changelog') { - const gitRepoLocation = __dirname; - - const commits = gitlog({ - repo: gitRepoLocation, - number: 5, - fields: ['hash', 'abbrevHash', 'subject', 'authorName', 'authorDateRel'], - }); - - const changelogEmbed = new MessageEmbed() - .setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL() }) - .setTitle('Changelog') - .setColor('#ffffff') - .setTimestamp(); - - commits.forEach(commit => { - changelogEmbed.addField(commit.abbrevHash, `> \`Hash:\`${commit.hash}\n> \`Subject:\`${commit.subject}\n> \`Author:\`${commit.authorName}\n> \`Date:\`${commit.authorDateRel}\n> \`Link\`: [GitHub](https://github.com/ADawesomeguy/AwesomeSciBo/commit/${commit.hash})\n`); - }); - - interaction.followUp({ embeds: [changelogEmbed] }); - } - else if (action === 'bot') { - await client.guilds.fetch(); - const trainingDocuments = await userScore.countDocuments({}); - const aboutBotEmbed = new MessageEmbed() - .setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL() }) - .setTitle('About AwesomeSciBo') - .addField('Servers', `${client.guilds.cache.size}`, true) - .addField('Training Users', `${trainingDocuments}`, true) - .setTimestamp(); - - interaction.followUp({ embeds: [aboutBotEmbed] }); - } - }, -}; diff --git a/commands/help.js b/commands/help.js deleted file mode 100644 index 85c86ae..0000000 --- a/commands/help.js +++ /dev/null @@ -1,16 +0,0 @@ -const { SlashCommandBuilder } = require('@discordjs/builders'); -const { MessageEmbed } = require('discord.js'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('help') - .setDescription('Replies with a help message explaining what the bot can do'), - async execute(interaction) { - await interaction.deferReply(); - - const helpEmbed = new MessageEmbed() - .setDescription('AwesomeSciBo has migrated to using slash commands! You can take a look at the different commands by typing `/` and clicking on the AwesomeSciBo icon.') - .setColor('#ffffff'); - interaction.followUp({ embeds: [helpEmbed] }); - }, -}; diff --git a/commands/rounds.js b/commands/rounds.js deleted file mode 100644 index ba7e08b..0000000 --- a/commands/rounds.js +++ /dev/null @@ -1,113 +0,0 @@ -const { SlashCommandBuilder } = require('@discordjs/builders'); -const { MessageEmbed } = require('discord.js'); - -const axios = require('axios'); - -const { log } = require('../helpers/log'); -const generatedRound = require('../models/generateRound'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('rounds') - .setDescription('Commands regarding the generation of rounds') - .addSubcommand(subcommand => { - subcommand - .setName('generate') - .setDescription('Generates a round with randomized questions from https://scibowldb.com/'); - return subcommand; - }) - .addSubcommand(subcommand => { - subcommand - .setName('list') - .setDescription('Lists your 5 most recently generated rounds with links'); - return subcommand; - }) - .addSubcommand(subcommand => { - subcommand - .setName('hit') - .setDescription('Shows the total number of rounds hit as well as the number for the specific user'); - return subcommand; - }), - async execute(interaction) { - await interaction.deferReply(); - - const action = interaction.options.getSubcommand(); - if (action === 'generate') { - let i; - let finalizedHTML = '

ROUND GENERATED BY AWESOMESCIBO USING THE SCIBOWLDB API

'; - let tossup_question; - let question_category; - let tossup_format; - let tossup_answer; - let bonus_question; - let bonus_format; - let bonus_answer; - let htmlContent = ''; - await axios.post('https://scibowldb.com/api/questions', { categories: ['BIOLOGY', 'PHYSICS', 'CHEMISTRY', 'EARTH AND SPACE', 'ASTRONOMY', 'MATH'] }) - .then((response) => { - for (i = 1; i < 26; i++) { - const data = response.data.questions[Math.floor(Math.random() * response.data.questions.length)]; - tossup_question = data.tossup_question; - tossup_answer = data.tossup_answer; - question_category = data.category; - tossup_format = data.tossup_format; - bonus_question = data.bonus_question; - bonus_answer = data.bonus_answer; - bonus_format = data.bonus_format; - htmlContent = '

TOSS-UP

\n
' + `${i}) ${question_category}` + ' ' + `${tossup_format}` + ' ' + tossup_question + '

' + 'ANSWER: ' + tossup_answer + '
'; - htmlContent += '

BONUS

\n
' + `${i}) ${question_category}` + ' ' + `${bonus_format}` + ' ' + bonus_question + '

' + 'ANSWER: ' + bonus_answer + '



'; - htmlContent = htmlContent.replace(/\n/g, '
'); - finalizedHTML += htmlContent; - } - - const newGeneratedRound = new generatedRound({ - htmlContent: finalizedHTML, - requestedBy: interaction.user.id, - authorTag: interaction.user.tag, - timestamp: new Date().toISOString(), - }); - - newGeneratedRound.save((err, round) => { - if (err) { - log({ logger: 'rounds', content: `Saving round to DB failed: ${err}`, level: 'error' }); - return; - } - interaction.followUp(`Here's your round: https://api.adawesome.tech/round/${round._id.toString()}`, { ephemeral: true }); - }); - }); - } - else if (action === 'list') { - let roundsList = await generatedRound.find({ requestedBy: interaction.user.id }).sort({ timestamp: -1 }); - let finalMessage = ''; - if (!roundsList) { - interaction.followUp('You haven\'t requested any roundsList!'); - return; - } - - if (roundsList.length > 5) { - roundsList = roundsList.slice(0, 5); - } - - roundsList.forEach(async (item, index) => { - finalMessage += `${index + 1}. [${item.timestamp.split('T')[0]}](https://api.adawesome.tech/round/${item._id.toString()})\n`; - }); - - const roundsListEmbed = new MessageEmbed() - .setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL() }) - .setTitle(`Last 5 roundsList requested by ${interaction.user.tag}`) - .setDescription(finalMessage) - .setTimestamp(); - - interaction.followUp({ - embeds: [roundsListEmbed], - ephemeral: true, - }); - } - else if (action === 'hit') { - const totalCount = await generatedRound.countDocuments({}); - const userCount = await generatedRound.countDocuments({ requestedBy: interaction.user.id }); - - interaction.followUp(`Total Hits: ${totalCount}\nYour Hits: ${userCount}`); - } - }, -}; diff --git a/commands/top.js b/commands/top.js deleted file mode 100644 index cd0ada7..0000000 --- a/commands/top.js +++ /dev/null @@ -1,40 +0,0 @@ -const { SlashCommandBuilder } = require('@discordjs/builders'); -const { MessageEmbed } = require('discord.js'); - -const { log } = require('../helpers/log'); -const userScore = require('../models/userScore'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('top') - .setDescription('Lists top ten scores across servers (server specific leaderboard WIP)'), - async execute(interaction) { - await interaction.deferReply(); - - let messageContent = ''; - userScore - .find({}) - .sort({ score: -1 }) // Sort by descending order - .exec((err, obj) => { - if (err) { - log({ logger: 'top', content: `Getting top players failed: ${err}`, level: 'error' }); - console.log(err); - } - if (obj.length < 10) { - // Need at least 10 scores for top 10 - return interaction.followUp( - `There are only ${obj.length} users, we need at least 10!`, - ); - } - for (let i = 0; i < 10; i++) { - messageContent += `${i + 1}: <@${obj[i].authorID}>: ${obj[i].score}\n`; // Loop through each user and add their name and score to leaderboard content - } - const leaderboardEmbed = new MessageEmbed() - .setTitle('Top Ten!') - .setDescription(messageContent) - .setColor('#ffffff'); - - interaction.followUp({ embeds: [leaderboardEmbed] }); - }); - }, -}; diff --git a/commands/train.js b/commands/train.js deleted file mode 100644 index f93eae5..0000000 --- a/commands/train.js +++ /dev/null @@ -1,172 +0,0 @@ -const { SlashCommandBuilder } = require('@discordjs/builders'); -const { MessageEmbed } = require('discord.js'); - -const decode = require('html-entities').decode; -const axios = require('axios'); - -const userScore = require('../models/userScore'); - -const { log } = require('../helpers/log.js'); -const { updateScore } = require('../helpers/db.js'); - -module.exports = { - data: new SlashCommandBuilder() - .setName('train') - .setDescription('Sends a training question to be answered') - .addStringOption(option => { - option - .setName('subject') - .setDescription('Optional subject to be used as a filter') - .setRequired(false) - .addChoice('astro', 'astro') - .addChoice('bio', 'bio') - .addChoice('ess', 'ess') - .addChoice('chem', 'chem') - .addChoice('phys', 'phys') - .addChoice('math', 'math') - .addChoice('energy', 'energy') - .setRequired(false); - return option; - }), - async execute(interaction) { - await interaction.deferReply(); - - const subject = interaction.options.get('subject') ? interaction.options.get('subject').value : null; - const authorId = interaction.user.id; - let score; - userScore - .findOne({ authorID: authorId }) - .lean() - .then((obj, err) => { - if (!obj) { - score = 0; - } - else if (obj) { - score = obj.score; - } - else { - log({ logger: 'train', content: `Getting user score failed: ${err}`, level: 'error' }); - } - }); - - let categoryArray = []; - - switch (subject) { - case null: - categoryArray = ['BIOLOGY', 'PHYSICS', 'CHEMISTRY', 'EARTH AND SPACE', 'ASTRONOMY', 'MATH']; - break; - case 'astro': - case 'astronomy': - categoryArray = ['ASTRONOMY']; - break; - case 'bio': - case 'biology': - categoryArray = ['BIOLOGY']; - break; - case 'ess': - case 'earth science': - case 'es': - categoryArray = ['EARTH SCIENCE']; - break; - case 'chem': - case 'chemistry': - categoryArray = ['CHEMISTRY']; - break; - case 'phys': - case 'physics': - categoryArray = ['PHYSICS']; - break; - case 'math': - categoryArray = ['MATH']; - break; - case 'energy': - categoryArray = ['ENERGY']; - break; - default: - interaction.followUp( - new MessageEmbed() - .setDescription('<:red_x:816791117671825409> Not a valid subject!') - .setColor('#ffffff'), - ); - return; - } - - axios - .post('https://scibowldb.com/api/questions/random', { categories: categoryArray }) - .then((res) => { - const data = res.data.question; - const tossupQuestion = data.tossup_question; - const tossupAnswer = data.tossup_answer; - let answers = tossupAnswer.split(' (ACCEPT: '); - if (answers.length > 1) { - answers[1] = answers[1].slice(0, answers[1].length - 1); // If there are multiple elements, it means there was an 'accept' and therefore a trailing ')' which should be removed - answers = [answers[0], ...answers[1].split(new RegExp(' OR ', 'i'))]; // Use the first element plus the last element split by 'OR' case insensitive - } - interaction.followUp({ content: decode(tossupQuestion) + `\n\n||Source: ${data.uri}||` }) - .then(() => { - const messageFilter = m => m.author.id === interaction.user.id || m.author.id === interaction.client.user.id; - interaction.channel.awaitMessages({ - filter: messageFilter, - max: 1, - }) - .then(collected => { - const answerMsg = collected.first(); - - if (answerMsg.author.id === interaction.client.user.id) return; - - let predicted = null; - if (data.tossup_format === 'Multiple Choice') { - if (answerMsg.content.charAt(0).toLowerCase() === tossupAnswer.charAt(0).toLowerCase()) { - predicted = 'correct'; - } - else { - predicted = 'incorrect'; - } - } - else if (answerMsg.content.toLowerCase() === tossupAnswer.toLowerCase() || answers.includes(answerMsg.content.toUpperCase())) { - predicted = 'correct'; - } - else { - predicted = 'incorrect'; - } - - if (predicted === 'correct') { - updateScore(true, score, authorId).then((msgToReply) => - answerMsg.reply(msgToReply), - ); - } - else { - const overrideEmbed = new MessageEmbed() - .setAuthor({ name: answerMsg.author.tag, iconURL: answerMsg.author.displayAvatarURL() }) - .addField('Correct answer', `\`${tossupAnswer}\``) - .setDescription('It seems your answer was incorrect. Please react with <:override:955265585086857236> to override your answer if you think you got it right.') - .setColor('#ffffff') - .setTimestamp(); - answerMsg.channel.send({ - embeds: [overrideEmbed], - }) - .then(overrideMsg => { - overrideMsg.react('<:override:955265585086857236>'); - const filter = (reaction, user) => { - return ( - ['override'].includes(reaction.emoji.name) && - user.id === answerMsg.author.id - ); - }; - overrideMsg - .awaitReactions({ - filter: filter, - max: 1, - }) - .then(() => { - updateScore(true, score, authorId).then((msgToReply) => - answerMsg.reply(msgToReply), - ); - }).catch(err => log({ logger: 'train', content: `Failed to override score: ${err}`, level: 'error' })); - }).catch(err => log({ logger: 'train', content: `Failed to send override message: ${err}`, level: 'error' })); - } - }).catch(err => log({ logger: 'train', content: `${err}`, level: 'error' })); - }).catch(err => log({ logger: 'train', content: `${err}`, level: 'error' })); - }).catch(err => log({ logger: 'train', content: `${err}`, level: 'error' })); - }, -}; diff --git a/events/interactionCreate.js b/events/interactionCreate.js deleted file mode 100644 index 750fad0..0000000 --- a/events/interactionCreate.js +++ /dev/null @@ -1,21 +0,0 @@ -const { log } = require('../helpers/log'); - -module.exports = { - name: 'interactionCreate', - once: false, - async execute(interaction) { - const client = interaction.client; - if (!interaction.isCommand()) return; - - const command = client.commands.get(interaction.commandName); - if (!command) return; - - try { - await command.execute(interaction); - } - catch (error) { - log({ logger: 'interaction', content: `Interaction ${interaction.name} failed!`, level: 'error' }); - await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true }); - } - }, -}; diff --git a/events/messageCreate.js b/events/messageCreate.js deleted file mode 100644 index fe0232d..0000000 --- a/events/messageCreate.js +++ /dev/null @@ -1,35 +0,0 @@ -const axios = require('axios'); -const { MessageEmbed } = require('discord.js'); -const decode = require('html-entities').decode; - -const { testingGuild } = require('../helpers/env'); -module.exports = { - name: 'messageCreate', - once: false, - async execute(message) { - if (message.author.bot || message.guild.id != testingGuild) return; - - if (message.content.startsWith('!q')) { - const questionId = message.content.split(' ')[1]; - axios - .get(`https://scibowldb.com/api/questions/${questionId}`) - .then((res) => { - const data = res.data.question; - const tossupQuestion = data.tossup_question; - const tossupAnswer = data.tossup_answer; - let answers = tossupAnswer.split(' (ACCEPT: '); - if (answers.length > 1) { - answers[1] = answers[1].slice(0, answers[1].length - 1); // If there are multiple elements, it means there was an 'accept' and therefore a trailing ')' which should be removed - answers = [answers[0], ...answers[1].split(new RegExp(' OR ', 'i'))]; // Use the first element plus the last element split by 'OR' case insensitive - } - const dataEmbed = new MessageEmbed() - .setTitle('Data') - .setDescription(`\`\`\`json\n${JSON.stringify(data, null, 2)}\`\`\``); - message.reply({ - content: decode(tossupQuestion) + `\n\nAnswers: [${answers}]`, - embeds: [dataEmbed], - }); - }); - } - }, -}; diff --git a/events/ready.js b/events/ready.js deleted file mode 100644 index c9ecabe..0000000 --- a/events/ready.js +++ /dev/null @@ -1,16 +0,0 @@ -const db = require('../helpers/db'); -const { mongoUri } = require('../helpers/env'); -const { log } = require('../helpers/log'); - -module.exports = { - name: 'ready', - once: true, - async execute(client) { - await db.connect(mongoUri); - log({ logger: 'status', content: `Logged in as ${client.user.tag}!`, level: 'info' }); - client.user.setActivity( - 'for /help', - { type: 'WATCHING' }, - ); - }, -}; diff --git a/helpers/db.js b/helpers/db.js deleted file mode 100644 index e999dd4..0000000 --- a/helpers/db.js +++ /dev/null @@ -1,45 +0,0 @@ -const mongoose = require('mongoose'); - -const { log } = require('../helpers/log.js'); -const userScore = require('../models/userScore'); - -module.exports = { - async updateScore(isCorrect, score, authorId) { - if (!isCorrect) { - return `Nice try! Your score is still ${score}.`; - } - else { - score += 4; - if (score == 4) { - const newUserScore = new userScore({ - authorID: authorId, - score: score, - }); - newUserScore.save((err) => - err - ? console.log('Error creating new user for scoring') - : console.log('Sucessfully created user to score.'), - ); - } - else { - // TODO: Error handling - const doc = await userScore.findOne({ - authorID: authorId, - }); - doc.score = doc.score + 4; - doc.save(); - } - - return `Great job! Your score is now ${score}.`; - } - }, - async connect(mongoUri) { - mongoose - .connect(mongoUri, { - useUnifiedTopology: true, - useNewUrlParser: true, - }) - .then(() => log({ logger: 'db', content: `Connected to the database at ${mongoUri}!`, level: 'info' })) - .catch(err => log({ logger: 'db', content: `Failed to connect to the database at ${mongoUri}: ${err}`, level: 'fatal' })); - }, -}; diff --git a/helpers/env.js b/helpers/env.js deleted file mode 100644 index 69f0af6..0000000 --- a/helpers/env.js +++ /dev/null @@ -1,8 +0,0 @@ -require('dotenv').config(); - -module.exports = { - clientId: process.env.CLIENT_ID, - testingGuild: process.env.TESTING_GUILD, - token: process.env.TOKEN, - mongoUri: process.env.MONGO_URI, -}; diff --git a/helpers/log.js b/helpers/log.js deleted file mode 100644 index eeac9f1..0000000 --- a/helpers/log.js +++ /dev/null @@ -1,31 +0,0 @@ -const log4js = require('log4js'); - -module.exports = { - async log(config) { - const logger = log4js.getLogger(config.logger); - logger.level = 'debug'; - switch (config.level) { - case 'trace': - logger.trace(config.content); - break; - case 'debug': - logger.debug(config.content); - break; - case 'info': - logger.info(config.content); - break; - case 'warn': - logger.warn(config.content); - break; - case 'error': - logger.error(config.content); - break; - case 'fatal': - logger.fatal(config.content); - break; - default: - logger.debug(config.content); - break; - } - }, -}; diff --git a/index.js b/index.js deleted file mode 100755 index 74b6be1..0000000 --- a/index.js +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env node - -const fs = require('node:fs'); -const { Client, Collection, Intents } = require('discord.js'); -const { token } = require('./helpers/env'); -const { log } = require('./helpers/log'); - -const client = new Client({ - intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILD_MESSAGE_REACTIONS, Intents.FLAGS.DIRECT_MESSAGES, Intents.FLAGS.DIRECT_MESSAGE_REACTIONS], -}); - -client.commands = new Collection(); - -const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js')); -const eventFiles = fs.readdirSync('./events').filter(file => file.endsWith('.js')); - -for (const file of commandFiles) { - const command = require(`./commands/${file}`); - client.commands.set(command.data.name, command); - log({ logger: 'command', content: `Registered command ${file}!`, level: 'info' }); -} - -for (const file of eventFiles) { - const event = require(`./events/${file}`); - if (event.once) { - client.once(event.name, (...args) => event.execute(...args)); - } - else { - client.on(event.name, (...args) => event.execute(...args)); - } - log({ logger: 'event', content: `Registered event ${file}!`, level: 'info' }); -} - -client.login(token); diff --git a/package.json b/package.json index da30ddd..8bc8498 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ }, "devDependencies": { "eslint": "^8.7.0", - "nodemon": "^2.0.15" + "nodemon": "^2.0.15", + "typescript": "^4.6.2" }, "name": "awesomescibo", "version": "3.2.1", diff --git a/src/commands/about.ts b/src/commands/about.ts new file mode 100644 index 0000000..c70a44b --- /dev/null +++ b/src/commands/about.ts @@ -0,0 +1,77 @@ +import { SlashCommandBuilder } from '@discordjs/builders'; +import { MessageEmbed } from 'discord.js'; + +const gitlog = require('gitlog').default; + +import userScore from '../models/userScore'; + +export const data = new SlashCommandBuilder() + .setName('about') + .setDescription('Commands regarding the creation/development of the bot') + .addSubcommand(subcommand => { + subcommand + .setName('contributors') + .setDescription('Lists contributors to the AwesomeSciBo bot'); + return subcommand; + }) + .addSubcommand(subcommand => { + subcommand + .setName('changelog') + .setDescription('Lists the 5 most recent changes in a "git log" type format'); + return subcommand; + }) + .addSubcommand(subcommand => { + subcommand + .setName('bot') + .setDescription('Lists information about AwesomeSciBo'); + return subcommand; + }); + +export async function execute(interaction) { + await interaction.deferReply(); + + const client = interaction.client; + const action = interaction.options.getSubcommand(); + if (action === 'contributors') { + const contributorEmbed = new MessageEmbed().setTitle('Contributors') + .addField('Creator', '<@745063586422063214> [ADawesomeguy#3602]', true) + .addField('Contributors', '<@650525101048987649> [tEjAs#8127]\n<@426864344463048705> [tetrident#9396]', true) // Add more contributors here, first one is Abheek, second one is Tejas + .setTimestamp() + .setColor('#ffffff'); + + interaction.followUp({ embeds: [contributorEmbed] }); + } + else if (action === 'changelog') { + const gitRepoLocation = __dirname; + + const commits = gitlog({ + repo: gitRepoLocation, + number: 5, + fields: ['hash', 'abbrevHash', 'subject', 'authorName', 'authorDateRel'], + }); + + const changelogEmbed = new MessageEmbed() + .setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL() }) + .setTitle('Changelog') + .setColor('#ffffff') + .setTimestamp(); + + commits.forEach(commit => { + changelogEmbed.addField(commit.abbrevHash, `> \`Hash:\`${commit.hash}\n> \`Subject:\`${commit.subject}\n> \`Author:\`${commit.authorName}\n> \`Date:\`${commit.authorDateRel}\n> \`Link\`: [GitHub](https://github.com/ADawesomeguy/AwesomeSciBo/commit/${commit.hash})\n`); + }); + + interaction.followUp({ embeds: [changelogEmbed] }); + } + else if (action === 'bot') { + await client.guilds.fetch(); + const trainingDocuments = await userScore.countDocuments({}); + const aboutBotEmbed = new MessageEmbed() + .setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL() }) + .setTitle('About AwesomeSciBo') + .addField('Servers', `${client.guilds.cache.size}`, true) + .addField('Training Users', `${trainingDocuments}`, true) + .setTimestamp(); + + interaction.followUp({ embeds: [aboutBotEmbed] }); + } +} diff --git a/src/commands/help.ts b/src/commands/help.ts new file mode 100644 index 0000000..38d5887 --- /dev/null +++ b/src/commands/help.ts @@ -0,0 +1,15 @@ +import { SlashCommandBuilder } from '@discordjs/builders'; +import { MessageEmbed } from 'discord.js'; + +export const data = new SlashCommandBuilder() + .setName('help') + .setDescription('Replies with a help message explaining what the bot can do'); + +export async function execute(interaction) { + await interaction.deferReply(); + + const helpEmbed = new MessageEmbed() + .setDescription('AwesomeSciBo has migrated to using slash commands! You can take a look at the different commands by typing `/` and clicking on the AwesomeSciBo icon.') + .setColor('#ffffff'); + interaction.followUp({ embeds: [helpEmbed] }); +} \ No newline at end of file diff --git a/src/commands/rounds.ts b/src/commands/rounds.ts new file mode 100644 index 0000000..ec46b7b --- /dev/null +++ b/src/commands/rounds.ts @@ -0,0 +1,112 @@ +import { SlashCommandBuilder } from '@discordjs/builders'; +import { MessageEmbed } from 'discord.js'; + +import axios from 'axios'; + +import log from '../helpers/log'; +import generatedRound from '../models/generateRound'; + +export const data = new SlashCommandBuilder() + .setName('rounds') + .setDescription('Commands regarding the generation of rounds') + .addSubcommand(subcommand => { + subcommand + .setName('generate') + .setDescription('Generates a round with randomized questions from https://scibowldb.com/'); + return subcommand; + }) + .addSubcommand(subcommand => { + subcommand + .setName('list') + .setDescription('Lists your 5 most recently generated rounds with links'); + return subcommand; + }) + .addSubcommand(subcommand => { + subcommand + .setName('hit') + .setDescription('Shows the total number of rounds hit as well as the number for the specific user'); + return subcommand; + }); + +export async function execute(interaction) { + await interaction.deferReply(); + + const action = interaction.options.getSubcommand(); + if (action === 'generate') { + let i; + let finalizedHTML = '

ROUND GENERATED BY AWESOMESCIBO USING THE SCIBOWLDB API

'; + let tossup_question; + let question_category; + let tossup_format; + let tossup_answer; + let bonus_question; + let bonus_format; + let bonus_answer; + let htmlContent = ''; + await axios.post('https://scibowldb.com/api/questions', { categories: ['BIOLOGY', 'PHYSICS', 'CHEMISTRY', 'EARTH AND SPACE', 'ASTRONOMY', 'MATH'] }) + .then((response) => { + for (i = 1; i < 26; i++) { + const data = response.data.questions[Math.floor(Math.random() * response.data.questions.length)]; + tossup_question = data.tossup_question; + tossup_answer = data.tossup_answer; + question_category = data.category; + tossup_format = data.tossup_format; + bonus_question = data.bonus_question; + bonus_answer = data.bonus_answer; + bonus_format = data.bonus_format; + htmlContent = '

TOSS-UP

\n
' + `${i}) ${question_category}` + ' ' + `${tossup_format}` + ' ' + tossup_question + '

' + 'ANSWER: ' + tossup_answer + '
'; + htmlContent += '

BONUS

\n
' + `${i}) ${question_category}` + ' ' + `${bonus_format}` + ' ' + bonus_question + '

' + 'ANSWER: ' + bonus_answer + '



'; + htmlContent = htmlContent.replace(/\n/g, '
'); + finalizedHTML += htmlContent; + } + + const newGeneratedRound = new generatedRound({ + htmlContent: finalizedHTML, + requestedBy: interaction.user.id, + authorTag: interaction.user.tag, + timestamp: new Date().toISOString(), + }); + + newGeneratedRound.save((err, round) => { + if (err) { + log({ logger: 'rounds', content: `Saving round to DB failed: ${err}`, level: 'error' }); + return; + } + interaction.followUp(`Here's your round: https://api.adawesome.tech/round/${round._id.toString()}`, { ephemeral: true }); + }); + }); + } + else if (action === 'list') { + let roundsList = await generatedRound.find({ requestedBy: interaction.user.id }).sort({ timestamp: -1 }); + let finalMessage = ''; + if (!roundsList) { + interaction.followUp('You haven\'t requested any roundsList!'); + return; + } + + if (roundsList.length > 5) { + roundsList = roundsList.slice(0, 5); + } + + roundsList.forEach(async (item, index) => { + finalMessage += `${index + 1}. [${item.timestamp.split('T')[0]}](https://api.adawesome.tech/round/${item._id.toString()})\n`; + }); + + const roundsListEmbed = new MessageEmbed() + .setAuthor({ name: interaction.user.tag, iconURL: interaction.user.displayAvatarURL() }) + .setTitle(`Last 5 roundsList requested by ${interaction.user.tag}`) + .setDescription(finalMessage) + .setTimestamp(); + + interaction.followUp({ + embeds: [roundsListEmbed], + ephemeral: true, + }); + } + else if (action === 'hit') { + const totalCount = await generatedRound.countDocuments({}); + const userCount = await generatedRound.countDocuments({ requestedBy: interaction.user.id }); + + interaction.followUp(`Total Hits: ${totalCount}\nYour Hits: ${userCount}`); + } +} \ No newline at end of file diff --git a/src/commands/top.ts b/src/commands/top.ts new file mode 100644 index 0000000..c1c12dc --- /dev/null +++ b/src/commands/top.ts @@ -0,0 +1,39 @@ +import { SlashCommandBuilder } from '@discordjs/builders'; +import { MessageEmbed } from 'discord.js'; + +import log from '../helpers/log'; +import userScore from '../models/userScore'; + +export const data = new SlashCommandBuilder() + .setName('top') + .setDescription('Lists top ten scores across servers (server specific leaderboard WIP)'); + +export async function execute(interaction) { + await interaction.deferReply(); + + let messageContent = ''; + userScore + .find({}) + .sort({ score: -1 }) // Sort by descending order + .exec((err, obj) => { + if (err) { + log({ logger: 'top', content: `Getting top players failed: ${err}`, level: 'error' }); + console.log(err); + } + if (obj.length < 10) { + // Need at least 10 scores for top 10 + return interaction.followUp( + `There are only ${obj.length} users, we need at least 10!`, + ); + } + for (let i = 0; i < 10; i++) { + messageContent += `${i + 1}: <@${obj[i].authorID}>: ${obj[i].score}\n`; // Loop through each user and add their name and score to leaderboard content + } + const leaderboardEmbed = new MessageEmbed() + .setTitle('Top Ten!') + .setDescription(messageContent) + .setColor('#ffffff'); + + interaction.followUp({ embeds: [leaderboardEmbed] }); + }); +} \ No newline at end of file diff --git a/src/commands/train.ts b/src/commands/train.ts new file mode 100644 index 0000000..46b7ddd --- /dev/null +++ b/src/commands/train.ts @@ -0,0 +1,171 @@ +import { SlashCommandBuilder } from '@discordjs/builders'; +import { MessageEmbed } from 'discord.js'; + +import { decode } from 'html-entities'; +import axios from 'axios'; + +import userScore from '../models/userScore'; + +import log from '../helpers/log.js'; +import { updateScore } from '../helpers/db.js'; + +export const data = new SlashCommandBuilder() + .setName('train') + .setDescription('Sends a training question to be answered') + .addStringOption(option => { + option + .setName('subject') + .setDescription('Optional subject to be used as a filter') + .setRequired(false) + .addChoice('astro', 'astro') + .addChoice('bio', 'bio') + .addChoice('ess', 'ess') + .addChoice('chem', 'chem') + .addChoice('phys', 'phys') + .addChoice('math', 'math') + .addChoice('energy', 'energy') + .setRequired(false); + return option; + }); + +export async function execute(interaction) { + await interaction.deferReply(); + + const subject = interaction.options.get('subject') ? interaction.options.get('subject').value : null; + const authorId = interaction.user.id; + let score; + userScore + .findOne({ authorID: authorId }) + .lean() + .then((obj, err) => { + if (!obj) { + score = 0; + } + else if (obj) { + score = obj.score; + } + else { + log({ logger: 'train', content: `Getting user score failed: ${err}`, level: 'error' }); + } + }); + + let categoryArray : string[] = []; + + switch (subject) { + case null: + categoryArray = ['BIOLOGY', 'PHYSICS', 'CHEMISTRY', 'EARTH AND SPACE', 'ASTRONOMY', 'MATH']; + break; + case 'astro': + case 'astronomy': + categoryArray = ['ASTRONOMY']; + break; + case 'bio': + case 'biology': + categoryArray = ['BIOLOGY']; + break; + case 'ess': + case 'earth science': + case 'es': + categoryArray = ['EARTH SCIENCE']; + break; + case 'chem': + case 'chemistry': + categoryArray = ['CHEMISTRY']; + break; + case 'phys': + case 'physics': + categoryArray = ['PHYSICS']; + break; + case 'math': + categoryArray = ['MATH']; + break; + case 'energy': + categoryArray = ['ENERGY']; + break; + default: + interaction.followUp( + new MessageEmbed() + .setDescription('<:red_x:816791117671825409> Not a valid subject!') + .setColor('#ffffff'), + ); + return; + } + + axios + .post('https://scibowldb.com/api/questions/random', { categories: categoryArray }) + .then((res) => { + const data = res.data.question; + const tossupQuestion = data.tossup_question; + const tossupAnswer = data.tossup_answer; + let answers = tossupAnswer.split(' (ACCEPT: '); + if (answers.length > 1) { + answers[1] = answers[1].slice(0, answers[1].length - 1); // If there are multiple elements, it means there was an 'accept' and therefore a trailing ')' which should be removed + answers = [answers[0], ...answers[1].split(new RegExp(' OR ', 'i'))]; // Use the first element plus the last element split by 'OR' case insensitive + } + interaction.followUp({ content: decode(tossupQuestion) + `\n\n||Source: ${data.uri}||` }) + .then(() => { + const messageFilter = m => m.author.id === interaction.user.id || m.author.id === interaction.client.user.id; + interaction.channel.awaitMessages({ + filter: messageFilter, + max: 1, + }) + .then(collected => { + const answerMsg = collected.first(); + + if (answerMsg.author.id === interaction.client.user.id) return; + + let predicted = ''; + if (data.tossup_format === 'Multiple Choice') { + if (answerMsg.content.charAt(0).toLowerCase() === tossupAnswer.charAt(0).toLowerCase()) { + predicted = 'correct'; + } + else { + predicted = 'incorrect'; + } + } + else if (answerMsg.content.toLowerCase() === tossupAnswer.toLowerCase() || answers.includes(answerMsg.content.toUpperCase())) { + predicted = 'correct'; + } + else { + predicted = 'incorrect'; + } + + if (predicted === 'correct') { + updateScore(true, score, authorId).then((msgToReply) => + answerMsg.reply(msgToReply), + ); + } + else { + const overrideEmbed = new MessageEmbed() + .setAuthor({ name: answerMsg.author.tag, iconURL: answerMsg.author.displayAvatarURL() }) + .addField('Correct answer', `\`${tossupAnswer}\``) + .setDescription('It seems your answer was incorrect. Please react with <:override:955265585086857236> to override your answer if you think you got it right.') + .setColor('#ffffff') + .setTimestamp(); + answerMsg.channel.send({ + embeds: [overrideEmbed], + }) + .then(overrideMsg => { + overrideMsg.react('<:override:955265585086857236>'); + const filter = (reaction, user) => { + return ( + ['override'].includes(reaction.emoji.name) && + user.id === answerMsg.author.id + ); + }; + overrideMsg + .awaitReactions({ + filter: filter, + max: 1, + }) + .then(() => { + updateScore(true, score, authorId).then((msgToReply) => + answerMsg.reply(msgToReply), + ); + }).catch(err => log({ logger: 'train', content: `Failed to override score: ${err}`, level: 'error' })); + }).catch(err => log({ logger: 'train', content: `Failed to send override message: ${err}`, level: 'error' })); + } + }).catch(err => log({ logger: 'train', content: `${err}`, level: 'error' })); + }).catch(err => log({ logger: 'train', content: `${err}`, level: 'error' })); + }).catch(err => log({ logger: 'train', content: `${err}`, level: 'error' })); +} \ No newline at end of file diff --git a/deploy-commands.js b/src/deploy-commands.ts similarity index 56% rename from deploy-commands.js rename to src/deploy-commands.ts index 0b7b816..6e3cb3c 100755 --- a/deploy-commands.js +++ b/src/deploy-commands.ts @@ -1,16 +1,18 @@ #!/usr/bin/env node -const fs = require('node:fs'); -const { REST } = require('@discordjs/rest'); -const { Routes } = require('discord-api-types/v9'); -const { clientId, token } = require('./helpers/env'); +import fs from 'node:fs'; +import { REST } from '@discordjs/rest'; +import { Routes } from 'discord-api-types/v9'; +import { clientId, token } from './helpers/env'; -const commands = []; +const commands : any[] = []; const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js')); for (const file of commandFiles) { - const command = require(`./commands/${file}`); - commands.push(command.data.toJSON()); + import(`./commands/${file}`) + .then(command => { + commands.push(command.data.toJSON()); + }) } const rest = new REST({ version: '9' }).setToken(token); diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts new file mode 100644 index 0000000..8cdd4b0 --- /dev/null +++ b/src/events/interactionCreate.ts @@ -0,0 +1,21 @@ +import log from '../helpers/log'; + +export const name = 'interactionCreate'; + +export const once = false; + +export async function execute(interaction) { + const client = interaction.client; + if (!interaction.isCommand()) return; + + const command = client.commands.get(interaction.commandName); + if (!command) return; + + try { + await command.execute(interaction); + } + catch (error) { + log({ logger: 'interaction', content: `Interaction ${interaction.name} failed!`, level: 'error' }); + await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true }); + } +} \ No newline at end of file diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts new file mode 100644 index 0000000..c4232b9 --- /dev/null +++ b/src/events/messageCreate.ts @@ -0,0 +1,36 @@ +import axios from 'axios'; +import { MessageEmbed } from 'discord.js'; +const decode = require('html-entities').decode; + +import { testingGuild } from '../helpers/env'; + +export const name = 'messageCreate'; + +export const once = false; + +export async function execute(message) { + if (message.author.bot || message.guild.id != testingGuild) return; + + if (message.content.startsWith('!q')) { + const questionId = message.content.split(' ')[1]; + axios + .get(`https://scibowldb.com/api/questions/${questionId}`) + .then((res) => { + const data = res.data.question; + const tossupQuestion = data.tossup_question; + const tossupAnswer = data.tossup_answer; + let answers = tossupAnswer.split(' (ACCEPT: '); + if (answers.length > 1) { + answers[1] = answers[1].slice(0, answers[1].length - 1); // If there are multiple elements, it means there was an 'accept' and therefore a trailing ')' which should be removed + answers = [answers[0], ...answers[1].split(new RegExp(' OR ', 'i'))]; // Use the first element plus the last element split by 'OR' case insensitive + } + const dataEmbed = new MessageEmbed() + .setTitle('Data') + .setDescription(`\`\`\`json\n${JSON.stringify(data, null, 2)}\`\`\``); + message.reply({ + content: decode(tossupQuestion) + `\n\nAnswers: [${answers}]`, + embeds: [dataEmbed], + }); + }); + } +} \ No newline at end of file diff --git a/src/events/ready.ts b/src/events/ready.ts new file mode 100644 index 0000000..f816b31 --- /dev/null +++ b/src/events/ready.ts @@ -0,0 +1,16 @@ +import * as db from '../helpers/db'; +import { mongoUri } from '../helpers/env'; +import log from '../helpers/log'; + +export const name = 'ready'; + +export const once = true; + +export async function execute(client) { + await db.connect(mongoUri); + log({ logger: 'status', content: `Logged in as ${client.user.tag}!`, level: 'info' }); + client.user.setActivity( + 'for /help', + { type: 'WATCHING' }, + ); +} diff --git a/src/helpers/db.ts b/src/helpers/db.ts new file mode 100644 index 0000000..afd7952 --- /dev/null +++ b/src/helpers/db.ts @@ -0,0 +1,44 @@ +import mongoose from 'mongoose'; + +import log from '../helpers/log'; +import userScore from '../models/userScore'; + +export async function updateScore(isCorrect, score, authorId) { + if (!isCorrect) { + return `Nice try! Your score is still ${score}.`; + } + else { + score += 4; + if (score == 4) { + const newUserScore = new userScore({ + authorID: authorId, + score: score, + }); + newUserScore.save((err) => + err + ? console.log('Error creating new user for scoring') + : console.log('Sucessfully created user to score.'), + ); + } + else { + // TODO: Error handling + const doc = await userScore.findOne({ + authorID: authorId, + }); + doc.score = doc.score + 4; + doc.save(); + } + + return `Great job! Your score is now ${score}.`; + } +} + +export async function connect(mongoUri) { + mongoose + .connect(mongoUri, { + useUnifiedTopology: true, + useNewUrlParser: true, + }) + .then(() => log({ logger: 'db', content: `Connected to the database at ${mongoUri}!`, level: 'info' })) + .catch(err => log({ logger: 'db', content: `Failed to connect to the database at ${mongoUri}: ${err}`, level: 'fatal' })); +} \ No newline at end of file diff --git a/src/helpers/env.ts b/src/helpers/env.ts new file mode 100644 index 0000000..22b1b3d --- /dev/null +++ b/src/helpers/env.ts @@ -0,0 +1,6 @@ +import 'dotenv/config'; + +export const clientId : string = process.env.CLIENT_ID!; +export const testingGuild : string = process.env.TESTING_GUILD!; +export const token : string = process.env.TOKEN!; +export const mongoUri : string = process.env.MONGO_URI!; \ No newline at end of file diff --git a/src/helpers/log.ts b/src/helpers/log.ts new file mode 100644 index 0000000..7e092d1 --- /dev/null +++ b/src/helpers/log.ts @@ -0,0 +1,29 @@ +import log4js from 'log4js'; + +export default function (config) { + const logger = log4js.getLogger(config.logger); + logger.level = 'debug'; + switch (config.level) { + case 'trace': + logger.trace(config.content); + break; + case 'debug': + logger.debug(config.content); + break; + case 'info': + logger.info(config.content); + break; + case 'warn': + logger.warn(config.content); + break; + case 'error': + logger.error(config.content); + break; + case 'fatal': + logger.fatal(config.content); + break; + default: + logger.debug(config.content); + break; + } +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100755 index 0000000..1249a6e --- /dev/null +++ b/src/index.ts @@ -0,0 +1,38 @@ +#!/usr/bin/env node + +import fs from 'node:fs'; +import { Client, Collection, Intents } from 'discord.js'; +import { token } from './helpers/env'; +import log from './helpers/log'; + +const client = new Client({ + intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILD_MESSAGE_REACTIONS, Intents.FLAGS.DIRECT_MESSAGES, Intents.FLAGS.DIRECT_MESSAGE_REACTIONS], +}); + +client['commands'] = new Collection(); + +const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js')); +const eventFiles = fs.readdirSync('./events').filter(file => file.endsWith('.js')); + +for (const file of commandFiles) { + import(`./commands/${file}`) + .then(command => { + client['commands'].set(command.data.name, command); + log({ logger: 'command', content: `Registered command ${file}!`, level: 'info' }); + }) +} + +for (const file of eventFiles) { + import(`./events/${file}`) + .then(event => { + if (event.once) { + client.once(event.name, (...args) => event.execute(...args)); + } + else { + client.on(event.name, (...args) => event.execute(...args)); + } + log({ logger: 'event', content: `Registered event ${file}!`, level: 'info' }); + }) +} + +client.login(token); diff --git a/models/generateRound.js b/src/models/generateRound.ts similarity index 70% rename from models/generateRound.js rename to src/models/generateRound.ts index 48eb765..1cc3611 100644 --- a/models/generateRound.js +++ b/src/models/generateRound.ts @@ -1,4 +1,4 @@ -const mongoose = require('mongoose'); +import mongoose from 'mongoose'; const generatedRoundSchema = new mongoose.Schema({ htmlContent: { @@ -19,4 +19,4 @@ const generatedRoundSchema = new mongoose.Schema({ }, }); -module.exports = mongoose.model('GeneratedRounds', generatedRoundSchema); +export default mongoose.model('GeneratedRounds', generatedRoundSchema); diff --git a/models/userScore.js b/src/models/userScore.ts similarity index 59% rename from models/userScore.js rename to src/models/userScore.ts index 5c069ff..3ef9a9a 100644 --- a/models/userScore.js +++ b/src/models/userScore.ts @@ -1,4 +1,4 @@ -const mongoose = require('mongoose'); +import mongoose from 'mongoose'; const userScoreSchema = new mongoose.Schema({ authorID: { @@ -11,4 +11,4 @@ const userScoreSchema = new mongoose.Schema({ }, }); -module.exports = mongoose.model('UserScore', userScoreSchema); +export default mongoose.model('UserScore', userScoreSchema); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..fb4c0b6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,101 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Projects */ + // "incremental": true, /* Enable incremental compilation */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ + // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "resolveJsonModule": true, /* Enable importing .json files */ + // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./built", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": false, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/yarn.lock b/yarn.lock index 643b629..dbb899a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1580,6 +1580,11 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typescript@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.2.tgz#fe12d2727b708f4eef40f51598b3398baa9611d4" + integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg== + undefsafe@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" From 1fac256079b60e5142571aaabec8abe2b87639e3 Mon Sep 17 00:00:00 2001 From: Abheek Dhawan Date: Mon, 21 Mar 2022 02:54:46 -0500 Subject: [PATCH 2/3] Fix module declaration format --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index fb4c0b6..ec2ede4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,7 +24,7 @@ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "es2022", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ From 44dd742575d73dc37ba90478ddaad36f48554e58 Mon Sep 17 00:00:00 2001 From: Abheek Dhawan Date: Mon, 21 Mar 2022 03:09:10 -0500 Subject: [PATCH 3/3] Fix reimplement ESLint for TS and fix errors --- .eslintrc.json | 12 +- package.json | 4 +- src/commands/about.ts | 2 +- src/commands/rounds.ts | 16 +- src/commands/train.ts | 10 +- src/deploy-commands.ts | 2 +- src/events/messageCreate.ts | 2 +- src/helpers/log.ts | 2 +- src/index.ts | 4 +- tsconfig.json | 2 +- yarn.lock | 291 ++++++++++++++++++++++++++++++------ 11 files changed, 278 insertions(+), 69 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 8804aa8..b46b74b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,12 +1,16 @@ { - "extends": "eslint:recommended", + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "plugins": [ + "@typescript-eslint" + ], + "parser": "@typescript-eslint/parser", "env": { "node": true, "es6": true }, - "parserOptions": { - "ecmaVersion": 2021 - }, "rules": { "arrow-spacing": ["warn", { "before": true, "after": true }], "brace-style": ["error", "stroustrup", { "allowSingleLine": true }], diff --git a/package.json b/package.json index 8bc8498..0c2ce11 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,9 @@ "mongoose": "^5.12.5" }, "devDependencies": { - "eslint": "^8.7.0", + "@typescript-eslint/eslint-plugin": "^5.15.0", + "@typescript-eslint/parser": "^5.15.0", + "eslint": "^8.11.0", "nodemon": "^2.0.15", "typescript": "^4.6.2" }, diff --git a/src/commands/about.ts b/src/commands/about.ts index c70a44b..c990ad0 100644 --- a/src/commands/about.ts +++ b/src/commands/about.ts @@ -1,7 +1,7 @@ import { SlashCommandBuilder } from '@discordjs/builders'; import { MessageEmbed } from 'discord.js'; -const gitlog = require('gitlog').default; +import gitlog from 'gitlog'; import userScore from '../models/userScore'; diff --git a/src/commands/rounds.ts b/src/commands/rounds.ts index ec46b7b..4301e4e 100644 --- a/src/commands/rounds.ts +++ b/src/commands/rounds.ts @@ -46,14 +46,14 @@ export async function execute(interaction) { await axios.post('https://scibowldb.com/api/questions', { categories: ['BIOLOGY', 'PHYSICS', 'CHEMISTRY', 'EARTH AND SPACE', 'ASTRONOMY', 'MATH'] }) .then((response) => { for (i = 1; i < 26; i++) { - const data = response.data.questions[Math.floor(Math.random() * response.data.questions.length)]; - tossup_question = data.tossup_question; - tossup_answer = data.tossup_answer; - question_category = data.category; - tossup_format = data.tossup_format; - bonus_question = data.bonus_question; - bonus_answer = data.bonus_answer; - bonus_format = data.bonus_format; + const questionData = response.data.questions[Math.floor(Math.random() * response.data.questions.length)]; + tossup_question = questionData.tossup_question; + tossup_answer = questionData.tossup_answer; + question_category = questionData.category; + tossup_format = questionData.tossup_format; + bonus_question = questionData.bonus_question; + bonus_answer = questionData.bonus_answer; + bonus_format = questionData.bonus_format; htmlContent = '

TOSS-UP

\n
' + `${i}) ${question_category}` + ' ' + `${tossup_format}` + ' ' + tossup_question + '

' + 'ANSWER: ' + tossup_answer + '
'; htmlContent += '

BONUS

\n
' + `${i}) ${question_category}` + ' ' + `${bonus_format}` + ' ' + bonus_question + '

' + 'ANSWER: ' + bonus_answer + '



'; htmlContent = htmlContent.replace(/\n/g, '
'); diff --git a/src/commands/train.ts b/src/commands/train.ts index 46b7ddd..08719bb 100644 --- a/src/commands/train.ts +++ b/src/commands/train.ts @@ -94,15 +94,15 @@ export async function execute(interaction) { axios .post('https://scibowldb.com/api/questions/random', { categories: categoryArray }) .then((res) => { - const data = res.data.question; - const tossupQuestion = data.tossup_question; - const tossupAnswer = data.tossup_answer; + const questionData = res.data.question; + const tossupQuestion = questionData.tossup_question; + const tossupAnswer = questionData.tossup_answer; let answers = tossupAnswer.split(' (ACCEPT: '); if (answers.length > 1) { answers[1] = answers[1].slice(0, answers[1].length - 1); // If there are multiple elements, it means there was an 'accept' and therefore a trailing ')' which should be removed answers = [answers[0], ...answers[1].split(new RegExp(' OR ', 'i'))]; // Use the first element plus the last element split by 'OR' case insensitive } - interaction.followUp({ content: decode(tossupQuestion) + `\n\n||Source: ${data.uri}||` }) + interaction.followUp({ content: decode(tossupQuestion) + `\n\n||Source: ${questionData.uri}||` }) .then(() => { const messageFilter = m => m.author.id === interaction.user.id || m.author.id === interaction.client.user.id; interaction.channel.awaitMessages({ @@ -115,7 +115,7 @@ export async function execute(interaction) { if (answerMsg.author.id === interaction.client.user.id) return; let predicted = ''; - if (data.tossup_format === 'Multiple Choice') { + if (questionData.tossup_format === 'Multiple Choice') { if (answerMsg.content.charAt(0).toLowerCase() === tossupAnswer.charAt(0).toLowerCase()) { predicted = 'correct'; } diff --git a/src/deploy-commands.ts b/src/deploy-commands.ts index 6e3cb3c..359ac5c 100755 --- a/src/deploy-commands.ts +++ b/src/deploy-commands.ts @@ -12,7 +12,7 @@ for (const file of commandFiles) { import(`./commands/${file}`) .then(command => { commands.push(command.data.toJSON()); - }) + }); } const rest = new REST({ version: '9' }).setToken(token); diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index c4232b9..3898e04 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -1,6 +1,6 @@ import axios from 'axios'; import { MessageEmbed } from 'discord.js'; -const decode = require('html-entities').decode; +import { decode } from 'html-entities'; import { testingGuild } from '../helpers/env'; diff --git a/src/helpers/log.ts b/src/helpers/log.ts index 7e092d1..07995e4 100644 --- a/src/helpers/log.ts +++ b/src/helpers/log.ts @@ -1,6 +1,6 @@ import log4js from 'log4js'; -export default function (config) { +export default function(config) { const logger = log4js.getLogger(config.logger); logger.level = 'debug'; switch (config.level) { diff --git a/src/index.ts b/src/index.ts index 1249a6e..0f17f45 100755 --- a/src/index.ts +++ b/src/index.ts @@ -19,7 +19,7 @@ for (const file of commandFiles) { .then(command => { client['commands'].set(command.data.name, command); log({ logger: 'command', content: `Registered command ${file}!`, level: 'info' }); - }) + }); } for (const file of eventFiles) { @@ -32,7 +32,7 @@ for (const file of eventFiles) { client.on(event.name, (...args) => event.execute(...args)); } log({ logger: 'event', content: `Registered event ${file}!`, level: 'info' }); - }) + }); } client.login(token); diff --git a/tsconfig.json b/tsconfig.json index ec2ede4..fb4c0b6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,7 +24,7 @@ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ /* Modules */ - "module": "es2022", /* Specify what module code is generated. */ + "module": "commonjs", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ diff --git a/yarn.lock b/yarn.lock index dbb899a..3fa871b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -31,16 +31,16 @@ node-fetch "^2.6.5" tslib "^2.3.1" -"@eslint/eslintrc@^1.0.5": - version "1.0.5" - resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz" - integrity sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ== +"@eslint/eslintrc@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.1.tgz#8b5e1c49f4077235516bc9ec7d41378c0f69b8c6" + integrity sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.2.0" + espree "^9.3.1" globals "^13.9.0" - ignore "^4.0.6" + ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.0.4" @@ -60,6 +60,27 @@ resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + "@sapphire/async-queue@^1.1.9": version "1.1.9" resolved "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.9.tgz" @@ -101,6 +122,11 @@ dependencies: "@types/node" "*" +"@types/json-schema@^7.0.9": + version "7.0.10" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.10.tgz#9b05b7896166cd00e9cbd59864853abf65d9ac23" + integrity sha512-BLO9bBq59vW3fxCpD4o0N4U+DXsvwvIcl+jofw0frQo/GrBFC+/jRZj1E7kgp6dvTyNmA4y6JCV5Id/r3mNP5A== + "@types/mongodb@^3.5.27": version "3.6.20" resolved "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz" @@ -129,6 +155,86 @@ dependencies: "@types/node" "*" +"@typescript-eslint/eslint-plugin@^5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.15.0.tgz#c28ef7f2e688066db0b6a9d95fb74185c114fb9a" + integrity sha512-u6Db5JfF0Esn3tiAKELvoU5TpXVSkOpZ78cEGn/wXtT2RVqs2vkt4ge6N8cRCyw7YVKhmmLDbwI2pg92mlv7cA== + dependencies: + "@typescript-eslint/scope-manager" "5.15.0" + "@typescript-eslint/type-utils" "5.15.0" + "@typescript-eslint/utils" "5.15.0" + debug "^4.3.2" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.2.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.15.0.tgz#95f603f8fe6eca7952a99bfeef9b85992972e728" + integrity sha512-NGAYP/+RDM2sVfmKiKOCgJYPstAO40vPAgACoWPO/+yoYKSgAXIFaBKsV8P0Cc7fwKgvj27SjRNX4L7f4/jCKQ== + dependencies: + "@typescript-eslint/scope-manager" "5.15.0" + "@typescript-eslint/types" "5.15.0" + "@typescript-eslint/typescript-estree" "5.15.0" + debug "^4.3.2" + +"@typescript-eslint/scope-manager@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.15.0.tgz#d97afab5e0abf4018d1289bd711be21676cdd0ee" + integrity sha512-EFiZcSKrHh4kWk0pZaa+YNJosvKE50EnmN4IfgjkA3bTHElPtYcd2U37QQkNTqwMCS7LXeDeZzEqnsOH8chjSg== + dependencies: + "@typescript-eslint/types" "5.15.0" + "@typescript-eslint/visitor-keys" "5.15.0" + +"@typescript-eslint/type-utils@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.15.0.tgz#d2c02eb2bdf54d0a645ba3a173ceda78346cf248" + integrity sha512-KGeDoEQ7gHieLydujGEFLyLofipe9PIzfvA/41urz4hv+xVxPEbmMQonKSynZ0Ks2xDhJQ4VYjB3DnRiywvKDA== + dependencies: + "@typescript-eslint/utils" "5.15.0" + debug "^4.3.2" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.15.0.tgz#c7bdd103843b1abae97b5518219d3e2a0d79a501" + integrity sha512-yEiTN4MDy23vvsIksrShjNwQl2vl6kJeG9YkVJXjXZnkJElzVK8nfPsWKYxcsGWG8GhurYXP4/KGj3aZAxbeOA== + +"@typescript-eslint/typescript-estree@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.15.0.tgz#81513a742a9c657587ad1ddbca88e76c6efb0aac" + integrity sha512-Hb0e3dGc35b75xLzixM3cSbG1sSbrTBQDfIScqdyvrfJZVEi4XWAT+UL/HMxEdrJNB8Yk28SKxPLtAhfCbBInA== + dependencies: + "@typescript-eslint/types" "5.15.0" + "@typescript-eslint/visitor-keys" "5.15.0" + debug "^4.3.2" + globby "^11.0.4" + is-glob "^4.0.3" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.15.0.tgz#468510a0974d3ced8342f37e6c662778c277f136" + integrity sha512-081rWu2IPKOgTOhHUk/QfxuFog8m4wxW43sXNOMSCdh578tGJ1PAaWPsj42LOa7pguh173tNlMigsbrHvh/mtA== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.15.0" + "@typescript-eslint/types" "5.15.0" + "@typescript-eslint/typescript-estree" "5.15.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/visitor-keys@5.15.0": + version "5.15.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.15.0.tgz#5669739fbf516df060f978be6a6dce75855a8027" + integrity sha512-+vX5FKtgvyHbmIJdxMJ2jKm9z2BIlXJiuewI8dsDYMp5LzPUcuTT78Ya5iwvQg3VqSVdmxyM8Anj1Jeq7733ZQ== + dependencies: + "@typescript-eslint/types" "5.15.0" + eslint-visitor-keys "^3.0.0" + abbrev@1: version "1.1.1" resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" @@ -186,6 +292,11 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" @@ -248,7 +359,7 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@~3.0.2: +braces@^3.0.1, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -451,6 +562,13 @@ denque@^1.4.1: resolved "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz" integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + discord-api-types@^0.26.0, discord-api-types@^0.26.1: version "0.26.1" resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.26.1.tgz#726f766ddc37d60da95740991d22cb6ef2ed787b" @@ -517,10 +635,18 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-scope@^7.1.0: - version "7.1.0" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz" - integrity sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg== +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" @@ -537,17 +663,17 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz" - integrity sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ== +eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^8.7.0: - version "8.7.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-8.7.0.tgz" - integrity sha512-ifHYzkBGrzS2iDU7KjhCAVMGCvF6M3Xfs8X8b37cgrUlDt6bWRTpRh6T/gtSXv1HJ/BUGgmjvNvOEGu85Iif7w== +eslint@^8.11.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.11.0.tgz#88b91cfba1356fc10bb9eb592958457dfe09fb37" + integrity sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA== dependencies: - "@eslint/eslintrc" "^1.0.5" + "@eslint/eslintrc" "^1.2.1" "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" chalk "^4.0.0" @@ -555,10 +681,10 @@ eslint@^8.7.0: debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.1.0" + eslint-scope "^7.1.1" eslint-utils "^3.0.0" - eslint-visitor-keys "^3.2.0" - espree "^9.3.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.1" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -583,14 +709,14 @@ eslint@^8.7.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^9.2.0, espree@^9.3.0: - version "9.3.0" - resolved "https://registry.npmjs.org/espree/-/espree-9.3.0.tgz" - integrity sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ== +espree@^9.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" + integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== dependencies: acorn "^8.7.0" acorn-jsx "^5.3.1" - eslint-visitor-keys "^3.1.0" + eslint-visitor-keys "^3.3.0" esquery@^1.4.0: version "1.4.0" @@ -606,6 +732,11 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" @@ -621,6 +752,17 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" @@ -631,6 +773,13 @@ fast-levenshtein@^2.0.6: resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -727,6 +876,13 @@ gitlog@^4.0.4: debug "^4.1.1" tslib "^1.14.1" +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + glob-parent@^6.0.1: version "6.0.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" @@ -734,13 +890,6 @@ glob-parent@^6.0.1: dependencies: is-glob "^4.0.3" -glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - glob@^7.1.3: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" @@ -767,6 +916,18 @@ globals@^13.6.0, globals@^13.9.0: dependencies: type-fest "^0.20.2" +globby@^11.0.4: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + got@^9.6.0: version "9.6.0" resolved "https://registry.npmjs.org/got/-/got-9.6.0.tgz" @@ -824,12 +985,7 @@ ignore-by-default@^1.0.1: resolved "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz" integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.2.0: +ignore@^5.1.8, ignore@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== @@ -1057,6 +1213,19 @@ memory-pager@^1.0.2: resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + mime-db@1.51.0: version "1.51.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" @@ -1258,7 +1427,12 @@ path-key@^3.1.0: resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -picomatch@^2.0.4, picomatch@^2.2.1: +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -1303,6 +1477,11 @@ pupa@^2.1.1: dependencies: escape-goat "^2.0.0" +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + rc@^1.2.8: version "1.2.8" resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" @@ -1374,6 +1553,11 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + rfdc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" @@ -1386,6 +1570,13 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -1420,7 +1611,7 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.4: +semver@^7.3.4, semver@^7.3.5: version "7.3.5" resolved "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== @@ -1449,6 +1640,11 @@ signal-exit@^3.0.2: resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz" integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + sliced@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz" @@ -1551,7 +1747,7 @@ ts-mixer@^6.0.0: resolved "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz" integrity sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ== -tslib@^1.14.1: +tslib@^1.14.1, tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -1561,6 +1757,13 @@ tslib@^2.3.1: resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"