Browse Source

Merge pull request #34 from ADawesomeguy/ts-migration

Begin TypeScript migration
pull/41/head
Abheek Dhawan 3 years ago
committed by GitHub
parent
commit
257eeca8e7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      .eslintrc.json
  2. 1
      .gitignore
  3. 78
      commands/about.js
  4. 16
      commands/help.js
  5. 113
      commands/rounds.js
  6. 40
      commands/top.js
  7. 172
      commands/train.js
  8. 21
      events/interactionCreate.js
  9. 35
      events/messageCreate.js
  10. 16
      events/ready.js
  11. 45
      helpers/db.js
  12. 8
      helpers/env.js
  13. 31
      helpers/log.js
  14. 34
      index.js
  15. 7
      package.json
  16. 77
      src/commands/about.ts
  17. 15
      src/commands/help.ts
  18. 112
      src/commands/rounds.ts
  19. 39
      src/commands/top.ts
  20. 171
      src/commands/train.ts
  21. 16
      src/deploy-commands.ts
  22. 21
      src/events/interactionCreate.ts
  23. 36
      src/events/messageCreate.ts
  24. 16
      src/events/ready.ts
  25. 44
      src/helpers/db.ts
  26. 6
      src/helpers/env.ts
  27. 29
      src/helpers/log.ts
  28. 38
      src/index.ts
  29. 4
      src/models/generateRound.ts
  30. 4
      src/models/userScore.ts
  31. 101
      tsconfig.json
  32. 296
      yarn.lock

12
.eslintrc.json

@ -1,12 +1,16 @@
{ {
"extends": "eslint:recommended", "extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"plugins": [
"@typescript-eslint"
],
"parser": "@typescript-eslint/parser",
"env": { "env": {
"node": true, "node": true,
"es6": true "es6": true
}, },
"parserOptions": {
"ecmaVersion": 2021
},
"rules": { "rules": {
"arrow-spacing": ["warn", { "before": true, "after": true }], "arrow-spacing": ["warn", { "before": true, "after": true }],
"brace-style": ["error", "stroustrup", { "allowSingleLine": true }], "brace-style": ["error", "stroustrup", { "allowSingleLine": true }],

1
.gitignore

@ -12,3 +12,4 @@ config.json
.DS_Store .DS_Store
data/ data/
*.patch *.patch
built/

78
commands/about.js

@ -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] });
}
},
};

16
commands/help.js

@ -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] });
},
};

113
commands/rounds.js

