Add JSON metadata finder
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Ethan Lane 2023-12-06 18:16:00 +00:00
parent 5a8cc955f6
commit 9b11d5d495
11 changed files with 362 additions and 36 deletions

View file

@ -28,5 +28,7 @@ DB_CARD_FILE=:memory:
EXPRESS_PORT=3303
FEATURE_METADATA=true
GDRIVESYNC_WHITELIST=147392775707426816,887272961504071690
GDRIVESYNC_AUTO=true

View file

@ -28,5 +28,7 @@ DB_CARD_FILE=:memory:
EXPRESS_PORT=3323
FEATURE_METADATA=false
GDRIVESYNC_WHITELIST=147392775707426816,887272961504071690
GDRIVESYNC_AUTO=false

View file

@ -28,5 +28,7 @@ DB_CARD_FILE=:memory:
EXPRESS_PORT=3313
FEATURE_METADATA=true
GDRIVESYNC_WHITELIST=147392775707426816,887272961504071690
GDRIVESYNC_AUTO=false

View file

@ -31,6 +31,7 @@
"discord.js": "^14.3.0",
"dotenv": "^16.0.0",
"express": "^4.18.2",
"glob": "^10.3.10",
"jest": "^29.0.0",
"jest-mock-extended": "^3.0.0",
"minimatch": "9.0.3",

View file

@ -0,0 +1,38 @@
import { readFileSync } from "fs";
import path from "path";
import Config from "../database/entities/app/Config";
import { glob } from "glob";
import SeriesMetadata from "../contracts/SeriesMetadata";
import { CoreClient } from "../client/client";
export default class CardMetadataFunction {
public static async Execute(): Promise<boolean> {
if (await Config.GetValue('safemode') == "true") return false;
try {
CoreClient.Cards = await this.FindMetadataJSONs();
console.log(`Loaded ${CoreClient.Cards.flatMap(x => x.cards).length} cards to database`);
} catch {
await Config.SetValue('safemode', 'true');
return false;
}
return true;
}
private static async FindMetadataJSONs(): Promise<SeriesMetadata[]> {
const res: SeriesMetadata[] = [];
const seriesJSONs = await glob(path.join(process.cwd(), 'cards', '/**/*.json'));
for (let jsonPath of seriesJSONs) {
const jsonFile = readFileSync(jsonPath);
const parsedJson: SeriesMetadata[] = JSON.parse(jsonFile.toString());
res.push(...parsedJson);
}
return res;
}
}

View file

@ -6,9 +6,68 @@ import { v4 } from "uuid";
import { CoreClient } from "../client/client";
import Inventory from "../database/entities/app/Inventory";
import Config from "../database/entities/app/Config";
import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata";
import path from "path";
export default class Reroll extends ButtonEvent {
public override async execute(interaction: ButtonInteraction) {
if (!(process.env.FEATURE_METADATA && process.env.FEATURE_METADATA == 'true')) {
await this.executeLegacy(interaction);
return;
}
if (!CoreClient.AllowDrops) {
await interaction.reply('Bot is currently syncing, please wait until its done.');
return;
}
if (await Config.GetValue('safemode') == "true") {
await interaction.reply('Safe Mode has been activated, please resync to continue.');
return;
}
const randomCard = CardDropHelperMetadata.GetRandomCard();
if (!randomCard) {
await interaction.reply('Unable to fetch card, please try again.');
return;
}
const image = readFileSync(path.join(process.cwd(), 'cards', randomCard.card.path));
await interaction.deferReply();
const attachment = new AttachmentBuilder(image, { name: randomCard.card.id });
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.card.id);
const quantityClaimed = inventory ? inventory.Quantity : 0;
const embed = CardDropHelperMetadata.GenerateDropEmbed(randomCard, quantityClaimed);
const claimId = v4();
const row = CardDropHelperMetadata.GenerateDropButtons(randomCard, claimId, interaction.user.id);
try {
await interaction.editReply({
embeds: [ embed ],
files: [ attachment ],
components: [ row ],
});
} catch (e) {
console.error(e);
if (e instanceof DiscordAPIError) {
await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: ${e.code}`);
} else {
await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: UNKNOWN`);
}
}
CoreClient.ClaimId = claimId;
}
public async executeLegacy(interaction: ButtonInteraction) {
if (!CoreClient.AllowDrops) {
await interaction.reply('Bot is currently syncing, please wait until its done.');
return;

View file

@ -14,6 +14,8 @@ import { ButtonEvent } from "../type/buttonEvent";
import AppDataSource from "../database/dataSources/appDataSource";
import { Environment } from "../constants/Environment";
import Webhooks from "../webhooks";
import CardMetadataFunction from "../Functions/CardMetadataFunction";
import SeriesMetadata from "../contracts/SeriesMetadata";
export class CoreClient extends Client {
private static _commandItems: ICommandItem[];
@ -27,6 +29,7 @@ export class CoreClient extends Client {
public static ClaimId: string;
public static Environment: Environment;
public static AllowDrops: boolean;
public static Cards: SeriesMetadata[];
public static get commandItems(): ICommandItem[] {
return this._commandItems;
@ -75,7 +78,11 @@ export class CoreClient extends Client {
super.on("interactionCreate", this._events.onInteractionCreate);
super.on("ready", this._events.onReady);
await CardSetupFunction.Execute();
if (process.env.FEATURE_METADATA && process.env.FEATURE_METADATA == 'true') {
await CardMetadataFunction.Execute();
} else {
await CardSetupFunction.Execute();
}
this._util.loadEvents(this, CoreClient._eventItems);
this._util.loadSlashCommands(this);

View file

@ -6,6 +6,8 @@ import { CoreClient } from "../client/client";
import { v4 } from "uuid";
import Inventory from "../database/entities/app/Inventory";
import Config from "../database/entities/app/Config";
import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata";
import path from "path";
export default class Drop extends Command {
constructor() {
@ -17,6 +19,63 @@ export default class Drop extends Command {
}
public override async execute(interaction: CommandInteraction) {
if (!(process.env.FEATURE_METADATA && process.env.FEATURE_METADATA == 'true')) {
await this.executeLegacy(interaction);
return;
}
if (!CoreClient.AllowDrops) {
await interaction.reply('Bot is currently syncing, please wait until its done.');
return;
}
if (await Config.GetValue('safemode') == "true") {
await interaction.reply('Safe Mode has been activated, please resync to continue.');
return;
}
const randomCard = CardDropHelperMetadata.GetRandomCard();
if (!randomCard) {
await interaction.reply('Unable to fetch card, please try again.');
return;
}
const image = readFileSync(path.join(process.cwd(), 'cards', randomCard.card.path));
await interaction.deferReply();
const attachment = new AttachmentBuilder(image, { name: randomCard.card.id });
const inventory = await Inventory.FetchOneByCardNumberAndUserId(interaction.user.id, randomCard.card.id);
const quantityClaimed = inventory ? inventory.Quantity : 0;
const embed = CardDropHelperMetadata.GenerateDropEmbed(randomCard, quantityClaimed);
const claimId = v4();
const row = CardDropHelperMetadata.GenerateDropButtons(randomCard, claimId, interaction.user.id);
try {
await interaction.editReply({
embeds: [ embed ],
files: [ attachment ],
components: [ row ],
});
} catch (e) {
console.error(e);
if (e instanceof DiscordAPIError) {
await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: ${e.code}`);
} else {
await interaction.editReply(`Unable to send next drop. Please try again, and report this if it keeps happening. Code: UNKNOWN`);
}
}
CoreClient.ClaimId = claimId;
}
public async executeLegacy(interaction: CommandInteraction) {
if (!CoreClient.AllowDrops) {
await interaction.reply('Bot is currently syncing, please wait until its done.');
return;

View file

@ -0,0 +1,19 @@
import { CardRarity } from "../constants/CardRarity";
export default interface SeriesMetadata {
id: number,
name: string,
cards: CardMetadata[],
}
export interface CardMetadata {
id: string,
name: string,
type: CardRarity,
path: string,
}
export interface DropResult {
series: SeriesMetadata,
card: CardMetadata,
}

View file

@ -0,0 +1,76 @@
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
import { CardRarity, CardRarityToColour, CardRarityToString } from "../constants/CardRarity";
import CardRarityChances from "../constants/CardRarityChances";
import Card from "../database/entities/card/Card";
import SeriesMetadata, { CardMetadata, DropResult } from "../contracts/SeriesMetadata";
import { CoreClient } from "../client/client";
export default class CardDropHelperMetadata {
public static GetRandomCard(): DropResult | undefined {
const randomRarity = Math.random() * 100;
let cardRarity: CardRarity;
const bronzeChance = CardRarityChances.Bronze;
const silverChance = bronzeChance + CardRarityChances.Silver;
const goldChance = silverChance + CardRarityChances.Gold;
const mangaChance = goldChance + CardRarityChances.Manga;
if (randomRarity < bronzeChance) cardRarity = CardRarity.Bronze;
else if (randomRarity < silverChance) cardRarity = CardRarity.Silver;
else if (randomRarity < goldChance) cardRarity = CardRarity.Gold;
else if (randomRarity < mangaChance) cardRarity = CardRarity.Manga;
else cardRarity = CardRarity.Legendary;
const randomCard = this.GetRandomCardByRarity(cardRarity);
return randomCard;
}
public static GetRandomCardByRarity(rarity: CardRarity): DropResult | undefined {
const allCards = CoreClient.Cards
.flatMap(x => x.cards)
.filter(x => x.type == rarity);
const randomCardIndex = Math.floor(Math.random() * allCards.length);
const card = allCards[randomCardIndex];
const series = CoreClient.Cards
.find(x => x.cards.includes(card));
if (!series) {
return undefined;
}
return {
series: series,
card: card,
};
}
public static GenerateDropEmbed(drop: DropResult, quantityClaimed: Number): EmbedBuilder {
let description = "";
description += `Series: ${drop.series.name}\n`;
description += `Claimed: ${quantityClaimed}\n`;
return new EmbedBuilder()
.setTitle(drop.card.name)
.setDescription(description)
.setFooter({ text: CardRarityToString(drop.card.type) })
.setColor(CardRarityToColour(drop.card.type))
.setImage(`attachment://${drop.card.id}`);
}
public static GenerateDropButtons(drop: DropResult, claimId: string, userId: string): ActionRowBuilder<ButtonBuilder> {
return new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setCustomId(`claim ${drop.card.id} ${claimId} ${userId}`)
.setLabel("Claim")
.setStyle(ButtonStyle.Primary),
new ButtonBuilder()
.setCustomId(`reroll`)
.setLabel("Reroll")
.setStyle(ButtonStyle.Secondary));
}
}

131
yarn.lock
View file

@ -410,6 +410,18 @@
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
"@isaacs/cliui@^8.0.2":
version "8.0.2"
resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==
dependencies:
string-width "^5.1.2"
string-width-cjs "npm:string-width@^4.2.0"
strip-ansi "^7.0.1"
strip-ansi-cjs "npm:strip-ansi@^6.0.1"
wrap-ansi "^8.1.0"
wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
@ -707,6 +719,11 @@
mkdirp "^1.0.4"
rimraf "^3.0.2"
"@pkgjs/parseargs@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
"@pnpm/config.env-replace@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz#ab29da53df41e8948a00f2433f085f54de8b3a4c"
@ -950,14 +967,7 @@
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690"
integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==
"@types/node@*":
version "20.10.3"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.3.tgz#4900adcc7fc189d5af5bb41da8f543cea6962030"
integrity sha512-XJavIpZqiXID5Yxnxv3RUDKTN5b81ddNC3ecsA0SoFXz/QU8OGBwZGMomiq0zw+uuqbL/krztv/DINAQ/EV4gg==
dependencies:
undici-types "~5.26.4"
"@types/node@^20.0.0":
"@types/node@*", "@types/node@^20.0.0":
version "20.10.3"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.3.tgz#4900adcc7fc189d5af5bb41da8f543cea6962030"
integrity sha512-XJavIpZqiXID5Yxnxv3RUDKTN5b81ddNC3ecsA0SoFXz/QU8OGBwZGMomiq0zw+uuqbL/krztv/DINAQ/EV4gg==
@ -1867,7 +1877,7 @@ create-jest@^29.7.0:
jest-util "^29.7.0"
prompts "^2.0.1"
cross-spawn@^7.0.3:
cross-spawn@^7.0.0, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@ -2378,6 +2388,14 @@ find-up@^6.3.0:
locate-path "^7.1.0"
path-exists "^5.0.0"
foreground-child@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d"
integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==
dependencies:
cross-spawn "^7.0.0"
signal-exit "^4.0.1"
form-data-encoder@^2.1.2:
version "2.1.4"
resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5"
@ -2493,6 +2511,17 @@ glob-parent@^5.1.2:
dependencies:
is-glob "^4.0.1"
glob@^10.3.10:
version "10.3.10"
resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b"
integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==
dependencies:
foreground-child "^3.1.0"
jackspeak "^2.3.5"
minimatch "^9.0.1"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
path-scurry "^1.10.1"
glob@^7.1.3, glob@^7.1.4:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
@ -3159,6 +3188,15 @@ istanbul-reports@^3.1.3:
html-escaper "^2.0.0"
istanbul-lib-report "^3.0.0"
jackspeak@^2.3.5:
version "2.3.6"
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8"
integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==
dependencies:
"@isaacs/cliui" "^8.0.2"
optionalDependencies:
"@pkgjs/parseargs" "^0.11.0"
jest-changed-files@^29.7.0:
version "29.7.0"
resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a"
@ -3766,6 +3804,11 @@ lru-cache@^7.5.1:
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89"
integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==
"lru-cache@^9.1.1 || ^10.0.0":
version "10.1.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.1.0.tgz#2098d41c2dc56500e6c88584aa656c84de7d0484"
integrity sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==
magic-bytes.js@^1.5.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/magic-bytes.js/-/magic-bytes.js-1.6.0.tgz#ee4354ac41a9b86f410e2690bc25dc4c264fb55d"
@ -3904,7 +3947,7 @@ mimic-response@^4.0.0:
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f"
integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==
minimatch@9.0.3, minimatch@^9.0.0:
minimatch@9.0.3, minimatch@^9.0.0, minimatch@^9.0.1:
version "9.0.3"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825"
integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
@ -3981,6 +4024,11 @@ minipass@^5.0.0:
resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d"
integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0":
version "7.0.4"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c"
integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==
minizlib@^2.0.0, minizlib@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
@ -4515,6 +4563,14 @@ path-parse@^1.0.7:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
path-scurry@^1.10.1:
version "1.10.1"
resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698"
integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==
dependencies:
lru-cache "^9.1.1 || ^10.0.0"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
path-to-regexp@0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
@ -5007,6 +5063,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
signal-exit@^4.0.1:
version "4.1.0"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
sisteransi@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
@ -5136,6 +5197,15 @@ string-length@^4.0.1:
char-regex "^1.0.2"
strip-ansi "^6.0.0"
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
string-width@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
@ -5145,15 +5215,6 @@ string-width@^1.0.1:
is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0"
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
string-width@^2.1.0, string-width@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
@ -5185,6 +5246,13 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
@ -5206,13 +5274,6 @@ strip-ansi@^5.1.0:
dependencies:
ansi-regex "^4.1.0"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^7.0.1:
version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@ -5669,6 +5730,15 @@ widest-line@^4.0.1:
dependencies:
string-width "^5.0.1"
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba"
@ -5686,15 +5756,6 @@ wrap-ansi@^6.2.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"