@ -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 = '<html><head><link rel=\'preconnect\' href=\'https://fonts.gstatic.com\'><link href=\'https://fonts.googleapis.com/css2?family=Ubuntu&display=swap\' rel=\'stylesheet\'> </head><body style=\'width: 70%; margin-left: auto; margin-right: auto;\'><h2 style=\'text-align: center; text-decoration: underline overline; padding: 7px;\'>ROUND GENERATED BY AWESOMESCIBO USING THE SCIBOWLDB API</h2>';
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 = '<br><br><h3 style=\'text-align: center;\'><strong>TOSS-UP</strong></h3>\n<br>' + `${i}) <strong>${question_category}</strong>` + ' ' + `<em>${tossup_format}</em>` + ' ' + tossup_question + '<br><br>' + '<strong>ANSWER:</strong> ' + tossup_answer + '<br>';
htmlContent += '<br><br><h3 style=\'text-align: center;\'><strong>BONUS</strong></h3>\n<br>' + `${i}) <strong>${question_category}</strong>` + ' ' + `<em>${bonus_format}</em>` + ' ' + bonus_question + '<br><br>' + '<strong>ANSWER:</strong> ' + bonus_answer + '<br><br><hr><br>';
htmlContent = htmlContent.replace(/\n/g, '<br>');
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}`);
}
},
};

40
commands/top.js

@ -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] });
});
},
};

172
commands/train.js

@ -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' }));
},
};

21
events/interactionCreate.js

@ -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 });
}
},
};

35
events/messageCreate.js

@ -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],
});
});
}
},
};

16
events/ready.js

@ -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' },
);
},
};

45
helpers/db.js

@ -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' }));
},
};

8
helpers/env.js

@ -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,
};

31
helpers/log.js

@ -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;
}
},
};

34
index.js

@ -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);

7
package.json

@ -10,8 +10,11 @@
"mongoose": "^5.12.5" "mongoose": "^5.12.5"
}, },
"devDependencies": { "devDependencies": {
"eslint": "^8.7.0", "@typescript-eslint/eslint-plugin": "^5.15.0",
"nodemon": "^2.0.15" "@typescript-eslint/parser": "^5.15.0",
"eslint": "^8.11.0",
"nodemon": "^2.0.15",
"typescript": "^4.6.2"
}, },
"name": "awesomescibo", "name": "awesomescibo",
"version": "3.2.1", "version": "3.2.1",

77
src/commands/about.ts

@ -0,0 +1,77 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { MessageEmbed } from 'discord.js';
import gitlog from 'gitlog';
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] });
}
}

15
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] });
}

112
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 = '<html><head><link rel=\'preconnect\' href=\'https://fonts.gstatic.com\'><link href=\'https://fonts.googleapis.com/css2?family=Ubuntu&display=swap\' rel=\'stylesheet\'> </head><body style=\'width: 70%; margin-left: auto; margin-right: auto;\'><h2 style=\'text-align: center; text-decoration: underline overline; padding: 7px;\'>ROUND GENERATED BY AWESOMESCIBO USING THE SCIBOWLDB API</h2>';
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 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 = '<br><br><h3 style=\'text-align: center;\'><strong>TOSS-UP</strong></h3>\n<br>' + `${i}) <strong>${question_category}</strong>` + ' ' + `<em>${tossup_format}</em>` + ' ' + tossup_question + '<br><br>' + '<strong>ANSWER:</strong> ' + tossup_answer + '<br>';
htmlContent += '<br><br><h3 style=\'text-align: center;\'><strong>BONUS</strong></h3>\n<br>' + `${i}) <strong>${question_category}</strong>` + ' ' + `<em>${bonus_format}</em>` + ' ' + bonus_question + '<br><br>' + '<strong>ANSWER:</strong> ' + bonus_answer + '<br><br><hr><br>';
htmlContent = htmlContent.replace(/\n/g, '<br>');
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}`);
}
}

39
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] });
});
}

171
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 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: ${questionData.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 (questionData.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' }));
}

16
deploy-commands.js → src/deploy-commands.ts

@ -1,16 +1,18 @@
#!/usr/bin/env node #!/usr/bin/env node
const fs = require('node:fs'); import fs from 'node:fs';
const { REST } = require('@discordjs/rest'); import { REST } from '@discordjs/rest';
const { Routes } = require('discord-api-types/v9'); import { Routes } from 'discord-api-types/v9';
const { clientId, token } = require('./helpers/env'); import { clientId, token } from './helpers/env';
const commands = []; const commands : any[] = [];
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js')); const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
for (const file of commandFiles) { for (const file of commandFiles) {
const command = require(`./commands/${file}`); import(`./commands/${file}`)
commands.push(command.data.toJSON()); .then(command => {
commands.push(command.data.toJSON());
});
} }
const rest = new REST({ version: '9' }).setToken(token); const rest = new REST({ version: '9' }).setToken(token);

21
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 });
}
}

36
src/events/messageCreate.ts

@ -0,0 +1,36 @@
import axios from 'axios';
import { MessageEmbed } from 'discord.js';
import { decode } from 'html-entities';
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],
});
});
}
}

16
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' },
);
}

44
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' }));
}

6
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!;

29
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;
}
}

38
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);

4
models/generateRound.js → src/models/generateRound.ts

@ -1,4 +1,4 @@
const mongoose = require('mongoose'); import mongoose from 'mongoose';
const generatedRoundSchema = new mongoose.Schema({ const generatedRoundSchema = new mongoose.Schema({
htmlContent: { htmlContent: {
@ -19,4 +19,4 @@ const generatedRoundSchema = new mongoose.Schema({
}, },
}); });
module.exports = mongoose.model('GeneratedRounds', generatedRoundSchema); export default mongoose.model('GeneratedRounds', generatedRoundSchema);

4
models/userScore.js → src/models/userScore.ts

@ -1,4 +1,4 @@
const mongoose = require('mongoose'); import mongoose from 'mongoose';
const userScoreSchema = new mongoose.Schema({ const userScoreSchema = new mongoose.Schema({
authorID: { authorID: {
@ -11,4 +11,4 @@ const userScoreSchema = new mongoose.Schema({
}, },
}); });
module.exports = mongoose.model('UserScore', userScoreSchema); export default mongoose.model('UserScore', userScoreSchema);

101
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 `<reference>`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. */
}
}

296
yarn.lock

@ -31,16 +31,16 @@
node-fetch "^2.6.5" node-fetch "^2.6.5"
tslib "^2.3.1" tslib "^2.3.1"
"@eslint/eslintrc@^1.0.5": "@eslint/eslintrc@^1.2.1":
version "1.0.5" version "1.2.1"
resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.1.tgz#8b5e1c49f4077235516bc9ec7d41378c0f69b8c6"
integrity sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ== integrity sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==
dependencies: dependencies:
ajv "^6.12.4" ajv "^6.12.4"
debug "^4.3.2" debug "^4.3.2"
espree "^9.2.0" espree "^9.3.1"
globals "^13.9.0" globals "^13.9.0"
ignore "^4.0.6" ignore "^5.2.0"
import-fresh "^3.2.1" import-fresh "^3.2.1"
js-yaml "^4.1.0" js-yaml "^4.1.0"
minimatch "^3.0.4" minimatch "^3.0.4"
@ -60,6 +60,27 @@
resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== 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": "@sapphire/async-queue@^1.1.9":
version "1.1.9" version "1.1.9"
resolved "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.9.tgz" resolved "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.9.tgz"
@ -101,6 +122,11 @@
dependencies: dependencies:
"@types/node" "*" "@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": "@types/mongodb@^3.5.27":
version "3.6.20" version "3.6.20"
resolved "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz" resolved "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz"
@ -129,6 +155,86 @@
dependencies: dependencies:
"@types/node" "*" "@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: abbrev@1:
version "1.1.1" version "1.1.1"
resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" 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" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== 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: asynckit@^0.4.0:
version "0.4.0" version "0.4.0"
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" 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" balanced-match "^1.0.0"
concat-map "0.0.1" concat-map "0.0.1"
braces@~3.0.2: braces@^3.0.1, braces@~3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 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" resolved "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz"
integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== 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: discord-api-types@^0.26.0, discord-api-types@^0.26.1:
version "0.26.1" version "0.26.1"
resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.26.1.tgz#726f766ddc37d60da95740991d22cb6ef2ed787b" 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" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
eslint-scope@^7.1.0: eslint-scope@^5.1.1:
version "7.1.0" version "5.1.1"
resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
integrity sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg== 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: dependencies:
esrecurse "^4.3.0" esrecurse "^4.3.0"
estraverse "^5.2.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" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz"
integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.2.0: eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0:
version "3.2.0" version "3.3.0"
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ== integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
eslint@^8.7.0: eslint@^8.11.0:
version "8.7.0" version "8.11.0"
resolved "https://registry.npmjs.org/eslint/-/eslint-8.7.0.tgz" resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.11.0.tgz#88b91cfba1356fc10bb9eb592958457dfe09fb37"
integrity sha512-ifHYzkBGrzS2iDU7KjhCAVMGCvF6M3Xfs8X8b37cgrUlDt6bWRTpRh6T/gtSXv1HJ/BUGgmjvNvOEGu85Iif7w== integrity sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==
dependencies: dependencies:
"@eslint/eslintrc" "^1.0.5" "@eslint/eslintrc" "^1.2.1"
"@humanwhocodes/config-array" "^0.9.2" "@humanwhocodes/config-array" "^0.9.2"
ajv "^6.10.0" ajv "^6.10.0"
chalk "^4.0.0" chalk "^4.0.0"
@ -555,10 +681,10 @@ eslint@^8.7.0:
debug "^4.3.2" debug "^4.3.2"
doctrine "^3.0.0" doctrine "^3.0.0"
escape-string-regexp "^4.0.0" escape-string-regexp "^4.0.0"
eslint-scope "^7.1.0" eslint-scope "^7.1.1"
eslint-utils "^3.0.0" eslint-utils "^3.0.0"
eslint-visitor-keys "^3.2.0" eslint-visitor-keys "^3.3.0"
espree "^9.3.0" espree "^9.3.1"
esquery "^1.4.0" esquery "^1.4.0"
esutils "^2.0.2" esutils "^2.0.2"
fast-deep-equal "^3.1.3" fast-deep-equal "^3.1.3"
@ -583,14 +709,14 @@ eslint@^8.7.0:
text-table "^0.2.0" text-table "^0.2.0"
v8-compile-cache "^2.0.3" v8-compile-cache "^2.0.3"
espree@^9.2.0, espree@^9.3.0: espree@^9.3.1:
version "9.3.0" version "9.3.1"
resolved "https://registry.npmjs.org/espree/-/espree-9.3.0.tgz" resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd"
integrity sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ== integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==
dependencies: dependencies:
acorn "^8.7.0" acorn "^8.7.0"
acorn-jsx "^5.3.1" acorn-jsx "^5.3.1"
eslint-visitor-keys "^3.1.0" eslint-visitor-keys "^3.3.0"
esquery@^1.4.0: esquery@^1.4.0:
version "1.4.0" version "1.4.0"
@ -606,6 +732,11 @@ esrecurse@^4.3.0:
dependencies: dependencies:
estraverse "^5.2.0" 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: estraverse@^5.1.0, estraverse@^5.2.0:
version "5.3.0" version "5.3.0"
resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" 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" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== 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: fast-json-stable-stringify@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" 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" resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= 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: file-entry-cache@^6.0.1:
version "6.0.1" version "6.0.1"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" 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" debug "^4.1.1"
tslib "^1.14.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: glob-parent@^6.0.1:
version "6.0.2" version "6.0.2"
resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz"
@ -734,13 +890,6 @@ glob-parent@^6.0.1:
dependencies: dependencies:
is-glob "^4.0.3" 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: glob@^7.1.3:
version "7.2.0" version "7.2.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" 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: dependencies:
type-fest "^0.20.2" 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: got@^9.6.0:
version "9.6.0" version "9.6.0"
resolved "https://registry.npmjs.org/got/-/got-9.6.0.tgz" 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" resolved "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz"
integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk=
ignore@^4.0.6: ignore@^5.1.8, ignore@^5.2.0:
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:
version "5.2.0" version "5.2.0"
resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz" resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz"
integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== 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" resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5"
integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== 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: mime-db@1.51.0:
version "1.51.0" version "1.51.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" 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" resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== 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" version "2.3.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
@ -1303,6 +1477,11 @@ pupa@^2.1.1:
dependencies: dependencies:
escape-goat "^2.0.0" 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: rc@^1.2.8:
version "1.2.8" version "1.2.8"
resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz"
@ -1374,6 +1553,11 @@ responselike@^1.0.2:
dependencies: dependencies:
lowercase-keys "^1.0.0" 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: rfdc@^1.3.0:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
@ -1386,6 +1570,13 @@ rimraf@^3.0.2:
dependencies: dependencies:
glob "^7.1.3" 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: safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2" version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 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" resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.3.4: semver@^7.3.4, semver@^7.3.5:
version "7.3.5" version "7.3.5"
resolved "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz" resolved "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz"
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== 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" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz"
integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== 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: sliced@1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz" 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" resolved "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz"
integrity sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ== integrity sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==
tslib@^1.14.1: tslib@^1.14.1, tslib@^1.8.1:
version "1.14.1" version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
@ -1561,6 +1757,13 @@ tslib@^2.3.1:
resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz" resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz"
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== 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: type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0" version "0.4.0"
resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"
@ -1580,6 +1783,11 @@ typedarray-to-buffer@^3.1.5:
dependencies: dependencies:
is-typedarray "^1.0.0" 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: undefsafe@^2.0.5:
version "2.0.5" version "2.0.5"
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"

Loading…
Cancel
Save