commit c9914e55ea53e4d7871a78609a7d1ce060921cea Author: Samir L. Boulema Date: Thu Apr 30 19:51:30 2026 +0200 Initial commit Co-authored-by: Copilot diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..81f3ec3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +# top-most EditorConfig file +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = tab +indent_size = 4 +tab_width = 4 diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..32909b2 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +npm node_modules +build \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..7fc8ba5 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,21 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "env": { "node": true }, + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "parserOptions": { + "sourceType": "module" + }, + "rules": { + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }], + "@typescript-eslint/ban-ts-comment": "off", + "no-prototype-builtins": "off", + "@typescript-eslint/no-empty-function": "off" + } +} diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 0000000..888b461 --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,71 @@ +name: MtG Deck + +on: + push: + branches: + - main + - 'feature/**' + +permissions: + contents: read + +env: + version: '1.0.${{ github.run_number }}' + nodeVersion: '18' + +jobs: + build: + name: 🛠️ Build + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: ${{ env.nodeVersion }}.x + + - name: Build plugin + run: | + npm install + npm run build + + - name: Publish Build Artifacts + uses: actions/upload-artifact@v7 + with: + name: mtg-deck + path: | + main.js + manifest.json + styles.css + + release: + if: github.ref_name == 'main' + name: 🚚 Release + needs: [build] + runs-on: ubuntu-latest + environment: Release + permissions: + contents: write + steps: + - name: Download artifact + uses: actions/download-artifact@v8 + with: + name: mtg-deck + + - name: Tag release + id: tag_release + uses: mathieudutour/github-tag-action@v6.2 + with: + custom_tag: '${{ env.version }}' + github_token: ${{ secrets.GITHUB_TOKEN }} + + - name: Create a GitHub release + uses: ncipollo/release-action@v1.21.0 + with: + tag: ${{ steps.tag_release.outputs.new_tag }} + name: ${{ steps.tag_release.outputs.new_tag }} + body: ${{ steps.tag_release.outputs.changelog }} + artifacts: 'main.js,manifest.json,styles.css' + skipIfReleaseExists: true \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f386483 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# vscode +.vscode + +# Intellij +*.iml +.idea + +# npm +node_modules + +# Don't include the compiled main.js file in the repo. +# They should be uploaded to GitHub releases instead. +main.js + +# Exclude sourcemaps +*.map + +# obsidian +data.json + +# Exclude macOS Finder (System Explorer) View States +.DS_Store diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..b973752 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +tag-version-prefix="" \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..2e469d2 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,8 @@ +main.js +node_modules/ +.husky +.circleci +jest/ +jest.config.js +*.md +esbuild.config.mjs \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1 @@ +{} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..326e7b9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Omar Delarosa & Samir Boulema + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..099d047 --- /dev/null +++ b/README.md @@ -0,0 +1,68 @@ +# Obsidian MTG Deck plugin + +This is a plugin to manage your Magic: The Gathering card collections and decks as Obsidian notes. + +## Decklists + +Using the `mtg-deck` syntax hint in any Markdown file, you can define your decklists as follows: + +```mtgdeck +4 Delver of Secrets // Insectile Aberration +4 Haughty Djinn +3 Tolarian Terror +4 Consider +4 Essence Scatter +4 Fading Hope +4 Make Disappear # consider Negate instead +4 Slip Out the Back +3 Spell Pierce +3 Thirst for Discovery +20 Island +1 Otawara, Soaring City +1 Otherworldly Gaze +1 Reckoner Bankbuster + +Sideboard: +2 Disdainful Stroke +4 Negate +4 Out of the Way +1 Reckoner Bankbuster +4 Ertai's Scorn +``` + +Which in turn renders as: + +![](art/example_decklist.png) + +You can also copy paste directly from MTGA exports, though setlists and collector's numbers will not be shown and are not yet supported in the renderer. + +## Collections + +This plugin expects your collection to be stored as csv files with the extension `.mtg.collection.csv` by default. This extension is configurable in settings: + +![](art/example_settings.png) + +These files are expected to be properly formed CSVs such as those generated by tools like [Deckbox](https://deckbox.org/) + +### Example CSV Files + +``` +Name,Count,Set +Delver of Secrets // Insectile Aberration,8,MID +"Otawara, Soaring City",4,NEO +"Rona's Vortex",2,DMU +``` + +``` +Name,Count,Set +Delver of Secrets // Insectile Aberration,1,MID +"Otawara, Soaring City",6,NEO +"Rona's Vortex",3,DMU +Ledger Shredder,5,SNC +``` + +Note that your collection will consist of the merged result of all of your CSV files. + +# Contributing + +See [the official Obsidian plugin guidelines](https://github.com/obsidianmd/obsidian-sample-plugin#obsidian-sample-plugin) \ No newline at end of file diff --git a/art/example_decklist.png b/art/example_decklist.png new file mode 100644 index 0000000..c715d7a Binary files /dev/null and b/art/example_decklist.png differ diff --git a/art/example_settings.png b/art/example_settings.png new file mode 100644 index 0000000..16b1b61 Binary files /dev/null and b/art/example_settings.png differ diff --git a/esbuild.config.mjs b/esbuild.config.mjs new file mode 100644 index 0000000..8e2dad0 --- /dev/null +++ b/esbuild.config.mjs @@ -0,0 +1,42 @@ +import esbuild from "esbuild"; +import process from "process"; +import builtins from 'builtin-modules' + +const banner = +`/* +THIS IS A GENERATED/BUNDLED FILE BY ESBUILD +if you want to view the source, please visit the github repository of this plugin +*/ +`; + +const prod = (process.argv[2] === 'production'); + +esbuild.build({ + banner: { + js: banner, + }, + entryPoints: ['main.ts'], + bundle: true, + external: [ + 'obsidian', + 'electron', + '@codemirror/autocomplete', + '@codemirror/collab', + '@codemirror/commands', + '@codemirror/language', + '@codemirror/lint', + '@codemirror/search', + '@codemirror/state', + '@codemirror/view', + '@lezer/common', + '@lezer/highlight', + '@lezer/lr', + ...builtins], + format: 'cjs', + watch: !prod, + target: 'es2018', + logLevel: "info", + sourcemap: prod ? false : 'inline', + treeShaking: true, + outfile: 'main.js', +}).catch(() => process.exit(1)); diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..18e2aa9 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,8 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +// import {defaults} from 'jest-config'; +module.exports = { + preset: 'ts-jest', + setupFiles: ['/jest/globalSetup.ts'], + testEnvironment: 'jest-environment-jsdom', + testRegex: '(/test/.*|(\\.|/)(test|spec))\\.[jt]sx?$' +}; \ No newline at end of file diff --git a/jest/fixtures/content.ts b/jest/fixtures/content.ts new file mode 100644 index 0000000..dbe779c --- /dev/null +++ b/jest/fixtures/content.ts @@ -0,0 +1,63 @@ +export const EXAMPLE_DECK_1: string = `Deck +4 Delver of Secrets // Insectile Aberration +4 Haughty Djinn +3 Tolarian Terror +4 Consider +4 Essence Scatter +4 Fading Hope +4 Make Disappear # consider Negate instead +4 Slip Out the Back +3 Spell Pierce +3 Thirst for Discovery +# Lands +20 Island +1 Otawara, Soaring City +1 Otherworldly Gaze +1 Reckoner Bankbuster + +Sideboard: +2 Disdainful Stroke +4 Negate +4 Out of the Way +1 Reckoner Bankbuster +4 Ertai's Scorn`; + +export const EXAMPLE_DECK_1_HTML = ` +

Deck


52 / 60cards$32.25 / $45.23

Sideboard:


10 / 15cards$0.74 / $5.19
`; + +export const EXAMPLE_DECK_1_HTML_WITHOUT_PRICES = ` +
`; + + +export const EXAMPLE_COLLECTION = { + "delver of secrets": 3, + "haughty djinn": 3, + "tolarian terror": 3, + consider: 4, + "essence scatter": 4, + "fading hope": 4, + "make disappear": 4, + "slipe out the back": 4, + "spell pierce": 3, + "thirst for discovery": 3, + island: 20, + "otawara, soaring city": 1, + "otherworldy gaze": 1, + "recokner bankbuster": 2, + "disdainful stroke": 2, + negate: 4, + "out of the way": 4, + "ertain's scorn": 4, +}; \ No newline at end of file diff --git a/jest/fixtures/scryfall-data.ts b/jest/fixtures/scryfall-data.ts new file mode 100644 index 0000000..c826ae4 --- /dev/null +++ b/jest/fixtures/scryfall-data.ts @@ -0,0 +1,2964 @@ +import { ScryfallResponse } from "../../src/scryfall"; + +export const EXAMPLE_SCRYFALL_RESPONSE_1: ScryfallResponse = { + "object": "list", + "total_cards": 1, + "has_more": false, + "data": [ + { + "object": "card", + "id": "abff6c81-65a4-48fa-ba8f-580f87b0344a", + "oracle_id": "edd531b9-f615-4399-8c8c-1c5e18c4acbf", + "multiverse_ids": [ + 534807, + 534808 + ], + "mtgo_id": 93028, + "arena_id": 78378, + "tcgplayer_id": 248082, + "cardmarket_id": 574906, + "name": "Delver of Secrets // Insectile Aberration", + "lang": "en", + "released_at": "2021-09-24", + "uri": "https://api.scryfall.com/cards/abff6c81-65a4-48fa-ba8f-580f87b0344a", + "scryfall_uri": "https://scryfall.com/card/mid/47/delver-of-secrets-insectile-aberration?utm_source=api", + "layout": "transform", + "highres_image": true, + "image_status": "highres_scan", + "cmc": 1, + "type_line": "Creature — Human Wizard // Creature — Human Insect", + "color_identity": [ + "U" + ], + "keywords": [ + "Flying", + "Transform" + ], + "card_faces": [ + { + "object": "card_face", + "name": "Delver of Secrets", + "mana_cost": "{U}", + "type_line": "Creature — Human Wizard", + "oracle_text": "At the beginning of your upkeep, look at the top card of your library. You may reveal that card. If an instant or sorcery card is revealed this way, transform Delver of Secrets.", + "colors": [ + "U" + ], + "power": "1", + "toughness": "1", + "flavor_text": "\"If my hypothesis is correct . . .\"", + "artist": "Matt Stewart", + "artist_id": "20871267-2d8a-41d5-b03a-be3d557c5734", + "illustration_id": "9b572479-d64a-4d61-bd09-2c9a95138ddb", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "normal": "https://cards.scryfall.io/normal/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "large": "https://cards.scryfall.io/large/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "png": "https://cards.scryfall.io/png/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.png?1634347351", + "art_crop": "https://cards.scryfall.io/art_crop/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "border_crop": "https://cards.scryfall.io/border_crop/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351" + } + }, + { + "object": "card_face", + "name": "Insectile Aberration", + "flavor_name": "", + "mana_cost": "", + "type_line": "Creature — Human Insect", + "oracle_text": "Flying", + "colors": [ + "U" + ], + "color_indicator": [ + "U" + ], + "power": "3", + "toughness": "2", + "flavor_text": "\"Aha! Yes! Now I hear it, the beautiful poetry of the lights in the sky. I must reach the moon and ask what it all means!\"", + "artist": "Matt Stewart", + "artist_id": "20871267-2d8a-41d5-b03a-be3d557c5734", + "illustration_id": "83f0906b-d0e5-4725-ab5b-e33ed3387123", + "image_uris": { + "small": "https://cards.scryfall.io/small/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "normal": "https://cards.scryfall.io/normal/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "large": "https://cards.scryfall.io/large/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "png": "https://cards.scryfall.io/png/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.png?1634347351", + "art_crop": "https://cards.scryfall.io/art_crop/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "border_crop": "https://cards.scryfall.io/border_crop/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351" + } + } + ], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "legal", + "vintage": "legal", + "penny": "legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "arena", + "paper", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": true, + "variation": false, + "set_id": "44b8eb8f-fa23-401a-98b5-1fbb9871128e", + "set": "mid", + "set_name": "Innistrad: Midnight Hunt", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/44b8eb8f-fa23-401a-98b5-1fbb9871128e", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Amid&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/mid?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/abff6c81-65a4-48fa-ba8f-580f87b0344a/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3Aedd531b9-f615-4399-8c8c-1c5e18c4acbf&unique=prints", + "collector_number": "47", + "digital": false, + "rarity": "uncommon", + "artist": "Matt Stewart", + "artist_ids": [ + "20871267-2d8a-41d5-b03a-be3d557c5734" + ], + "border_color": "black", + "frame": "2015", + "frame_effects": [ + "sunmoondfc" + ], + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 11230, + "penny_rank": 99, + "preview": { + "source": "Hareruya", + "source_uri": "https://article.hareruyamtg.com/article/54478", + "previewed_at": "2021-09-07" + }, + "prices": { + "usd": "0.41", + "usd_foil": "0.72", + "usd_etched": null, + "eur": "0.55", + "eur_foil": "1.34", + "tix": "0.03" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=534807", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Delver+of+Secrets+%2F%2F+Insectile+Aberration&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Delver+of+Secrets+%2F%2F+Insectile+Aberration&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Delver+of+Secrets" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/248082?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Delver+of+Secrets&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/93028?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + } + ] +}; + +export const EXAMPLE_MULTI_CARD_RESPONSE = { + "object": "list", + "not_found": [], + "data": [ + { + "object": "card", + "id": "abff6c81-65a4-48fa-ba8f-580f87b0344a", + "oracle_id": "edd531b9-f615-4399-8c8c-1c5e18c4acbf", + "multiverse_ids": [ + 534807, + 534808 + ], + "mtgo_id": 93028, + "arena_id": 78378, + "tcgplayer_id": 248082, + "cardmarket_id": 574906, + "name": "Delver of Secrets // Insectile Aberration", + "lang": "en", + "released_at": "2021-09-24", + "uri": "https://api.scryfall.com/cards/abff6c81-65a4-48fa-ba8f-580f87b0344a", + "scryfall_uri": "https://scryfall.com/card/mid/47/delver-of-secrets-insectile-aberration?utm_source=api", + "layout": "transform", + "highres_image": true, + "image_status": "highres_scan", + "cmc": 1, + "type_line": "Creature — Human Wizard // Creature — Human Insect", + "color_identity": [ + "U" + ], + "keywords": [ + "Flying", + "Transform" + ], + "card_faces": [ + { + "object": "card_face", + "name": "Delver of Secrets", + "mana_cost": "{U}", + "type_line": "Creature — Human Wizard", + "oracle_text": "At the beginning of your upkeep, look at the top card of your library. You may reveal that card. If an instant or sorcery card is revealed this way, transform Delver of Secrets.", + "colors": [ + "U" + ], + "power": "1", + "toughness": "1", + "flavor_text": "\"If my hypothesis is correct . . .\"", + "artist": "Matt Stewart", + "artist_id": "20871267-2d8a-41d5-b03a-be3d557c5734", + "illustration_id": "9b572479-d64a-4d61-bd09-2c9a95138ddb", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "normal": "https://cards.scryfall.io/normal/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "large": "https://cards.scryfall.io/large/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "png": "https://cards.scryfall.io/png/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.png?1634347351", + "art_crop": "https://cards.scryfall.io/art_crop/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "border_crop": "https://cards.scryfall.io/border_crop/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351" + } + }, + { + "object": "card_face", + "name": "Insectile Aberration", + "flavor_name": "", + "mana_cost": "", + "type_line": "Creature — Human Insect", + "oracle_text": "Flying", + "colors": [ + "U" + ], + "color_indicator": [ + "U" + ], + "power": "3", + "toughness": "2", + "flavor_text": "\"Aha! Yes! Now I hear it, the beautiful poetry of the lights in the sky. I must reach the moon and ask what it all means!\"", + "artist": "Matt Stewart", + "artist_id": "20871267-2d8a-41d5-b03a-be3d557c5734", + "illustration_id": "83f0906b-d0e5-4725-ab5b-e33ed3387123", + "image_uris": { + "small": "https://cards.scryfall.io/small/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "normal": "https://cards.scryfall.io/normal/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "large": "https://cards.scryfall.io/large/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "png": "https://cards.scryfall.io/png/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.png?1634347351", + "art_crop": "https://cards.scryfall.io/art_crop/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "border_crop": "https://cards.scryfall.io/border_crop/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351" + } + } + ], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "legal", + "vintage": "legal", + "penny": "legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "arena", + "paper", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": true, + "variation": false, + "set_id": "44b8eb8f-fa23-401a-98b5-1fbb9871128e", + "set": "mid", + "set_name": "Innistrad: Midnight Hunt", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/44b8eb8f-fa23-401a-98b5-1fbb9871128e", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Amid&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/mid?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/abff6c81-65a4-48fa-ba8f-580f87b0344a/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3Aedd531b9-f615-4399-8c8c-1c5e18c4acbf&unique=prints", + "collector_number": "47", + "digital": false, + "rarity": "uncommon", + "artist": "Matt Stewart", + "artist_ids": [ + "20871267-2d8a-41d5-b03a-be3d557c5734" + ], + "border_color": "black", + "frame": "2015", + "frame_effects": [ + "sunmoondfc" + ], + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 11230, + "penny_rank": 99, + "preview": { + "source": "Hareruya", + "source_uri": "https://article.hareruyamtg.com/article/54478", + "previewed_at": "2021-09-07" + }, + "prices": { + "usd": "0.41", + "usd_foil": "0.72", + "usd_etched": null, + "eur": "0.55", + "eur_foil": "1.34", + "tix": "0.03" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=534807", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Delver+of+Secrets+%2F%2F+Insectile+Aberration&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Delver+of+Secrets+%2F%2F+Insectile+Aberration&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Delver+of+Secrets" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/248082?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Delver+of+Secrets&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/93028?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + { + "object": "card", + "id": "7ea4b5bc-18a4-45db-a56a-ab3f8bd2fb0d", + "oracle_id": "e9117015-1050-44dd-a46b-e7ffe2085fae", + "multiverse_ids": [ + 555247 + ], + "mtgo_id": 98311, + "arena_id": 80197, + "tcgplayer_id": 268342, + "cardmarket_id": 651255, + "name": "Ledger Shredder", + "lang": "en", + "released_at": "2022-04-29", + "uri": "https://api.scryfall.com/cards/7ea4b5bc-18a4-45db-a56a-ab3f8bd2fb0d", + "scryfall_uri": "https://scryfall.com/card/snc/46/ledger-shredder?utm_source=api", + "layout": "normal", + "highres_image": true, + "image_status": "highres_scan", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/7/e/7ea4b5bc-18a4-45db-a56a-ab3f8bd2fb0d.jpg?1664410287", + "normal": "https://cards.scryfall.io/normal/front/7/e/7ea4b5bc-18a4-45db-a56a-ab3f8bd2fb0d.jpg?1664410287", + "large": "https://cards.scryfall.io/large/front/7/e/7ea4b5bc-18a4-45db-a56a-ab3f8bd2fb0d.jpg?1664410287", + "png": "https://cards.scryfall.io/png/front/7/e/7ea4b5bc-18a4-45db-a56a-ab3f8bd2fb0d.png?1664410287", + "art_crop": "https://cards.scryfall.io/art_crop/front/7/e/7ea4b5bc-18a4-45db-a56a-ab3f8bd2fb0d.jpg?1664410287", + "border_crop": "https://cards.scryfall.io/border_crop/front/7/e/7ea4b5bc-18a4-45db-a56a-ab3f8bd2fb0d.jpg?1664410287" + }, + "mana_cost": "{1}{U}", + "cmc": 2, + "type_line": "Creature — Bird Advisor", + "oracle_text": "Flying\nWhenever a player casts their second spell each turn, Ledger Shredder connives. (Draw a card, then discard a card. If you discarded a nonland card, put a +1/+1 counter on this creature.)", + "power": "1", + "toughness": "3", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [ + "Flying", + "Connive" + ], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "not_legal", + "vintage": "legal", + "penny": "not_legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "not_legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "paper", + "mtgo", + "arena" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": false, + "variation": false, + "set_id": "df837242-8c15-42e4-b049-c933a02dc501", + "set": "snc", + "set_name": "Streets of New Capenna", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/df837242-8c15-42e4-b049-c933a02dc501", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Asnc&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/snc?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/7ea4b5bc-18a4-45db-a56a-ab3f8bd2fb0d/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3Ae9117015-1050-44dd-a46b-e7ffe2085fae&unique=prints", + "collector_number": "46", + "digital": false, + "rarity": "rare", + "watermark": "obscura", + "flavor_text": "No evidence, no crime.", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Mila Pesic", + "artist_ids": [ + "81c5ec23-220b-4efa-b7df-9e49dd371e8d" + ], + "illustration_id": "d64a1c85-5bff-4dfb-a6f2-5a7e05590d36", + "border_color": "black", + "frame": "2015", + "security_stamp": "oval", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 1612, + "preview": { + "source": "Wizards of the Coast", + "source_uri": "https://magic.wizards.com/en/articles/archive/feature/streets-of-new-capenna-mechanics-2022-04-07", + "previewed_at": "2022-04-07" + }, + "prices": { + "usd": "18.80", + "usd_foil": "20.41", + "usd_etched": null, + "eur": "23.81", + "eur_foil": "31.00", + "tix": "19.79" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555247", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Ledger+Shredder&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Ledger+Shredder&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Ledger+Shredder" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/268342?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Ledger+Shredder&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/98311?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + { + "object": "card", + "id": "95f27eeb-6f14-4db3-adb9-9be5ed76b34b", + "oracle_id": "53f7c868-b03e-4fc2-8dcf-a75bbfa3272b", + "multiverse_ids": [ + 442071 + ], + "mtgo_id": 67078, + "mtgo_foil_id": 67079, + "tcgplayer_id": 161421, + "cardmarket_id": 319002, + "name": "Dark Ritual", + "lang": "en", + "released_at": "2018-03-16", + "uri": "https://api.scryfall.com/cards/95f27eeb-6f14-4db3-adb9-9be5ed76b34b", + "scryfall_uri": "https://scryfall.com/card/a25/82/dark-ritual?utm_source=api", + "layout": "normal", + "highres_image": true, + "image_status": "highres_scan", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/9/5/95f27eeb-6f14-4db3-adb9-9be5ed76b34b.jpg?1628801678", + "normal": "https://cards.scryfall.io/normal/front/9/5/95f27eeb-6f14-4db3-adb9-9be5ed76b34b.jpg?1628801678", + "large": "https://cards.scryfall.io/large/front/9/5/95f27eeb-6f14-4db3-adb9-9be5ed76b34b.jpg?1628801678", + "png": "https://cards.scryfall.io/png/front/9/5/95f27eeb-6f14-4db3-adb9-9be5ed76b34b.png?1628801678", + "art_crop": "https://cards.scryfall.io/art_crop/front/9/5/95f27eeb-6f14-4db3-adb9-9be5ed76b34b.jpg?1628801678", + "border_crop": "https://cards.scryfall.io/border_crop/front/9/5/95f27eeb-6f14-4db3-adb9-9be5ed76b34b.jpg?1628801678" + }, + "mana_cost": "{B}", + "cmc": 1, + "type_line": "Instant", + "oracle_text": "Add {B}{B}{B}.", + "colors": [ + "B" + ], + "color_identity": [ + "B" + ], + "keywords": [], + "produced_mana": [ + "B" + ], + "legalities": { + "standard": "not_legal", + "future": "not_legal", + "historic": "banned", + "gladiator": "legal", + "pioneer": "not_legal", + "explorer": "not_legal", + "modern": "not_legal", + "legacy": "legal", + "pauper": "legal", + "vintage": "legal", + "penny": "legal", + "commander": "legal", + "brawl": "not_legal", + "historicbrawl": "legal", + "alchemy": "not_legal", + "paupercommander": "legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "legal" + }, + "games": [ + "paper", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": true, + "variation": false, + "set_id": "41ee6e2f-69b3-4c53-8a8e-960f5e974cfc", + "set": "a25", + "set_name": "Masters 25", + "set_type": "masters", + "set_uri": "https://api.scryfall.com/sets/41ee6e2f-69b3-4c53-8a8e-960f5e974cfc", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Aa25&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/a25?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/95f27eeb-6f14-4db3-adb9-9be5ed76b34b/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3A53f7c868-b03e-4fc2-8dcf-a75bbfa3272b&unique=prints", + "collector_number": "82", + "digital": false, + "rarity": "common", + "watermark": "set", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Clint Langley", + "artist_ids": [ + "0f670587-9f7b-47b3-89cc-8dca80df4cdf" + ], + "illustration_id": "d2b19b06-705f-40e4-aace-072885238f4c", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 80, + "penny_rank": 27, + "prices": { + "usd": "0.76", + "usd_foil": "1.95", + "usd_etched": null, + "eur": "1.10", + "eur_foil": "3.19", + "tix": "0.05" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=442071", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Dark+Ritual&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Dark+Ritual&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Dark+Ritual" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/161421?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Dark+Ritual&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/67078?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + } + ] +}; + +export const EXAMPLE_DECKLIST_CARD_DATA = { + "delver of secrets": { + "object": "card", + "id": "abff6c81-65a4-48fa-ba8f-580f87b0344a", + "oracle_id": "edd531b9-f615-4399-8c8c-1c5e18c4acbf", + "multiverse_ids": [ + 534807, + 534808 + ], + "mtgo_id": 93028, + "arena_id": 78378, + "tcgplayer_id": 248082, + "cardmarket_id": 574906, + "name": "Delver of Secrets // Insectile Aberration", + "lang": "en", + "released_at": "2021-09-24", + "uri": "https://api.scryfall.com/cards/abff6c81-65a4-48fa-ba8f-580f87b0344a", + "scryfall_uri": "https://scryfall.com/card/mid/47/delver-of-secrets-insectile-aberration?utm_source=api", + "layout": "transform", + "highres_image": true, + "image_status": "highres_scan", + "cmc": 1, + "type_line": "Creature — Human Wizard // Creature — Human Insect", + "color_identity": [ + "U" + ], + "keywords": [ + "Flying", + "Transform" + ], + "card_faces": [ + { + "object": "card_face", + "name": "Delver of Secrets", + "mana_cost": "{U}", + "type_line": "Creature — Human Wizard", + "oracle_text": "At the beginning of your upkeep, look at the top card of your library. You may reveal that card. If an instant or sorcery card is revealed this way, transform Delver of Secrets.", + "colors": [ + "U" + ], + "power": "1", + "toughness": "1", + "flavor_text": "\"If my hypothesis is correct . . .\"", + "artist": "Matt Stewart", + "artist_id": "20871267-2d8a-41d5-b03a-be3d557c5734", + "illustration_id": "9b572479-d64a-4d61-bd09-2c9a95138ddb", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "normal": "https://cards.scryfall.io/normal/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "large": "https://cards.scryfall.io/large/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "png": "https://cards.scryfall.io/png/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.png?1634347351", + "art_crop": "https://cards.scryfall.io/art_crop/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "border_crop": "https://cards.scryfall.io/border_crop/front/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351" + } + }, + { + "object": "card_face", + "name": "Insectile Aberration", + "flavor_name": "", + "mana_cost": "", + "type_line": "Creature — Human Insect", + "oracle_text": "Flying", + "colors": [ + "U" + ], + "color_indicator": [ + "U" + ], + "power": "3", + "toughness": "2", + "flavor_text": "\"Aha! Yes! Now I hear it, the beautiful poetry of the lights in the sky. I must reach the moon and ask what it all means!\"", + "artist": "Matt Stewart", + "artist_id": "20871267-2d8a-41d5-b03a-be3d557c5734", + "illustration_id": "83f0906b-d0e5-4725-ab5b-e33ed3387123", + "image_uris": { + "small": "https://cards.scryfall.io/small/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "normal": "https://cards.scryfall.io/normal/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "large": "https://cards.scryfall.io/large/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "png": "https://cards.scryfall.io/png/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.png?1634347351", + "art_crop": "https://cards.scryfall.io/art_crop/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351", + "border_crop": "https://cards.scryfall.io/border_crop/back/a/b/abff6c81-65a4-48fa-ba8f-580f87b0344a.jpg?1634347351" + } + } + ], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "legal", + "vintage": "legal", + "penny": "legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "arena", + "paper", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": true, + "variation": false, + "set_id": "44b8eb8f-fa23-401a-98b5-1fbb9871128e", + "set": "mid", + "set_name": "Innistrad: Midnight Hunt", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/44b8eb8f-fa23-401a-98b5-1fbb9871128e", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Amid&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/mid?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/abff6c81-65a4-48fa-ba8f-580f87b0344a/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3Aedd531b9-f615-4399-8c8c-1c5e18c4acbf&unique=prints", + "collector_number": "47", + "digital": false, + "rarity": "uncommon", + "artist": "Matt Stewart", + "artist_ids": [ + "20871267-2d8a-41d5-b03a-be3d557c5734" + ], + "border_color": "black", + "frame": "2015", + "frame_effects": [ + "sunmoondfc" + ], + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 11230, + "penny_rank": 99, + "preview": { + "source": "Hareruya", + "source_uri": "https://article.hareruyamtg.com/article/54478", + "previewed_at": "2021-09-07" + }, + "prices": { + "usd": "0.41", + "usd_foil": "0.72", + "usd_etched": null, + "eur": "0.55", + "eur_foil": "1.34", + "tix": "0.03" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=534807", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Delver+of+Secrets+%2F%2F+Insectile+Aberration&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Delver+of+Secrets+%2F%2F+Insectile+Aberration&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Delver+of+Secrets" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/248082?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Delver+of+Secrets&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/93028?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "haughty djinn": { + "object": "card", + "id": "35095a68-b7c0-4805-b0b6-6ca15a338692", + "oracle_id": "44036bb5-f300-40bd-9180-6b246315d886", + "multiverse_ids": [ + 574532 + ], + "mtgo_id": 102580, + "arena_id": 82104, + "tcgplayer_id": 283407, + "cardmarket_id": 672315, + "name": "Haughty Djinn", + "lang": "en", + "released_at": "2022-09-09", + "uri": "https://api.scryfall.com/cards/35095a68-b7c0-4805-b0b6-6ca15a338692", + "scryfall_uri": "https://scryfall.com/card/dmu/52/haughty-djinn?utm_source=api", + "layout": "normal", + "highres_image": false, + "image_status": "lowres", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/3/5/35095a68-b7c0-4805-b0b6-6ca15a338692.jpg?1663047886", + "normal": "https://cards.scryfall.io/normal/front/3/5/35095a68-b7c0-4805-b0b6-6ca15a338692.jpg?1663047886", + "large": "https://cards.scryfall.io/large/front/3/5/35095a68-b7c0-4805-b0b6-6ca15a338692.jpg?1663047886", + "png": "https://cards.scryfall.io/png/front/3/5/35095a68-b7c0-4805-b0b6-6ca15a338692.png?1663047886", + "art_crop": "https://cards.scryfall.io/art_crop/front/3/5/35095a68-b7c0-4805-b0b6-6ca15a338692.jpg?1663047886", + "border_crop": "https://cards.scryfall.io/border_crop/front/3/5/35095a68-b7c0-4805-b0b6-6ca15a338692.jpg?1663047886" + }, + "mana_cost": "{1}{U}{U}", + "cmc": 3, + "type_line": "Creature — Djinn", + "oracle_text": "Flying\nHaughty Djinn's power is equal to the number of instant and sorcery cards in your graveyard.\nInstant and sorcery spells you cast cost {1} less to cast.", + "power": "*", + "toughness": "4", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [ + "Flying" + ], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "not_legal", + "vintage": "legal", + "penny": "not_legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "not_legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "paper", + "arena", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": false, + "variation": false, + "set_id": "4e47a6cd-cdeb-4b0f-8f24-cfe1a0127cb3", + "set": "dmu", + "set_name": "Dominaria United", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/4e47a6cd-cdeb-4b0f-8f24-cfe1a0127cb3", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Admu&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/dmu?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/35095a68-b7c0-4805-b0b6-6ca15a338692/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3A44036bb5-f300-40bd-9180-6b246315d886&unique=prints", + "collector_number": "52", + "digital": false, + "rarity": "rare", + "flavor_text": "\"I adore your outfit. It's so . . . rustic.\"", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Mike Jordana", + "artist_ids": [ + "342d3a1e-0ddf-4823-af83-e13be8152b3f" + ], + "illustration_id": "7a06a88b-ecda-4825-91a5-e6ceefed3e24", + "border_color": "black", + "frame": "2015", + "security_stamp": "oval", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 10434, + "preview": { + "source": "iYingdi", + "source_uri": "https://www.iyingdi.com/tz/post/5213548", + "previewed_at": "2022-08-23" + }, + "prices": { + "usd": "1.60", + "usd_foil": "1.83", + "usd_etched": null, + "eur": "1.20", + "eur_foil": "1.40", + "tix": "0.39" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=574532", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Haughty+Djinn&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Haughty+Djinn&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Haughty+Djinn" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/283407?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Haughty+Djinn&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/102580?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "tolarian terror": { + "object": "card", + "id": "42f01cba-43d4-46ad-b7a5-d7631b0e1347", + "oracle_id": "b9d0f2e1-62c2-44fd-ad38-471daf17bb0a", + "multiverse_ids": [ + 574552 + ], + "mtgo_id": 102620, + "arena_id": 82124, + "tcgplayer_id": 282807, + "cardmarket_id": 671568, + "name": "Tolarian Terror", + "lang": "en", + "released_at": "2022-09-09", + "uri": "https://api.scryfall.com/cards/42f01cba-43d4-46ad-b7a5-d7631b0e1347", + "scryfall_uri": "https://scryfall.com/card/dmu/72/tolarian-terror?utm_source=api", + "layout": "normal", + "highres_image": false, + "image_status": "lowres", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/4/2/42f01cba-43d4-46ad-b7a5-d7631b0e1347.jpg?1663048321", + "normal": "https://cards.scryfall.io/normal/front/4/2/42f01cba-43d4-46ad-b7a5-d7631b0e1347.jpg?1663048321", + "large": "https://cards.scryfall.io/large/front/4/2/42f01cba-43d4-46ad-b7a5-d7631b0e1347.jpg?1663048321", + "png": "https://cards.scryfall.io/png/front/4/2/42f01cba-43d4-46ad-b7a5-d7631b0e1347.png?1663048321", + "art_crop": "https://cards.scryfall.io/art_crop/front/4/2/42f01cba-43d4-46ad-b7a5-d7631b0e1347.jpg?1663048321", + "border_crop": "https://cards.scryfall.io/border_crop/front/4/2/42f01cba-43d4-46ad-b7a5-d7631b0e1347.jpg?1663048321" + }, + "mana_cost": "{6}{U}", + "cmc": 7, + "type_line": "Creature — Serpent", + "oracle_text": "This spell costs {1} less to cast for each instant and sorcery card in your graveyard.\nWard {2} (Whenever this creature becomes the target of a spell or ability an opponent controls, counter it unless that player pays {2}.)", + "power": "5", + "toughness": "5", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [ + "Ward" + ], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "legal", + "vintage": "legal", + "penny": "legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "paper", + "arena", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": false, + "variation": false, + "set_id": "4e47a6cd-cdeb-4b0f-8f24-cfe1a0127cb3", + "set": "dmu", + "set_name": "Dominaria United", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/4e47a6cd-cdeb-4b0f-8f24-cfe1a0127cb3", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Admu&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/dmu?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/42f01cba-43d4-46ad-b7a5-d7631b0e1347/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3Ab9d0f2e1-62c2-44fd-ad38-471daf17bb0a&unique=prints", + "collector_number": "72", + "digital": false, + "rarity": "common", + "flavor_text": "Afterward, a number of treatises on sea serpent morphology were swiftly revised.", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Vincent Christiaens", + "artist_ids": [ + "31b01a73-d14f-4f9e-a5dc-9cee3b036124" + ], + "illustration_id": "6265d0da-6027-4f05-80e0-f9e78190324e", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 16859, + "penny_rank": 303, + "preview": { + "source": "AhhDean", + "source_uri": "https://twitter.com/Ahh_Deano/status/1560549459980759040", + "previewed_at": "2022-08-19" + }, + "prices": { + "usd": "0.23", + "usd_foil": "0.72", + "usd_etched": null, + "eur": "0.21", + "eur_foil": "0.63", + "tix": "0.01" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=574552", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Tolarian+Terror&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Tolarian+Terror&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Tolarian+Terror" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/282807?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Tolarian+Terror&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/102620?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "consider": { + "object": "card", + "id": "a211d505-4d40-4914-a9da-220770d6ddbc", + "oracle_id": "4c9bcba6-87b5-4fb3-97ee-6fe5b739337d", + "multiverse_ids": [ + 534803 + ], + "mtgo_id": 93020, + "arena_id": 78374, + "tcgplayer_id": 246015, + "cardmarket_id": 573807, + "name": "Consider", + "lang": "en", + "released_at": "2021-09-24", + "uri": "https://api.scryfall.com/cards/a211d505-4d40-4914-a9da-220770d6ddbc", + "scryfall_uri": "https://scryfall.com/card/mid/44/consider?utm_source=api", + "layout": "normal", + "highres_image": true, + "image_status": "highres_scan", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/a/2/a211d505-4d40-4914-a9da-220770d6ddbc.jpg?1634348697", + "normal": "https://cards.scryfall.io/normal/front/a/2/a211d505-4d40-4914-a9da-220770d6ddbc.jpg?1634348697", + "large": "https://cards.scryfall.io/large/front/a/2/a211d505-4d40-4914-a9da-220770d6ddbc.jpg?1634348697", + "png": "https://cards.scryfall.io/png/front/a/2/a211d505-4d40-4914-a9da-220770d6ddbc.png?1634348697", + "art_crop": "https://cards.scryfall.io/art_crop/front/a/2/a211d505-4d40-4914-a9da-220770d6ddbc.jpg?1634348697", + "border_crop": "https://cards.scryfall.io/border_crop/front/a/2/a211d505-4d40-4914-a9da-220770d6ddbc.jpg?1634348697" + }, + "mana_cost": "{U}", + "cmc": 1, + "type_line": "Instant", + "oracle_text": "Look at the top card of your library. You may put that card into your graveyard.\nDraw a card.", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "legal", + "vintage": "legal", + "penny": "not_legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "arena", + "paper", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": false, + "variation": false, + "set_id": "44b8eb8f-fa23-401a-98b5-1fbb9871128e", + "set": "mid", + "set_name": "Innistrad: Midnight Hunt", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/44b8eb8f-fa23-401a-98b5-1fbb9871128e", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Amid&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/mid?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/a211d505-4d40-4914-a9da-220770d6ddbc/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3A4c9bcba6-87b5-4fb3-97ee-6fe5b739337d&unique=prints", + "collector_number": "44", + "digital": false, + "rarity": "common", + "flavor_text": "Ivold gasped in surprise. Either a very strange insect had crawled onto one of the lenses or he was seeing geists at last!", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Zezhou Chen", + "artist_ids": [ + "810677e5-a502-4c03-b726-78cd808a75d4" + ], + "illustration_id": "ae8017d0-f56b-43a9-ab21-8ebc1f51d2c9", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 933, + "penny_rank": 23, + "prices": { + "usd": "1.81", + "usd_foil": "2.90", + "usd_etched": null, + "eur": "1.00", + "eur_foil": "2.95", + "tix": "0.08" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=534803", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Consider&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Consider&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Consider" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/246015?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Consider&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/93020?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "essence scatter": { + "object": "card", + "id": "b7ad4441-e300-4267-bedb-4ae6a64f59cd", + "oracle_id": "46665089-aa3d-44c3-964d-6638dfbb5782", + "multiverse_ids": [ + 574529 + ], + "mtgo_id": 102574, + "arena_id": 82101, + "tcgplayer_id": 283616, + "cardmarket_id": 672652, + "name": "Essence Scatter", + "lang": "en", + "released_at": "2022-09-09", + "uri": "https://api.scryfall.com/cards/b7ad4441-e300-4267-bedb-4ae6a64f59cd", + "scryfall_uri": "https://scryfall.com/card/dmu/49/essence-scatter?utm_source=api", + "layout": "normal", + "highres_image": false, + "image_status": "lowres", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/b/7/b7ad4441-e300-4267-bedb-4ae6a64f59cd.jpg?1663047829", + "normal": "https://cards.scryfall.io/normal/front/b/7/b7ad4441-e300-4267-bedb-4ae6a64f59cd.jpg?1663047829", + "large": "https://cards.scryfall.io/large/front/b/7/b7ad4441-e300-4267-bedb-4ae6a64f59cd.jpg?1663047829", + "png": "https://cards.scryfall.io/png/front/b/7/b7ad4441-e300-4267-bedb-4ae6a64f59cd.png?1663047829", + "art_crop": "https://cards.scryfall.io/art_crop/front/b/7/b7ad4441-e300-4267-bedb-4ae6a64f59cd.jpg?1663047829", + "border_crop": "https://cards.scryfall.io/border_crop/front/b/7/b7ad4441-e300-4267-bedb-4ae6a64f59cd.jpg?1663047829" + }, + "mana_cost": "{1}{U}", + "cmc": 2, + "type_line": "Instant", + "oracle_text": "Counter target creature spell.", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "legal", + "vintage": "legal", + "penny": "legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "paper", + "arena", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": true, + "variation": false, + "set_id": "4e47a6cd-cdeb-4b0f-8f24-cfe1a0127cb3", + "set": "dmu", + "set_name": "Dominaria United", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/4e47a6cd-cdeb-4b0f-8f24-cfe1a0127cb3", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Admu&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/dmu?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/b7ad4441-e300-4267-bedb-4ae6a64f59cd/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3A46665089-aa3d-44c3-964d-6638dfbb5782&unique=prints", + "collector_number": "49", + "digital": false, + "rarity": "common", + "flavor_text": "\"Phyrexians pollute everything they touch, so the solution is simple: don't let them touch anything.\"\n—Teferi", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Anastasia Ovchinnikova", + "artist_ids": [ + "3605d81f-5c97-4958-9dcc-d44a85e10305" + ], + "illustration_id": "c9ff8d5c-beba-4686-9ad6-88f6e12a4849", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 3436, + "penny_rank": 2243, + "prices": { + "usd": "0.05", + "usd_foil": "0.07", + "usd_etched": null, + "eur": "0.06", + "eur_foil": "0.14", + "tix": "0.01" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=574529", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Essence+Scatter&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Essence+Scatter&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Essence+Scatter" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/283616?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Essence+Scatter&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/102574?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "fading hope": { + "object": "card", + "id": "c2fb1fff-12be-4bd5-8dba-c36e84d49651", + "oracle_id": "64883ef2-c536-42e2-b52f-cfd1984fcdfd", + "multiverse_ids": [ + 534812 + ], + "mtgo_id": 93038, + "arena_id": 78383, + "tcgplayer_id": 248204, + "cardmarket_id": 574992, + "name": "Fading Hope", + "lang": "en", + "released_at": "2021-09-24", + "uri": "https://api.scryfall.com/cards/c2fb1fff-12be-4bd5-8dba-c36e84d49651", + "scryfall_uri": "https://scryfall.com/card/mid/51/fading-hope?utm_source=api", + "layout": "normal", + "highres_image": true, + "image_status": "highres_scan", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/c/2/c2fb1fff-12be-4bd5-8dba-c36e84d49651.jpg?1634348819", + "normal": "https://cards.scryfall.io/normal/front/c/2/c2fb1fff-12be-4bd5-8dba-c36e84d49651.jpg?1634348819", + "large": "https://cards.scryfall.io/large/front/c/2/c2fb1fff-12be-4bd5-8dba-c36e84d49651.jpg?1634348819", + "png": "https://cards.scryfall.io/png/front/c/2/c2fb1fff-12be-4bd5-8dba-c36e84d49651.png?1634348819", + "art_crop": "https://cards.scryfall.io/art_crop/front/c/2/c2fb1fff-12be-4bd5-8dba-c36e84d49651.jpg?1634348819", + "border_crop": "https://cards.scryfall.io/border_crop/front/c/2/c2fb1fff-12be-4bd5-8dba-c36e84d49651.jpg?1634348819" + }, + "mana_cost": "{U}", + "cmc": 1, + "type_line": "Instant", + "oracle_text": "Return target creature to its owner's hand. If its mana value was 3 or less, scry 1. (Look at the top card of your library. You may put that card on the bottom of your library.)", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [ + "Scry" + ], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "not_legal", + "vintage": "legal", + "penny": "not_legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "not_legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "arena", + "paper", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": false, + "variation": false, + "set_id": "44b8eb8f-fa23-401a-98b5-1fbb9871128e", + "set": "mid", + "set_name": "Innistrad: Midnight Hunt", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/44b8eb8f-fa23-401a-98b5-1fbb9871128e", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Amid&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/mid?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/c2fb1fff-12be-4bd5-8dba-c36e84d49651/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3A64883ef2-c536-42e2-b52f-cfd1984fcdfd&unique=prints", + "collector_number": "51", + "digital": false, + "rarity": "uncommon", + "flavor_text": "\"At least I won't become one of . . . those things.\"", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Rovina Cai", + "artist_ids": [ + "b64d0979-4028-4409-8285-eec2fa282dd4" + ], + "illustration_id": "a2df9eff-d8e0-43f1-b554-cc67c778517e", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 6268, + "penny_rank": 883, + "preview": { + "source": "Draftism", + "source_uri": "https://draftsim.com/mtg-mid-preview-card-fading-hope/", + "previewed_at": "2021-09-09" + }, + "prices": { + "usd": "0.59", + "usd_foil": "1.31", + "usd_etched": null, + "eur": "0.64", + "eur_foil": "0.85", + "tix": "0.03" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=534812", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Fading+Hope&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Fading+Hope&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Fading+Hope" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/248204?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Fading+Hope&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/93038?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "make disappear": { + "object": "card", + "id": "3f2d6a21-ea77-484b-9e3a-1bd49806f907", + "oracle_id": "5f12f665-f083-48ae-b61a-541051c996ec", + "multiverse_ids": [ + 555250 + ], + "mtgo_id": 98317, + "arena_id": 80200, + "tcgplayer_id": 268455, + "cardmarket_id": 651627, + "name": "Make Disappear", + "lang": "en", + "released_at": "2022-04-29", + "uri": "https://api.scryfall.com/cards/3f2d6a21-ea77-484b-9e3a-1bd49806f907", + "scryfall_uri": "https://scryfall.com/card/snc/49/make-disappear?utm_source=api", + "layout": "normal", + "highres_image": true, + "image_status": "highres_scan", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/3/f/3f2d6a21-ea77-484b-9e3a-1bd49806f907.jpg?1664410347", + "normal": "https://cards.scryfall.io/normal/front/3/f/3f2d6a21-ea77-484b-9e3a-1bd49806f907.jpg?1664410347", + "large": "https://cards.scryfall.io/large/front/3/f/3f2d6a21-ea77-484b-9e3a-1bd49806f907.jpg?1664410347", + "png": "https://cards.scryfall.io/png/front/3/f/3f2d6a21-ea77-484b-9e3a-1bd49806f907.png?1664410347", + "art_crop": "https://cards.scryfall.io/art_crop/front/3/f/3f2d6a21-ea77-484b-9e3a-1bd49806f907.jpg?1664410347", + "border_crop": "https://cards.scryfall.io/border_crop/front/3/f/3f2d6a21-ea77-484b-9e3a-1bd49806f907.jpg?1664410347" + }, + "mana_cost": "{1}{U}", + "cmc": 2, + "type_line": "Instant", + "oracle_text": "Casualty 1 (As you cast this spell, you may sacrifice a creature with power 1 or greater. When you do, copy this spell and you may choose a new target for the copy.)\nCounter target spell unless its controller pays {2}.", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [ + "Casualty" + ], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "legal", + "vintage": "legal", + "penny": "legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "paper", + "mtgo", + "arena" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": false, + "variation": false, + "set_id": "df837242-8c15-42e4-b049-c933a02dc501", + "set": "snc", + "set_name": "Streets of New Capenna", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/df837242-8c15-42e4-b049-c933a02dc501", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Asnc&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/snc?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/3f2d6a21-ea77-484b-9e3a-1bd49806f907/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3A5f12f665-f083-48ae-b61a-541051c996ec&unique=prints", + "collector_number": "49", + "digital": false, + "rarity": "common", + "watermark": "maestros", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Inka Schulz", + "artist_ids": [ + "3f93408e-c510-42a5-beef-9ddbc56d9056" + ], + "illustration_id": "c35ca814-c316-4175-bdad-fafeb0ffc389", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 10517, + "penny_rank": 5063, + "preview": { + "source": "Wizards of the Coast", + "source_uri": "https://www.youtube.com/watch?v=503zQMW2BCA", + "previewed_at": "2022-04-08" + }, + "prices": { + "usd": "0.11", + "usd_foil": "0.43", + "usd_etched": null, + "eur": "0.12", + "eur_foil": "0.14", + "tix": "0.01" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555250", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Make+Disappear&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Make+Disappear&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Make+Disappear" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/268455?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Make+Disappear&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/98317?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "slip out the back": { + "object": "card", + "id": "8725f4c4-fad7-460e-b86c-ff81674f0980", + "oracle_id": "82506e51-3fe1-446f-83c9-69e67583cefc", + "multiverse_ids": [ + 555263 + ], + "mtgo_id": 98343, + "arena_id": 80213, + "tcgplayer_id": 268915, + "cardmarket_id": 652170, + "name": "Slip Out the Back", + "lang": "en", + "released_at": "2022-04-29", + "uri": "https://api.scryfall.com/cards/8725f4c4-fad7-460e-b86c-ff81674f0980", + "scryfall_uri": "https://scryfall.com/card/snc/62/slip-out-the-back?utm_source=api", + "layout": "normal", + "highres_image": true, + "image_status": "highres_scan", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/8/7/8725f4c4-fad7-460e-b86c-ff81674f0980.jpg?1664410598", + "normal": "https://cards.scryfall.io/normal/front/8/7/8725f4c4-fad7-460e-b86c-ff81674f0980.jpg?1664410598", + "large": "https://cards.scryfall.io/large/front/8/7/8725f4c4-fad7-460e-b86c-ff81674f0980.jpg?1664410598", + "png": "https://cards.scryfall.io/png/front/8/7/8725f4c4-fad7-460e-b86c-ff81674f0980.png?1664410598", + "art_crop": "https://cards.scryfall.io/art_crop/front/8/7/8725f4c4-fad7-460e-b86c-ff81674f0980.jpg?1664410598", + "border_crop": "https://cards.scryfall.io/border_crop/front/8/7/8725f4c4-fad7-460e-b86c-ff81674f0980.jpg?1664410598" + }, + "mana_cost": "{U}", + "cmc": 1, + "type_line": "Instant", + "oracle_text": "Put a +1/+1 counter on target creature. It phases out. (Treat it and anything attached to it as though they don't exist until its controller's next turn.)", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "not_legal", + "vintage": "legal", + "penny": "legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "not_legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "paper", + "mtgo", + "arena" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": false, + "variation": false, + "set_id": "df837242-8c15-42e4-b049-c933a02dc501", + "set": "snc", + "set_name": "Streets of New Capenna", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/df837242-8c15-42e4-b049-c933a02dc501", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Asnc&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/snc?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/8725f4c4-fad7-460e-b86c-ff81674f0980/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3A82506e51-3fe1-446f-83c9-69e67583cefc&unique=prints", + "collector_number": "62", + "digital": false, + "rarity": "uncommon", + "flavor_text": "\"I was never here.\"", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Zara Alfonso", + "artist_ids": [ + "329a7971-c37e-47f7-9143-58dc929420a7" + ], + "illustration_id": "4e8d5334-284b-47f2-92a1-6902857a243e", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 2696, + "penny_rank": 95, + "preview": { + "source": "Outpost Ghent", + "source_uri": "https://www.facebook.com/OutpostGhent/posts/2150191685146473", + "previewed_at": "2022-04-14" + }, + "prices": { + "usd": "1.70", + "usd_foil": "1.80", + "usd_etched": null, + "eur": "0.35", + "eur_foil": "0.39", + "tix": "0.01" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555263", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Slip+Out+the+Back&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Slip+Out+the+Back&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Slip+Out+the+Back" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/268915?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Slip+Out+the+Back&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/98343?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "spell pierce": { + "object": "card", + "id": "35b8a9db-d126-4038-abb1-74dcc5b36136", + "oracle_id": "d64b0848-0193-4025-ba62-63ecd8fb9f50", + "multiverse_ids": [ + 571396 + ], + "mtgo_id": 101610, + "tcgplayer_id": 277154, + "cardmarket_id": 665727, + "name": "Spell Pierce", + "lang": "en", + "released_at": "2022-07-08", + "uri": "https://api.scryfall.com/cards/35b8a9db-d126-4038-abb1-74dcc5b36136", + "scryfall_uri": "https://scryfall.com/card/2x2/63/spell-pierce?utm_source=api", + "layout": "normal", + "highres_image": false, + "image_status": "lowres", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/3/5/35b8a9db-d126-4038-abb1-74dcc5b36136.jpg?1662525152", + "normal": "https://cards.scryfall.io/normal/front/3/5/35b8a9db-d126-4038-abb1-74dcc5b36136.jpg?1662525152", + "large": "https://cards.scryfall.io/large/front/3/5/35b8a9db-d126-4038-abb1-74dcc5b36136.jpg?1662525152", + "png": "https://cards.scryfall.io/png/front/3/5/35b8a9db-d126-4038-abb1-74dcc5b36136.png?1662525152", + "art_crop": "https://cards.scryfall.io/art_crop/front/3/5/35b8a9db-d126-4038-abb1-74dcc5b36136.jpg?1662525152", + "border_crop": "https://cards.scryfall.io/border_crop/front/3/5/35b8a9db-d126-4038-abb1-74dcc5b36136.jpg?1662525152" + }, + "mana_cost": "{U}", + "cmc": 1, + "type_line": "Instant", + "oracle_text": "Counter target noncreature spell unless its controller pays {2}.", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "legal", + "vintage": "legal", + "penny": "legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "paper", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": true, + "variation": false, + "set_id": "5a645837-b050-449f-ac90-1e7ccbf45031", + "set": "2x2", + "set_name": "Double Masters 2022", + "set_type": "masters", + "set_uri": "https://api.scryfall.com/sets/5a645837-b050-449f-ac90-1e7ccbf45031", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3A2x2&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/2x2?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/35b8a9db-d126-4038-abb1-74dcc5b36136/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3Ad64b0848-0193-4025-ba62-63ecd8fb9f50&unique=prints", + "collector_number": "63", + "digital": false, + "rarity": "common", + "flavor_text": "\"There's a hole in your plan.\"\n—Noyan Dar, Tazeem lullmage", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Vance Kovacs", + "artist_ids": [ + "b5516011-4722-4fc8-8542-102cecc52b71" + ], + "illustration_id": "4bdf8068-d062-4205-882c-d4fcd0878c1f", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 702, + "penny_rank": 63, + "preview": { + "source": "Wizards of the Coast", + "source_uri": "https://www.twitch.tv/videos/1512208234", + "previewed_at": "2022-06-23" + }, + "prices": { + "usd": "0.09", + "usd_foil": "0.23", + "usd_etched": null, + "eur": "0.19", + "eur_foil": "0.17", + "tix": "0.03" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=571396", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Spell+Pierce&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Spell+Pierce&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Spell+Pierce" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/277154?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Spell+Pierce&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/101610?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "thirst for discovery": { + "object": "card", + "id": "1ea179e9-9c0d-46c1-9ee8-60be68e1f79c", + "oracle_id": "1e05e6ef-14af-451d-9d54-e75b1f8871ab", + "multiverse_ids": [ + 540929 + ], + "mtgo_id": 94486, + "arena_id": 78877, + "tcgplayer_id": 253462, + "cardmarket_id": 582110, + "name": "Thirst for Discovery", + "lang": "en", + "released_at": "2021-11-19", + "uri": "https://api.scryfall.com/cards/1ea179e9-9c0d-46c1-9ee8-60be68e1f79c", + "scryfall_uri": "https://scryfall.com/card/vow/85/thirst-for-discovery?utm_source=api", + "layout": "normal", + "highres_image": true, + "image_status": "highres_scan", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/1/e/1ea179e9-9c0d-46c1-9ee8-60be68e1f79c.jpg?1643588791", + "normal": "https://cards.scryfall.io/normal/front/1/e/1ea179e9-9c0d-46c1-9ee8-60be68e1f79c.jpg?1643588791", + "large": "https://cards.scryfall.io/large/front/1/e/1ea179e9-9c0d-46c1-9ee8-60be68e1f79c.jpg?1643588791", + "png": "https://cards.scryfall.io/png/front/1/e/1ea179e9-9c0d-46c1-9ee8-60be68e1f79c.png?1643588791", + "art_crop": "https://cards.scryfall.io/art_crop/front/1/e/1ea179e9-9c0d-46c1-9ee8-60be68e1f79c.jpg?1643588791", + "border_crop": "https://cards.scryfall.io/border_crop/front/1/e/1ea179e9-9c0d-46c1-9ee8-60be68e1f79c.jpg?1643588791" + }, + "mana_cost": "{2}{U}", + "cmc": 3, + "type_line": "Instant", + "oracle_text": "Draw three cards. Then discard two cards unless you discard a basic land card.", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "not_legal", + "vintage": "legal", + "penny": "not_legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "not_legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "arena", + "paper", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": false, + "variation": false, + "set_id": "8144b676-569f-4716-8005-bc8f0778f3fa", + "set": "vow", + "set_name": "Innistrad: Crimson Vow", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/8144b676-569f-4716-8005-bc8f0778f3fa", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Avow&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/vow?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/1ea179e9-9c0d-46c1-9ee8-60be68e1f79c/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3A1e05e6ef-14af-451d-9d54-e75b1f8871ab&unique=prints", + "collector_number": "85", + "digital": false, + "rarity": "uncommon", + "flavor_text": "\"This is your only warning, alchemist. The secrets of the sea are not yours to behold. Lord Krothuss will not be so merciful next time.\"\n—Runo Stromkirk", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Dominik Mayer", + "artist_ids": [ + "c3439c4a-1fee-4e33-9b89-18dac27ac927" + ], + "illustration_id": "5a732850-8e83-41c9-9bc3-94d84c74b348", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 2848, + "penny_rank": 237, + "preview": { + "source": "AusGamers", + "source_uri": "https://www.ausgamers.com/news/read/3638231/magic-the-gathering-latest-set-is-all-about-vampires", + "previewed_at": "2021-11-02" + }, + "prices": { + "usd": "0.16", + "usd_foil": "0.67", + "usd_etched": null, + "eur": "0.16", + "eur_foil": "0.16", + "tix": "0.03" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=540929", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Thirst+for+Discovery&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Thirst+for+Discovery&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Thirst+for+Discovery" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/253462?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Thirst+for+Discovery&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/94486?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "island": { + "object": "card", + "id": "8bafc217-3d83-4551-b2e3-3494ec14b2f9", + "oracle_id": "b2c6aa39-2d2a-459c-a555-fb48ba993373", + "multiverse_ids": [ + 578549 + ], + "mtgo_id": 102406, + "arena_id": 82317, + "tcgplayer_id": 283078, + "cardmarket_id": 671639, + "name": "Island", + "lang": "en", + "released_at": "2022-09-09", + "uri": "https://api.scryfall.com/cards/8bafc217-3d83-4551-b2e3-3494ec14b2f9", + "scryfall_uri": "https://scryfall.com/card/dmu/265/island?utm_source=api", + "layout": "normal", + "highres_image": false, + "image_status": "lowres", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/8/b/8bafc217-3d83-4551-b2e3-3494ec14b2f9.jpg?1663052401", + "normal": "https://cards.scryfall.io/normal/front/8/b/8bafc217-3d83-4551-b2e3-3494ec14b2f9.jpg?1663052401", + "large": "https://cards.scryfall.io/large/front/8/b/8bafc217-3d83-4551-b2e3-3494ec14b2f9.jpg?1663052401", + "png": "https://cards.scryfall.io/png/front/8/b/8bafc217-3d83-4551-b2e3-3494ec14b2f9.png?1663052401", + "art_crop": "https://cards.scryfall.io/art_crop/front/8/b/8bafc217-3d83-4551-b2e3-3494ec14b2f9.jpg?1663052401", + "border_crop": "https://cards.scryfall.io/border_crop/front/8/b/8bafc217-3d83-4551-b2e3-3494ec14b2f9.jpg?1663052401" + }, + "mana_cost": "", + "cmc": 0, + "type_line": "Basic Land — Island", + "oracle_text": "({T}: Add {U}.)", + "colors": [], + "color_identity": [ + "U" + ], + "keywords": [], + "produced_mana": [ + "U" + ], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "legal", + "vintage": "legal", + "penny": "legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "legal" + }, + "games": [ + "paper", + "arena", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": true, + "variation": false, + "set_id": "4e47a6cd-cdeb-4b0f-8f24-cfe1a0127cb3", + "set": "dmu", + "set_name": "Dominaria United", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/4e47a6cd-cdeb-4b0f-8f24-cfe1a0127cb3", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Admu&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/dmu?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/8bafc217-3d83-4551-b2e3-3494ec14b2f9/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3Ab2c6aa39-2d2a-459c-a555-fb48ba993373&unique=prints", + "collector_number": "265", + "digital": false, + "rarity": "common", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Seb McKinnon", + "artist_ids": [ + "ad4caca0-8d89-44ce-a1a6-d5ca905bd6fb" + ], + "illustration_id": "f04d55be-9919-47d7-bae3-83b73afba109", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "prices": { + "usd": "0.09", + "usd_foil": "0.18", + "usd_etched": null, + "eur": "0.04", + "eur_foil": "0.09", + "tix": "0.01" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=578549", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Island&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Island&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Island" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/283078?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Island&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/102406?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "otawara, soaring city": { + "object": "card", + "id": "486d7edc-d983-41f0-8b78-c99aecd72996", + "oracle_id": "e9b6a394-691c-425a-9307-76d8edc7375e", + "multiverse_ids": [ + 548584 + ], + "mtgo_id": 97492, + "arena_id": 79711, + "tcgplayer_id": 262434, + "cardmarket_id": 607514, + "name": "Otawara, Soaring City", + "lang": "en", + "released_at": "2022-02-18", + "uri": "https://api.scryfall.com/cards/486d7edc-d983-41f0-8b78-c99aecd72996", + "scryfall_uri": "https://scryfall.com/card/neo/271/otawara-soaring-city?utm_source=api", + "layout": "normal", + "highres_image": true, + "image_status": "highres_scan", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/4/8/486d7edc-d983-41f0-8b78-c99aecd72996.jpg?1654568960", + "normal": "https://cards.scryfall.io/normal/front/4/8/486d7edc-d983-41f0-8b78-c99aecd72996.jpg?1654568960", + "large": "https://cards.scryfall.io/large/front/4/8/486d7edc-d983-41f0-8b78-c99aecd72996.jpg?1654568960", + "png": "https://cards.scryfall.io/png/front/4/8/486d7edc-d983-41f0-8b78-c99aecd72996.png?1654568960", + "art_crop": "https://cards.scryfall.io/art_crop/front/4/8/486d7edc-d983-41f0-8b78-c99aecd72996.jpg?1654568960", + "border_crop": "https://cards.scryfall.io/border_crop/front/4/8/486d7edc-d983-41f0-8b78-c99aecd72996.jpg?1654568960" + }, + "mana_cost": "", + "cmc": 0, + "type_line": "Legendary Land", + "oracle_text": "{T}: Add {U}.\nChannel — {3}{U}, Discard Otawara, Soaring City: Return target artifact, creature, enchantment, or planeswalker to its owner's hand. This ability costs {1} less to activate for each legendary creature you control.", + "colors": [], + "color_identity": [ + "U" + ], + "keywords": [ + "Channel" + ], + "produced_mana": [ + "U" + ], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "not_legal", + "vintage": "legal", + "penny": "not_legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "not_legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "paper", + "mtgo", + "arena" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": false, + "variation": false, + "set_id": "59a2059f-5482-433f-8761-eb2e17859b71", + "set": "neo", + "set_name": "Kamigawa: Neon Dynasty", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/59a2059f-5482-433f-8761-eb2e17859b71", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Aneo&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/neo?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/486d7edc-d983-41f0-8b78-c99aecd72996/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3Ae9b6a394-691c-425a-9307-76d8edc7375e&unique=prints", + "collector_number": "271", + "digital": false, + "rarity": "rare", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Alayna Danner", + "artist_ids": [ + "bb677b1a-ce51-4888-83d6-5a94de461ff9" + ], + "illustration_id": "92355104-5745-4012-b903-7f5be8699b78", + "border_color": "black", + "frame": "2015", + "frame_effects": [ + "legendary" + ], + "security_stamp": "oval", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 264, + "preview": { + "source": "Wizards of the Coast", + "source_uri": "https://twitter.com/mtgjp/status/1488067025477849094", + "previewed_at": "2022-01-31" + }, + "prices": { + "usd": "12.74", + "usd_foil": "13.11", + "usd_etched": null, + "eur": "15.51", + "eur_foil": "18.50", + "tix": "14.22" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=548584", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Otawara%2C+Soaring+City&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Otawara%2C+Soaring+City&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Otawara%2C+Soaring+City" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/262434?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Otawara%2C+Soaring+City&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/97492?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "otherworldly gaze": { + "object": "card", + "id": "9cebee20-869e-45ed-9ddc-843faf4032ad", + "oracle_id": "be668c2d-71ea-4346-8980-1fbf5e4cbed3", + "multiverse_ids": [ + 534831 + ], + "mtgo_id": 93076, + "arena_id": 78402, + "tcgplayer_id": 248292, + "cardmarket_id": 575026, + "name": "Otherworldly Gaze", + "lang": "en", + "released_at": "2021-09-24", + "uri": "https://api.scryfall.com/cards/9cebee20-869e-45ed-9ddc-843faf4032ad", + "scryfall_uri": "https://scryfall.com/card/mid/67/otherworldly-gaze?utm_source=api", + "layout": "normal", + "highres_image": true, + "image_status": "highres_scan", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/9/c/9cebee20-869e-45ed-9ddc-843faf4032ad.jpg?1634349134", + "normal": "https://cards.scryfall.io/normal/front/9/c/9cebee20-869e-45ed-9ddc-843faf4032ad.jpg?1634349134", + "large": "https://cards.scryfall.io/large/front/9/c/9cebee20-869e-45ed-9ddc-843faf4032ad.jpg?1634349134", + "png": "https://cards.scryfall.io/png/front/9/c/9cebee20-869e-45ed-9ddc-843faf4032ad.png?1634349134", + "art_crop": "https://cards.scryfall.io/art_crop/front/9/c/9cebee20-869e-45ed-9ddc-843faf4032ad.jpg?1634349134", + "border_crop": "https://cards.scryfall.io/border_crop/front/9/c/9cebee20-869e-45ed-9ddc-843faf4032ad.jpg?1634349134" + }, + "mana_cost": "{U}", + "cmc": 1, + "type_line": "Instant", + "oracle_text": "Look at the top three cards of your library. Put any number of them into your graveyard and the rest back on top of your library in any order.\nFlashback {1}{U} (You may cast this card from your graveyard for its flashback cost. Then exile it.)", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [ + "Flashback" + ], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "legal", + "vintage": "legal", + "penny": "not_legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "arena", + "paper", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": false, + "variation": false, + "set_id": "44b8eb8f-fa23-401a-98b5-1fbb9871128e", + "set": "mid", + "set_name": "Innistrad: Midnight Hunt", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/44b8eb8f-fa23-401a-98b5-1fbb9871128e", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Amid&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/mid?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/9cebee20-869e-45ed-9ddc-843faf4032ad/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3Abe668c2d-71ea-4346-8980-1fbf5e4cbed3&unique=prints", + "collector_number": "67", + "digital": false, + "rarity": "common", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Chris Cold", + "artist_ids": [ + "2622d22b-3fd8-4831-9b2b-adc5fac01b85" + ], + "illustration_id": "a59f90c6-e808-4df2-971e-ed9c1b481f27", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 3046, + "penny_rank": 1849, + "prices": { + "usd": "0.24", + "usd_foil": "3.66", + "usd_etched": null, + "eur": "0.24", + "eur_foil": "1.49", + "tix": "0.03" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=534831", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Otherworldly+Gaze&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Otherworldly+Gaze&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Otherworldly+Gaze" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/248292?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Otherworldly+Gaze&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/93076?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "reckoner bankbuster": { + "object": "card", + "id": "279acd17-6c17-427b-a69d-fc02442ff4a3", + "oracle_id": "b6be94dc-7162-4887-b959-3bda709724eb", + "multiverse_ids": [ + 548568 + ], + "mtgo_id": 97460, + "arena_id": 79695, + "tcgplayer_id": 262560, + "cardmarket_id": 607578, + "name": "Reckoner Bankbuster", + "lang": "en", + "released_at": "2022-02-18", + "uri": "https://api.scryfall.com/cards/279acd17-6c17-427b-a69d-fc02442ff4a3", + "scryfall_uri": "https://scryfall.com/card/neo/255/reckoner-bankbuster?utm_source=api", + "layout": "normal", + "highres_image": true, + "image_status": "highres_scan", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/2/7/279acd17-6c17-427b-a69d-fc02442ff4a3.jpg?1654568798", + "normal": "https://cards.scryfall.io/normal/front/2/7/279acd17-6c17-427b-a69d-fc02442ff4a3.jpg?1654568798", + "large": "https://cards.scryfall.io/large/front/2/7/279acd17-6c17-427b-a69d-fc02442ff4a3.jpg?1654568798", + "png": "https://cards.scryfall.io/png/front/2/7/279acd17-6c17-427b-a69d-fc02442ff4a3.png?1654568798", + "art_crop": "https://cards.scryfall.io/art_crop/front/2/7/279acd17-6c17-427b-a69d-fc02442ff4a3.jpg?1654568798", + "border_crop": "https://cards.scryfall.io/border_crop/front/2/7/279acd17-6c17-427b-a69d-fc02442ff4a3.jpg?1654568798" + }, + "mana_cost": "{2}", + "cmc": 2, + "type_line": "Artifact — Vehicle", + "oracle_text": "Reckoner Bankbuster enters the battlefield with three charge counters on it.\n{2}, {T}, Remove a charge counter from Reckoner Bankbuster: Draw a card. Then if there are no charge counters on Reckoner Bankbuster, create a Treasure token and a 1/1 colorless Pilot creature token with \"This creature crews Vehicles as though its power were 2 greater.\"\nCrew 3", + "power": "4", + "toughness": "4", + "colors": [], + "color_identity": [], + "keywords": [ + "Crew" + ], + "all_parts": [ + { + "object": "related_card", + "id": "72c22b76-3411-4ef3-8a3d-3931ff993b24", + "component": "token", + "name": "Treasure", + "type_line": "Token Artifact — Treasure", + "uri": "https://api.scryfall.com/cards/72c22b76-3411-4ef3-8a3d-3931ff993b24" + }, + { + "object": "related_card", + "id": "be84f259-2809-48c9-9c70-861437f08c23", + "component": "token", + "name": "Pilot", + "type_line": "Token Creature — Pilot", + "uri": "https://api.scryfall.com/cards/be84f259-2809-48c9-9c70-861437f08c23" + }, + { + "object": "related_card", + "id": "29e4c9a1-35c3-4063-b1ae-a9934f778fdd", + "component": "combo_piece", + "name": "Reckoner Bankbuster", + "type_line": "Artifact — Vehicle", + "uri": "https://api.scryfall.com/cards/29e4c9a1-35c3-4063-b1ae-a9934f778fdd" + } + ], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "not_legal", + "vintage": "legal", + "penny": "not_legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "not_legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "paper", + "mtgo", + "arena" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": false, + "variation": false, + "set_id": "59a2059f-5482-433f-8761-eb2e17859b71", + "set": "neo", + "set_name": "Kamigawa: Neon Dynasty", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/59a2059f-5482-433f-8761-eb2e17859b71", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Aneo&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/neo?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/279acd17-6c17-427b-a69d-fc02442ff4a3/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3Ab6be94dc-7162-4887-b959-3bda709724eb&unique=prints", + "collector_number": "255", + "digital": false, + "rarity": "rare", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Steve Prescott", + "artist_ids": [ + "a1139fb8-41f5-4a9e-9a74-f662e1a23b35" + ], + "illustration_id": "b8e3a577-b786-4c41-bd2f-66acecda84e0", + "border_color": "black", + "frame": "2015", + "security_stamp": "oval", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 2855, + "preview": { + "source": "Dot Esports", + "source_uri": "https://dotesports.com/mtg/news/reckoner-bankbuster-charges-up-vehicles-in-kamigawa-neon-dynasty", + "previewed_at": "2022-02-01" + }, + "prices": { + "usd": "3.93", + "usd_foil": "2.50", + "usd_etched": null, + "eur": "0.78", + "eur_foil": "0.64", + "tix": "1.89" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=548568", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Reckoner+Bankbuster&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Reckoner+Bankbuster&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Reckoner+Bankbuster" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/262560?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Reckoner+Bankbuster&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/97460?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "disdainful stroke": { + "object": "card", + "id": "492aa24c-61c4-48bc-b7b7-f423be2662da", + "oracle_id": "11e02134-7b1a-46a4-a89e-7539dd1efada", + "multiverse_ids": [ + 555240 + ], + "mtgo_id": 98297, + "arena_id": 80190, + "tcgplayer_id": 268769, + "cardmarket_id": 651834, + "name": "Disdainful Stroke", + "lang": "en", + "released_at": "2022-04-29", + "uri": "https://api.scryfall.com/cards/492aa24c-61c4-48bc-b7b7-f423be2662da", + "scryfall_uri": "https://scryfall.com/card/snc/39/disdainful-stroke?utm_source=api", + "layout": "normal", + "highres_image": true, + "image_status": "highres_scan", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/4/9/492aa24c-61c4-48bc-b7b7-f423be2662da.jpg?1664410153", + "normal": "https://cards.scryfall.io/normal/front/4/9/492aa24c-61c4-48bc-b7b7-f423be2662da.jpg?1664410153", + "large": "https://cards.scryfall.io/large/front/4/9/492aa24c-61c4-48bc-b7b7-f423be2662da.jpg?1664410153", + "png": "https://cards.scryfall.io/png/front/4/9/492aa24c-61c4-48bc-b7b7-f423be2662da.png?1664410153", + "art_crop": "https://cards.scryfall.io/art_crop/front/4/9/492aa24c-61c4-48bc-b7b7-f423be2662da.jpg?1664410153", + "border_crop": "https://cards.scryfall.io/border_crop/front/4/9/492aa24c-61c4-48bc-b7b7-f423be2662da.jpg?1664410153" + }, + "mana_cost": "{1}{U}", + "cmc": 2, + "type_line": "Instant", + "oracle_text": "Counter target spell with mana value 4 or greater.", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "legal", + "vintage": "legal", + "penny": "legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "paper", + "mtgo", + "arena" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": true, + "variation": false, + "set_id": "df837242-8c15-42e4-b049-c933a02dc501", + "set": "snc", + "set_name": "Streets of New Capenna", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/df837242-8c15-42e4-b049-c933a02dc501", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Asnc&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/snc?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/492aa24c-61c4-48bc-b7b7-f423be2662da/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3A11e02134-7b1a-46a4-a89e-7539dd1efada&unique=prints", + "collector_number": "39", + "digital": false, + "rarity": "common", + "flavor_text": "\"I've known for a year that you would cast this exact spell, at this exact spot, at this exact time.\"\n—Raffine", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Irina Nordsol", + "artist_ids": [ + "1e4cb52d-476e-4c68-ac87-2e620aede6d4" + ], + "illustration_id": "3c733048-9a4d-446b-9248-44b3e47592f5", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 1537, + "penny_rank": 3384, + "preview": { + "source": "Pokde.net", + "source_uri": "https://pokde.net/gaming/esports/mtg-streets-of-new-capenna-disdainful-stroke-card-preview", + "previewed_at": "2022-04-13" + }, + "prices": { + "usd": "0.09", + "usd_foil": "0.10", + "usd_etched": null, + "eur": "0.05", + "eur_foil": "0.11", + "tix": "0.01" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555240", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Disdainful+Stroke&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Disdainful+Stroke&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Disdainful+Stroke" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/268769?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Disdainful+Stroke&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/98297?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "negate": { + "object": "card", + "id": "4016c6f7-7cb4-46c2-af73-3bd6d682ea5e", + "oracle_id": "3407fe41-fdd3-4119-8f70-4bc4590a379f", + "multiverse_ids": [ + 574538 + ], + "mtgo_id": 102592, + "arena_id": 82110, + "tcgplayer_id": 283488, + "cardmarket_id": 672344, + "name": "Negate", + "lang": "en", + "released_at": "2022-09-09", + "uri": "https://api.scryfall.com/cards/4016c6f7-7cb4-46c2-af73-3bd6d682ea5e", + "scryfall_uri": "https://scryfall.com/card/dmu/58/negate?utm_source=api", + "layout": "normal", + "highres_image": false, + "image_status": "lowres", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/4/0/4016c6f7-7cb4-46c2-af73-3bd6d682ea5e.jpg?1663048006", + "normal": "https://cards.scryfall.io/normal/front/4/0/4016c6f7-7cb4-46c2-af73-3bd6d682ea5e.jpg?1663048006", + "large": "https://cards.scryfall.io/large/front/4/0/4016c6f7-7cb4-46c2-af73-3bd6d682ea5e.jpg?1663048006", + "png": "https://cards.scryfall.io/png/front/4/0/4016c6f7-7cb4-46c2-af73-3bd6d682ea5e.png?1663048006", + "art_crop": "https://cards.scryfall.io/art_crop/front/4/0/4016c6f7-7cb4-46c2-af73-3bd6d682ea5e.jpg?1663048006", + "border_crop": "https://cards.scryfall.io/border_crop/front/4/0/4016c6f7-7cb4-46c2-af73-3bd6d682ea5e.jpg?1663048006" + }, + "mana_cost": "{1}{U}", + "cmc": 2, + "type_line": "Instant", + "oracle_text": "Counter target noncreature spell.", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "legal", + "vintage": "legal", + "penny": "legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "paper", + "arena", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": true, + "variation": false, + "set_id": "4e47a6cd-cdeb-4b0f-8f24-cfe1a0127cb3", + "set": "dmu", + "set_name": "Dominaria United", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/4e47a6cd-cdeb-4b0f-8f24-cfe1a0127cb3", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Admu&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/dmu?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/4016c6f7-7cb4-46c2-af73-3bd6d682ea5e/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3A3407fe41-fdd3-4119-8f70-4bc4590a379f&unique=prints", + "collector_number": "58", + "digital": false, + "rarity": "common", + "flavor_text": "\"It's frustrating, isn't it, to be so weak and ineffectual? Don't worry, you'll be *compleat* soon enough.\"\n—Rona", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Isis", + "artist_ids": [ + "4d12227a-8657-48b7-884a-ff70cc6428a5" + ], + "illustration_id": "6f303eef-623f-4a31-8383-ad0a3142557e", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 48, + "penny_rank": 221, + "preview": { + "source": "Duniaku", + "source_uri": "https://duniaku.idntimes.com/geek/mainan/aditya-daniel/penasaran-dengan-kartu-mtg-dominaria-united-ini-preview-nya", + "previewed_at": "2022-08-24" + }, + "prices": { + "usd": "0.09", + "usd_foil": "0.11", + "usd_etched": null, + "eur": "0.06", + "eur_foil": "0.06", + "tix": "0.01" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=574538", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Negate&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Negate&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Negate" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/283488?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Negate&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/102592?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "out of the way": { + "object": "card", + "id": "2201ade5-8add-49f2-8045-ae351aaf061c", + "oracle_id": "9300874a-32a9-4869-b3e1-1b996403df4e", + "multiverse_ids": [ + 555253 + ], + "mtgo_id": 98323, + "arena_id": 80203, + "tcgplayer_id": 268549, + "cardmarket_id": 652090, + "name": "Out of the Way", + "lang": "en", + "released_at": "2022-04-29", + "uri": "https://api.scryfall.com/cards/2201ade5-8add-49f2-8045-ae351aaf061c", + "scryfall_uri": "https://scryfall.com/card/snc/52/out-of-the-way?utm_source=api", + "layout": "normal", + "highres_image": true, + "image_status": "highres_scan", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/2/2/2201ade5-8add-49f2-8045-ae351aaf061c.jpg?1664410401", + "normal": "https://cards.scryfall.io/normal/front/2/2/2201ade5-8add-49f2-8045-ae351aaf061c.jpg?1664410401", + "large": "https://cards.scryfall.io/large/front/2/2/2201ade5-8add-49f2-8045-ae351aaf061c.jpg?1664410401", + "png": "https://cards.scryfall.io/png/front/2/2/2201ade5-8add-49f2-8045-ae351aaf061c.png?1664410401", + "art_crop": "https://cards.scryfall.io/art_crop/front/2/2/2201ade5-8add-49f2-8045-ae351aaf061c.jpg?1664410401", + "border_crop": "https://cards.scryfall.io/border_crop/front/2/2/2201ade5-8add-49f2-8045-ae351aaf061c.jpg?1664410401" + }, + "mana_cost": "{3}{U}", + "cmc": 4, + "type_line": "Instant", + "oracle_text": "This spell costs {2} less to cast if it targets a green permanent.\nReturn target nonland permanent an opponent controls to its owner's hand.\nDraw a card.", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "not_legal", + "vintage": "legal", + "penny": "legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "not_legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "paper", + "mtgo", + "arena" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": false, + "variation": false, + "set_id": "df837242-8c15-42e4-b049-c933a02dc501", + "set": "snc", + "set_name": "Streets of New Capenna", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/df837242-8c15-42e4-b049-c933a02dc501", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Asnc&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/snc?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/2201ade5-8add-49f2-8045-ae351aaf061c/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3A9300874a-32a9-4869-b3e1-1b996403df4e&unique=prints", + "collector_number": "52", + "digital": false, + "rarity": "uncommon", + "flavor_text": "\"You bore me.\"", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Tony Foti", + "artist_ids": [ + "1ab97a5f-9abb-42f4-bbc4-954899619d6f" + ], + "illustration_id": "1e939f1b-d1fe-4e2f-9f1e-a48228337c35", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": false, + "edhrec_rank": 16466, + "preview": { + "source": "The Dive Down", + "source_uri": "https://twitter.com/TheDiveDown/status/1513524003541073924", + "previewed_at": "2022-04-11" + }, + "prices": { + "usd": "0.05", + "usd_foil": "0.06", + "usd_etched": null, + "eur": "0.05", + "eur_foil": "0.07", + "tix": "0.01" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555253", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Out+of+the+Way&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Out+of+the+Way&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Out+of+the+Way" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/268549?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Out+of+the+Way&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/98323?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + }, + "ertai's scorn": { + "object": "card", + "id": "6129b0d3-b50a-4a4b-9111-39f8fc6718dd", + "oracle_id": "76e6c0e7-593a-4b4a-9eb6-a912f9c3f26f", + "multiverse_ids": [ + 574528 + ], + "mtgo_id": 102572, + "arena_id": 82100, + "tcgplayer_id": 283606, + "cardmarket_id": 672651, + "name": "Ertai's Scorn", + "lang": "en", + "released_at": "2022-09-09", + "uri": "https://api.scryfall.com/cards/6129b0d3-b50a-4a4b-9111-39f8fc6718dd", + "scryfall_uri": "https://scryfall.com/card/dmu/48/ertais-scorn?utm_source=api", + "layout": "normal", + "highres_image": false, + "image_status": "lowres", + "image_uris": { + "small": "https://cards.scryfall.io/small/front/6/1/6129b0d3-b50a-4a4b-9111-39f8fc6718dd.jpg?1663047809", + "normal": "https://cards.scryfall.io/normal/front/6/1/6129b0d3-b50a-4a4b-9111-39f8fc6718dd.jpg?1663047809", + "large": "https://cards.scryfall.io/large/front/6/1/6129b0d3-b50a-4a4b-9111-39f8fc6718dd.jpg?1663047809", + "png": "https://cards.scryfall.io/png/front/6/1/6129b0d3-b50a-4a4b-9111-39f8fc6718dd.png?1663047809", + "art_crop": "https://cards.scryfall.io/art_crop/front/6/1/6129b0d3-b50a-4a4b-9111-39f8fc6718dd.jpg?1663047809", + "border_crop": "https://cards.scryfall.io/border_crop/front/6/1/6129b0d3-b50a-4a4b-9111-39f8fc6718dd.jpg?1663047809" + }, + "mana_cost": "{1}{U}{U}", + "cmc": 3, + "type_line": "Instant", + "oracle_text": "This spell costs {U} less to cast if an opponent cast two or more spells this turn.\nCounter target spell.", + "colors": [ + "U" + ], + "color_identity": [ + "U" + ], + "keywords": [], + "legalities": { + "standard": "legal", + "future": "legal", + "historic": "legal", + "gladiator": "legal", + "pioneer": "legal", + "explorer": "legal", + "modern": "legal", + "legacy": "legal", + "pauper": "not_legal", + "vintage": "legal", + "penny": "legal", + "commander": "legal", + "brawl": "legal", + "historicbrawl": "legal", + "alchemy": "legal", + "paupercommander": "not_legal", + "duel": "legal", + "oldschool": "not_legal", + "premodern": "not_legal" + }, + "games": [ + "paper", + "arena", + "mtgo" + ], + "reserved": false, + "foil": true, + "nonfoil": true, + "finishes": [ + "nonfoil", + "foil" + ], + "oversized": false, + "promo": false, + "reprint": false, + "variation": false, + "set_id": "4e47a6cd-cdeb-4b0f-8f24-cfe1a0127cb3", + "set": "dmu", + "set_name": "Dominaria United", + "set_type": "expansion", + "set_uri": "https://api.scryfall.com/sets/4e47a6cd-cdeb-4b0f-8f24-cfe1a0127cb3", + "set_search_uri": "https://api.scryfall.com/cards/search?order=set&q=e%3Admu&unique=prints", + "scryfall_set_uri": "https://scryfall.com/sets/dmu?utm_source=api", + "rulings_uri": "https://api.scryfall.com/cards/6129b0d3-b50a-4a4b-9111-39f8fc6718dd/rulings", + "prints_search_uri": "https://api.scryfall.com/cards/search?order=released&q=oracleid%3A76e6c0e7-593a-4b4a-9eb6-a912f9c3f26f&unique=prints", + "collector_number": "48", + "digital": false, + "rarity": "uncommon", + "flavor_text": "\"You're not so special, Karn. Anything that has been assembled can be disassembled.\"", + "card_back_id": "0aeebaf5-8c7d-4636-9e82-8c27447861f7", + "artist": "Alex Negrea", + "artist_ids": [ + "fbfc9dde-935f-4b2f-a0e3-bcec89809f6d" + ], + "illustration_id": "b3afc541-1063-44ae-a975-d2f4550ab7db", + "border_color": "black", + "frame": "2015", + "full_art": false, + "textless": false, + "booster": true, + "story_spotlight": true, + "edhrec_rank": 13000, + "penny_rank": 8945, + "prices": { + "usd": "0.13", + "usd_foil": "0.30", + "usd_etched": null, + "eur": "0.18", + "eur_foil": "0.15", + "tix": "0.01" + }, + "related_uris": { + "gatherer": "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=574528", + "tcgplayer_infinite_articles": "https://infinite.tcgplayer.com/search?contentMode=article&game=magic&partner=scryfall&q=Ertai%27s+Scorn&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "tcgplayer_infinite_decks": "https://infinite.tcgplayer.com/search?contentMode=deck&game=magic&partner=scryfall&q=Ertai%27s+Scorn&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "edhrec": "https://edhrec.com/route/?cc=Ertai%27s+Scorn" + }, + "purchase_uris": { + "tcgplayer": "https://www.tcgplayer.com/product/283606?page=1&utm_campaign=affiliate&utm_medium=api&utm_source=scryfall", + "cardmarket": "https://www.cardmarket.com/en/Magic/Products/Search?referrer=scryfall&searchString=Ertai%27s+Scorn&utm_campaign=card_prices&utm_medium=text&utm_source=scryfall", + "cardhoarder": "https://www.cardhoarder.com/cards/102572?affiliate_id=scryfall&ref=card-profile&utm_campaign=affiliate&utm_medium=card&utm_source=scryfall" + } + } +} \ No newline at end of file diff --git a/jest/globalSetup.ts b/jest/globalSetup.ts new file mode 100644 index 0000000..c93f4d8 --- /dev/null +++ b/jest/globalSetup.ts @@ -0,0 +1,22 @@ +import * as util from 'util' + +import { jest } from "@jest/globals"; + +// Mock http library to avoid using "obsidian" import +jest.mock('../src/http', () => { + return { + promiseWrappedRequest: (options: any) => Promise.resolve({} as any) + } +}); + +// ref: https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom +// ref: https://github.com/jsdom/jsdom/issues/2524 +Object.defineProperty(window, 'TextEncoder', { + writable: true, + value: util.TextEncoder +}); + +Object.defineProperty(window, 'TextDecoder', { + writable: true, + value: util.TextDecoder +}); \ No newline at end of file diff --git a/main.ts b/main.ts new file mode 100644 index 0000000..c38bb6a --- /dev/null +++ b/main.ts @@ -0,0 +1,232 @@ +import { App, Plugin, PluginSettingTab, Setting } from "obsidian"; +import { + DEFAULT_COLLECTION_COUNT_COLUMN, + DEFAULT_COLLECTION_FILE_EXTENSION, + DEFAULT_COLLECTION_NAME_COLUMN, + DEFAULT_COLLECTION_SYNC_INTERVAL, + syncCounts, +} from "src/collection"; +import { renderDecklist } from "src/renderer"; +import { ObsidianPluginMtgSettings } from "src/settings"; + +const DEFAULT_SETTINGS: ObsidianPluginMtgSettings = { + collection: { + fileExtension: DEFAULT_COLLECTION_FILE_EXTENSION, + nameColumn: DEFAULT_COLLECTION_NAME_COLUMN, + countColumn: DEFAULT_COLLECTION_COUNT_COLUMN, + syncIntervalMs: DEFAULT_COLLECTION_SYNC_INTERVAL, + }, + decklist: { + preferredCurrency: "usd", + showCardNamesAsHyperlinks: true, + showCardPreviews: true, + showBuylist: true, + hidePrices: false, + }, +}; + +export default class ObsidianPluginMtg extends Plugin { + settings: ObsidianPluginMtgSettings; + + // This keeps a record of the collection in memory + cardCounts: Record; + + async onload() { + await this.loadSettings(); + + // This adds a settings tab so the user can configure various aspects of the plugin + this.addSettingTab(new ObsidianPluginMtgSettingsTab(this.app, this)); + + const { vault } = this.app; + + vault.on("modify", async (f) => { + if (f.name.endsWith(".csv")) { + const settings = this.settings; + const collectionFileExt = + settings.collection?.fileExtension || ""; + if (f.name.endsWith(collectionFileExt)) { + this.cardCounts = await syncCounts(vault, settings); + } + } + }); + + this.app.workspace.onLayoutReady(async () => { + this.cardCounts = await syncCounts(vault, this.settings); + }); + + this.registerMarkdownCodeBlockProcessor( + "mtg-deck", + async (source: string, el: HTMLElement, ctx) => { + let error = null; + + // Sync card counts once if they haven't been already + if (!this.cardCounts) { + this.cardCounts = await syncCounts(vault, this.settings); + } + + try { + await renderDecklist( + el, + source, + this.cardCounts, + this.settings + ); + } catch (err) { + error = err; + console.log(err); + const errorNode = document.createDiv({ + text: error, + cls: "obsidian-plugin-mtg-error", + }); + el.appendChild(errorNode); + } + } + ); + } + + onunload() {} + + async loadSettings() { + this.settings = Object.assign( + {}, + DEFAULT_SETTINGS, + await this.loadData() + ); + } + + async saveSettings() { + await this.saveData(this.settings); + } +} + +class ObsidianPluginMtgSettingsTab extends PluginSettingTab { + plugin: ObsidianPluginMtg; + + constructor(app: App, plugin: ObsidianPluginMtg) { + super(app, plugin); + this.plugin = plugin; + } + + display(): void { + const { containerEl } = this; + + containerEl.empty(); + + containerEl.createEl("h2", { + text: "Settings for Obsidian MtG Plugin.", + }); + + // Collection CSV setting + new Setting(containerEl) + .setName("Collection CSV") + .setDesc("The file extension of your collection as a CSV file") + .addText((text) => + text + .setPlaceholder(".mtg.collection.csv") + .setValue(this.plugin.settings.collection.fileExtension) + .onChange(async (value) => { + this.plugin.settings.collection.fileExtension = value; + await this.plugin.saveSettings(); + }) + ); + + new Setting(containerEl) + .setName("Card name column name") + .setDesc("The name of the CSV column used for card names") + .addText((text) => + text + .setPlaceholder("Name") + .setValue(this.plugin.settings.collection.nameColumn) + .onChange(async (value) => { + this.plugin.settings.collection.nameColumn = value; + await this.plugin.saveSettings(); + }) + ); + + new Setting(containerEl) + .setName("Card count column name") + .setDesc("The name of the CSV column used for card counts/quantity") + .addText((text) => + text + .setPlaceholder("Count") + .setValue(this.plugin.settings.collection.countColumn) + .onChange(async (value) => { + this.plugin.settings.collection.countColumn = value; + await this.plugin.saveSettings(); + }) + ); + + new Setting(containerEl) + .setName("Preferred Currency") + .setDesc( + "The currency you prefer when viewing card prices in your decklist" + ) + .addDropdown((dropdown) => + dropdown + .addOption("usd", "USD") + .addOption("eur", "EUR") + .addOption("tix", "Tix") + .onChange(async (value: "usd" | "eur" | "tix") => { + this.plugin.settings.decklist.preferredCurrency = value; + await this.plugin.saveSettings(); + }) + ); + + new Setting(containerEl) + .setName("Show Card Name Hyperlinks") + .setDesc( + "Enables card names that link to Scryfall or purchasing sites when possible" + ) + .addToggle((toggle) => + toggle + .setValue( + this.plugin.settings.decklist.showCardNamesAsHyperlinks + ) + .onChange(async (value: boolean) => { + this.plugin.settings.decklist.showCardNamesAsHyperlinks = + value; + await this.plugin.saveSettings(); + }) + ); + + new Setting(containerEl) + .setName("Show Card Images") + .setDesc( + "Enables card previews when hovering with the mouse on desktop" + ) + .addToggle((toggle) => + toggle + .setValue(this.plugin.settings.decklist.showCardPreviews) + .onChange(async (value: boolean) => { + this.plugin.settings.decklist.showCardPreviews = value; + await this.plugin.saveSettings(); + }) + ); + + new Setting(containerEl) + .setName("Show Buylist") + .setDesc( + "Enables a buylist below your decklist with buylinks for each card" + ) + .addToggle((toggle) => + toggle + .setValue(this.plugin.settings.decklist.showBuylist) + .onChange(async (value: boolean) => { + this.plugin.settings.decklist.showBuylist = value; + await this.plugin.saveSettings(); + }) + ); + + new Setting(containerEl) + .setName("Hide Prices") + .setDesc("Toggles card prices in decklists") + .addToggle((toggle) => + toggle + .setValue(this.plugin.settings.decklist.hidePrices) + .onChange(async (value: boolean) => { + this.plugin.settings.decklist.hidePrices = value; + await this.plugin.saveSettings(); + }) + ); + } +} diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..43ff0e5 --- /dev/null +++ b/manifest.json @@ -0,0 +1,10 @@ +{ + "id": "mtg-deck", + "name": "MtG Deck", + "version": "1.0.0", + "minAppVersion": "0.15.0", + "description": "A plugin for managing Magic: The Gathering decks and card lists as Obsidian notes", + "author": "Samir Boulema", + "authorUrl": "https://github.com/sboulema", + "isDesktopOnly": false +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..8e1974f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6756 @@ +{ + "name": "obsidian-mtg", + "version": "1.0.9", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "obsidian-mtg", + "version": "1.0.9", + "license": "MIT", + "devDependencies": { + "@types/node": "^16.11.6", + "@typescript-eslint/eslint-plugin": "5.29.0", + "@typescript-eslint/parser": "5.29.0", + "builtin-modules": "3.3.0", + "esbuild": "0.14.47", + "eslint": "^8.24.0", + "husky": "^8.0.1", + "jest": "^29.1.2", + "jest-environment-jsdom": "^29.1.2", + "jsdom": "^20.0.1", + "obsidian": "latest", + "prettier": "2.7.1", + "prettier-eslint": "^15.0.1", + "ts-jest": "^29.0.3", + "ts-node": "^10.9.1", + "tslib": "2.4.0", + "typescript": "4.7.4" + }, + "engines": { + "node": "16.17.1" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.3.tgz", + "integrity": "sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", + "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.3", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helpers": "^7.19.0", + "@babel/parser": "^7.19.3", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.3", + "@babel/types": "^7.19.3", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz", + "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.19.3", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", + "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.19.3", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", + "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", + "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", + "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", + "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", + "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz", + "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.3", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.19.3", + "@babel/types": "^7.19.3", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", + "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", + "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.5.tgz", + "integrity": "sha512-XVVDtp+dVvRxMoxSiSfasYaG02VEe1qH5cKgMQJWhol6HwzbcqoCMJi8dAGoYAO57jhUyhI6cWuRiTcRaDaYug==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/gitignore-to-minimatch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", + "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.1.2.tgz", + "integrity": "sha512-ujEBCcYs82BTmRxqfHMQggSlkUZP63AE5YEaTPj7eFyJOzukkTorstOUC7L6nE3w5SYadGVAnTsQ/ZjTGL0qYQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.1.2", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.1.2", + "jest-util": "^29.1.2", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/jest-message-util": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.1.2.tgz", + "integrity": "sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.1.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.1.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/pretty-format": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", + "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.1.2.tgz", + "integrity": "sha512-sCO2Va1gikvQU2ynDN8V4+6wB7iVrD2CvT0zaRst4rglf56yLly0NQ9nuRRAWFeimRf+tCdFsb1Vk1N9LrrMPA==", + "dev": true, + "dependencies": { + "@jest/console": "^29.1.2", + "@jest/reporters": "^29.1.2", + "@jest/test-result": "^29.1.2", + "@jest/transform": "^29.1.2", + "@jest/types": "^29.1.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.0.0", + "jest-config": "^29.1.2", + "jest-haste-map": "^29.1.2", + "jest-message-util": "^29.1.2", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.1.2", + "jest-resolve-dependencies": "^29.1.2", + "jest-runner": "^29.1.2", + "jest-runtime": "^29.1.2", + "jest-snapshot": "^29.1.2", + "jest-util": "^29.1.2", + "jest-validate": "^29.1.2", + "jest-watcher": "^29.1.2", + "micromatch": "^4.0.4", + "pretty-format": "^29.1.2", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/jest-message-util": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.1.2.tgz", + "integrity": "sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.1.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.1.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/pretty-format": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", + "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.1.2.tgz", + "integrity": "sha512-rG7xZ2UeOfvOVzoLIJ0ZmvPl4tBEQ2n73CZJSlzUjPw4or1oSWC0s0Rk0ZX+pIBJ04aVr6hLWFn1DFtrnf8MhQ==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.1.2", + "@jest/types": "^29.1.2", + "@types/node": "*", + "jest-mock": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.1.2.tgz", + "integrity": "sha512-FXw/UmaZsyfRyvZw3M6POgSNqwmuOXJuzdNiMWW9LCYo0GRoRDhg+R5iq5higmRTHQY7hx32+j7WHwinRmoILQ==", + "dev": true, + "dependencies": { + "expect": "^29.1.2", + "jest-snapshot": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/@jest/expect-utils": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.1.2.tgz", + "integrity": "sha512-4a48bhKfGj/KAH39u0ppzNTABXQ8QPccWAFUFobWBaEMSMp+sB31Z2fK/l47c4a/Mu1po2ffmfAIPxXbVTXdtg==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/expect/node_modules/expect": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.1.2.tgz", + "integrity": "sha512-AuAGn1uxva5YBbBlXb+2JPxJRuemZsmlGcapPXWNSBNsQtAULfjioREGBWuI0EOvYUKjDnrCy8PW5Zlr1md5mw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.1.2", + "jest-get-type": "^29.0.0", + "jest-matcher-utils": "^29.1.2", + "jest-message-util": "^29.1.2", + "jest-util": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/jest-diff": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.1.2.tgz", + "integrity": "sha512-4GQts0aUopVvecIT4IwD/7xsBaMhKTYoM4/njE/aVw9wpw+pIUVp8Vab/KnSzSilr84GnLBkaP3JLDnQYCKqVQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.0.0", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/jest-matcher-utils": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.1.2.tgz", + "integrity": "sha512-MV5XrD3qYSW2zZSHRRceFzqJ39B2z11Qv0KPyZYxnzDHFeYZGJlgGi0SW+IXSJfOewgJp/Km/7lpcFT+cgZypw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.1.2", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/jest-message-util": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.1.2.tgz", + "integrity": "sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.1.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.1.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect/node_modules/pretty-format": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", + "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.1.2.tgz", + "integrity": "sha512-GppaEqS+QQYegedxVMpCe2xCXxxeYwQ7RsNx55zc8f+1q1qevkZGKequfTASI7ejmg9WwI+SJCrHe9X11bLL9Q==", + "dev": true, + "dependencies": { + "@jest/types": "^29.1.2", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^29.1.2", + "jest-mock": "^29.1.2", + "jest-util": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/fake-timers/node_modules/jest-message-util": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.1.2.tgz", + "integrity": "sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.1.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.1.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers/node_modules/pretty-format": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", + "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.1.2.tgz", + "integrity": "sha512-uMgfERpJYoQmykAd0ffyMq8wignN4SvLUG6orJQRe9WAlTRc9cdpCaE/29qurXixYJVZWUqIBXhSk8v5xN1V9g==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.1.2", + "@jest/expect": "^29.1.2", + "@jest/types": "^29.1.2", + "jest-mock": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.1.2.tgz", + "integrity": "sha512-X4fiwwyxy9mnfpxL0g9DD0KcTmEIqP0jUdnc2cfa9riHy+I6Gwwp5vOZiwyg0vZxfSDxrOlK9S4+340W4d+DAA==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.1.2", + "@jest/test-result": "^29.1.2", + "@jest/transform": "^29.1.2", + "@jest/types": "^29.1.2", + "@jridgewell/trace-mapping": "^0.3.15", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.1.2", + "jest-util": "^29.1.2", + "jest-worker": "^29.1.2", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/jest-message-util": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.1.2.tgz", + "integrity": "sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.1.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.1.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/pretty-format": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", + "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@jest/schemas": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.0.0.tgz", + "integrity": "sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.15", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.1.2.tgz", + "integrity": "sha512-jjYYjjumCJjH9hHCoMhA8PCl1OxNeGgAoZ7yuGYILRJX9NjgzTN0pCT5qAoYR4jfOP8htIByvAlz9vfNSSBoVg==", + "dev": true, + "dependencies": { + "@jest/console": "^29.1.2", + "@jest/types": "^29.1.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.1.2.tgz", + "integrity": "sha512-fU6dsUqqm8sA+cd85BmeF7Gu9DsXVWFdGn9taxM6xN1cKdcP/ivSgXh5QucFRFz1oZxKv3/9DYYbq0ULly3P/Q==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.1.2", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.1.2", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.1.2.tgz", + "integrity": "sha512-2uaUuVHTitmkx1tHF+eBjb4p7UuzBG7SXIaA/hNIkaMP6K+gXYGxP38ZcrofzqN0HeZ7A90oqsOa97WU7WZkSw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.1.2", + "@jridgewell/trace-mapping": "^0.3.15", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.1.2", + "jest-regex-util": "^29.0.0", + "jest-util": "^29.1.2", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.1.2.tgz", + "integrity": "sha512-DcXGtoTykQB5jiwCmVr8H4vdg2OJhQex3qPkG+ISyDO7xQXbt/4R6dowcRyPemRnkH7JoHvZuxPBdlq+9JxFCg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", + "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.24.43", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.43.tgz", + "integrity": "sha512-1orQTvtazZmsPeBroJjysvsOQCYV2yjWlebkSY38pl5vr2tdLjEJ+LoxITlGNZaH2RE19WlAwQMkH/7C14wLfw==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", + "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/codemirror": { + "version": "0.0.108", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.108.tgz", + "integrity": "sha512-3FGFcus0P7C2UOGCNUVENqObEb4SFk+S8Dnxq7K6aIsLVs/vDtlangl3PEO0ykaKXyK56swVF6Nho7VsA44uhw==", + "dev": true, + "dependencies": { + "@types/tern": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.6.tgz", + "integrity": "sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", + "dev": true + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jsdom": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.0.tgz", + "integrity": "sha512-YfAchFs0yM1QPDrLm2VHe+WHGtqms3NXnXAMolrgrVP6fgBHHXy1ozAbo/dFtPNtZC/m66bPiCTWYmqp1F14gA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "16.11.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.60.tgz", + "integrity": "sha512-kYIYa1D1L+HDv5M5RXQeEu1o0FKA6yedZIoyugm/MBPROkLpX4L7HRxMrPVyo8bnvjpW/wDlqFNGzXNMb7AdRw==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/tern": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz", + "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", + "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.29.0.tgz", + "integrity": "sha512-kgTsISt9pM53yRFQmLZ4npj99yGl3x3Pl7z4eA66OuTzAGC4bQB5H5fuLwPnqTKU3yyrrg4MIhjF17UYnL4c0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.29.0", + "@typescript-eslint/type-utils": "5.29.0", + "@typescript-eslint/utils": "5.29.0", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.29.0.tgz", + "integrity": "sha512-ruKWTv+x0OOxbzIw9nW5oWlUopvP/IQDjB5ZqmTglLIoDTctLlAJpAQFpNPJP/ZI7hTT9sARBosEfaKbcFuECw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.29.0", + "@typescript-eslint/types": "5.29.0", + "@typescript-eslint/typescript-estree": "5.29.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.29.0.tgz", + "integrity": "sha512-etbXUT0FygFi2ihcxDZjz21LtC+Eps9V2xVx09zFoN44RRHPrkMflidGMI+2dUs821zR1tDS6Oc9IXxIjOUZwA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.29.0", + "@typescript-eslint/visitor-keys": "5.29.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.29.0.tgz", + "integrity": "sha512-JK6bAaaiJozbox3K220VRfCzLa9n0ib/J+FHIwnaV3Enw/TO267qe0pM1b1QrrEuy6xun374XEAsRlA86JJnyg==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.29.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.29.0.tgz", + "integrity": "sha512-X99VbqvAXOMdVyfFmksMy3u8p8yoRGITgU1joBJPzeYa0rhdf5ok9S56/itRoUSh99fiDoMtarSIJXo7H/SnOg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.29.0.tgz", + "integrity": "sha512-mQvSUJ/JjGBdvo+1LwC+GY2XmSYjK1nAaVw2emp/E61wEVYEyibRHCqm1I1vEKbXCpUKuW4G7u9ZCaZhJbLoNQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.29.0", + "@typescript-eslint/visitor-keys": "5.29.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.29.0.tgz", + "integrity": "sha512-3Eos6uP1nyLOBayc/VUdKZikV90HahXE5Dx9L5YlSd/7ylQPXhLk1BYb29SDgnBnTp+jmSZUU0QxUiyHgW4p7A==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.29.0", + "@typescript-eslint/types": "5.29.0", + "@typescript-eslint/typescript-estree": "5.29.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.29.0.tgz", + "integrity": "sha512-Hpb/mCWsjILvikMQoZIE3voc9wtQcS0A9FUw3h8bhr9UxBdtI/tw1ZDZUOXHXLOVMedKCH5NxyzATwnU78bWCQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.29.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "dev": true, + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/babel-jest": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.1.2.tgz", + "integrity": "sha512-IuG+F3HTHryJb7gacC7SQ59A9kO56BctUsT67uJHp1mMCHUOMXpDwOHWGifWqdWVknN2WNkCVQELPjXx0aLJ9Q==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.1.2", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.0.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.0.2.tgz", + "integrity": "sha512-eBr2ynAEFjcebVvu8Ktx580BD1QKCrBG1XwEUTXJe285p9HA/4hOhfWCFRQhTKSyBV0VzjhG7H91Eifz9s29hg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.0.2.tgz", + "integrity": "sha512-BeVXp7rH5TK96ofyEnHjznjLMQ2nAeDJ+QzxKnHAAMs0RgrQsCywjAN8m4mOm5Di0pxU//3AoEeJJrerMH5UeA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.0.2", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001414", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz", + "integrity": "sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz", + "integrity": "sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==", + "dev": true + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/convert-source-map/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.1.tgz", + "integrity": "sha512-F29o+vci4DodHYT9UrR5IEbfBw9pE5eSapIJdTqXK5+6hq+t8VRxwQyKlW2i+KDKFkkJQRvFyI/QXD83h8LyQw==", + "dev": true + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", + "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.270", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.270.tgz", + "integrity": "sha512-KNhIzgLiJmDDC444dj9vEOpZEgsV96ult9Iff98Vanumn+ShJHd5se8aX6KeVxdc0YQeqdrezBZv89rleDbvSg==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/entities": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", + "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/esbuild": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.47.tgz", + "integrity": "sha512-wI4ZiIfFxpkuxB8ju4MHrGwGLyp1+awEHAHVpx6w7a+1pmYIq8T9FGEVVwFo0iFierDoMj++Xq69GXWYn2EiwA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "esbuild-android-64": "0.14.47", + "esbuild-android-arm64": "0.14.47", + "esbuild-darwin-64": "0.14.47", + "esbuild-darwin-arm64": "0.14.47", + "esbuild-freebsd-64": "0.14.47", + "esbuild-freebsd-arm64": "0.14.47", + "esbuild-linux-32": "0.14.47", + "esbuild-linux-64": "0.14.47", + "esbuild-linux-arm": "0.14.47", + "esbuild-linux-arm64": "0.14.47", + "esbuild-linux-mips64le": "0.14.47", + "esbuild-linux-ppc64le": "0.14.47", + "esbuild-linux-riscv64": "0.14.47", + "esbuild-linux-s390x": "0.14.47", + "esbuild-netbsd-64": "0.14.47", + "esbuild-openbsd-64": "0.14.47", + "esbuild-sunos-64": "0.14.47", + "esbuild-windows-32": "0.14.47", + "esbuild-windows-64": "0.14.47", + "esbuild-windows-arm64": "0.14.47" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.47.tgz", + "integrity": "sha512-R13Bd9+tqLVFndncMHssZrPWe6/0Kpv2/dt4aA69soX4PRxlzsVpCvoJeFE8sOEoeVEiBkI0myjlkDodXlHa0g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.47.tgz", + "integrity": "sha512-OkwOjj7ts4lBp/TL6hdd8HftIzOy/pdtbrNA4+0oVWgGG64HrdVzAF5gxtJufAPOsEjkyh1oIYvKAUinKKQRSQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.47.tgz", + "integrity": "sha512-R6oaW0y5/u6Eccti/TS6c/2c1xYTb1izwK3gajJwi4vIfNs1s8B1dQzI1UiC9T61YovOQVuePDcfqHLT3mUZJA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.47.tgz", + "integrity": "sha512-seCmearlQyvdvM/noz1L9+qblC5vcBrhUaOoLEDDoLInF/VQ9IkobGiLlyTPYP5dW1YD4LXhtBgOyevoIHGGnw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.47.tgz", + "integrity": "sha512-ZH8K2Q8/Ux5kXXvQMDsJcxvkIwut69KVrYQhza/ptkW50DC089bCVrJZZ3sKzIoOx+YPTrmsZvqeZERjyYrlvQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.47.tgz", + "integrity": "sha512-ZJMQAJQsIOhn3XTm7MPQfCzEu5b9STNC+s90zMWe2afy9EwnHV7Ov7ohEMv2lyWlc2pjqLW8QJnz2r0KZmeAEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.47.tgz", + "integrity": "sha512-FxZOCKoEDPRYvq300lsWCTv1kcHgiiZfNrPtEhFAiqD7QZaXrad8LxyJ8fXGcWzIFzRiYZVtB3ttvITBvAFhKw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.47.tgz", + "integrity": "sha512-nFNOk9vWVfvWYF9YNYksZptgQAdstnDCMtR6m42l5Wfugbzu11VpMCY9XrD4yFxvPo9zmzcoUL/88y0lfJZJJw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.47.tgz", + "integrity": "sha512-ZGE1Bqg/gPRXrBpgpvH81tQHpiaGxa8c9Rx/XOylkIl2ypLuOcawXEAo8ls+5DFCcRGt/o3sV+PzpAFZobOsmA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.47.tgz", + "integrity": "sha512-ywfme6HVrhWcevzmsufjd4iT3PxTfCX9HOdxA7Hd+/ZM23Y9nXeb+vG6AyA6jgq/JovkcqRHcL9XwRNpWG6XRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.47.tgz", + "integrity": "sha512-mg3D8YndZ1LvUiEdDYR3OsmeyAew4MA/dvaEJxvyygahWmpv1SlEEnhEZlhPokjsUMfRagzsEF/d/2XF+kTQGg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.47.tgz", + "integrity": "sha512-WER+f3+szmnZiWoK6AsrTKGoJoErG2LlauSmk73LEZFQ/iWC+KhhDsOkn1xBUpzXWsxN9THmQFltLoaFEH8F8w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.47.tgz", + "integrity": "sha512-1fI6bP3A3rvI9BsaaXbMoaOjLE3lVkJtLxsgLHqlBhLlBVY7UqffWBvkrX/9zfPhhVMd9ZRFiaqXnB1T7BsL2g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.47.tgz", + "integrity": "sha512-eZrWzy0xFAhki1CWRGnhsHVz7IlSKX6yT2tj2Eg8lhAwlRE5E96Hsb0M1mPSE1dHGpt1QVwwVivXIAacF/G6mw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.47.tgz", + "integrity": "sha512-Qjdjr+KQQVH5Q2Q1r6HBYswFTToPpss3gqCiSw2Fpq/ua8+eXSQyAMG+UvULPqXceOwpnPo4smyZyHdlkcPppQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.47.tgz", + "integrity": "sha512-QpgN8ofL7B9z8g5zZqJE+eFvD1LehRlxr25PBkjyyasakm4599iroUpaj96rdqRlO2ShuyqwJdr+oNqWwTUmQw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.47.tgz", + "integrity": "sha512-uOeSgLUwukLioAJOiGYm3kNl+1wJjgJA8R671GYgcPgCx7QR73zfvYqXFFcIO93/nBdIbt5hd8RItqbbf3HtAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.47.tgz", + "integrity": "sha512-H0fWsLTp2WBfKLBgwYT4OTfFly4Im/8B5f3ojDv1Kx//kiubVY0IQunP2Koc/fr/0wI7hj3IiBDbSrmKlrNgLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.47.tgz", + "integrity": "sha512-/Pk5jIEH34T68r8PweKRi77W49KwanZ8X6lr3vDAtOlH5EumPE4pBHqkCUdELanvsT14yMXLQ/C/8XPi1pAtkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.47", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.47.tgz", + "integrity": "sha512-HFSW2lnp62fl86/qPQlqw6asIwCnEsEoNIL1h2uVMgakddf+vUuMcCbtUY1i8sst7KkgHrVKCJQB33YhhOweCQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.24.0.tgz", + "integrity": "sha512-dWFaPhGhTAiPcCgm3f6LI2MBWbogMnTJzFBbhXVRQDJPkr9pGZvVjlVfXd+vyDcWPA2Ic9L2AXPIQM0+vk/cSQ==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.3.2", + "@humanwhocodes/config-array": "^0.10.5", + "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@humanwhocodes/module-importer": "^1.0.1", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "globby": "^11.1.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/espree": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", + "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "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" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/husky": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.1.tgz", + "integrity": "sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.1.2.tgz", + "integrity": "sha512-5wEIPpCezgORnqf+rCaYD1SK+mNN7NsstWzIsuvsnrhR/hSxXWd82oI7DkrbJ+XTD28/eG8SmxdGvukrGGK6Tw==", + "dev": true, + "dependencies": { + "@jest/core": "^29.1.2", + "@jest/types": "^29.1.2", + "import-local": "^3.0.2", + "jest-cli": "^29.1.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.0.0.tgz", + "integrity": "sha512-28/iDMDrUpGoCitTURuDqUzWQoWmOmOKOFST1mi2lwh62X4BFf6khgH3uSuo1e49X/UDjuApAj3w0wLOex4VPQ==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.1.2.tgz", + "integrity": "sha512-ajQOdxY6mT9GtnfJRZBRYS7toNIJayiiyjDyoZcnvPRUPwJ58JX0ci0PKAKUo2C1RyzlHw0jabjLGKksO42JGA==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.1.2", + "@jest/expect": "^29.1.2", + "@jest/test-result": "^29.1.2", + "@jest/types": "^29.1.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.1.2", + "jest-matcher-utils": "^29.1.2", + "jest-message-util": "^29.1.2", + "jest-runtime": "^29.1.2", + "jest-snapshot": "^29.1.2", + "jest-util": "^29.1.2", + "p-limit": "^3.1.0", + "pretty-format": "^29.1.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.1.2.tgz", + "integrity": "sha512-4GQts0aUopVvecIT4IwD/7xsBaMhKTYoM4/njE/aVw9wpw+pIUVp8Vab/KnSzSilr84GnLBkaP3JLDnQYCKqVQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.0.0", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.1.2.tgz", + "integrity": "sha512-MV5XrD3qYSW2zZSHRRceFzqJ39B2z11Qv0KPyZYxnzDHFeYZGJlgGi0SW+IXSJfOewgJp/Km/7lpcFT+cgZypw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.1.2", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-message-util": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.1.2.tgz", + "integrity": "sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.1.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.1.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/pretty-format": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", + "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.1.2.tgz", + "integrity": "sha512-EC3Zi86HJUOz+2YWQcJYQXlf0zuBhJoeyxLM6vb6qJsVmpP7KcCP1JnyF0iaqTaXdBP8Rlwsvs7hnKWQWWLwwA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.1.2", + "@jest/types": "^29.1.2", + "babel-jest": "^29.1.2", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.1.2", + "jest-environment-node": "^29.1.2", + "jest-get-type": "^29.0.0", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.1.2", + "jest-runner": "^29.1.2", + "jest-util": "^29.1.2", + "jest-validate": "^29.1.2", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.1.2", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/pretty-format": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", + "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.0.0.tgz", + "integrity": "sha512-s5Kpra/kLzbqu9dEjov30kj1n4tfu3e7Pl8v+f8jOkeWNqM6Ds8jRaJfZow3ducoQUrf2Z4rs2N5S3zXnb83gw==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.1.2.tgz", + "integrity": "sha512-AmTQp9b2etNeEwMyr4jc0Ql/LIX/dhbgP21gHAizya2X6rUspHn2gysMXaj6iwWuOJ2sYRgP8c1P4cXswgvS1A==", + "dev": true, + "dependencies": { + "@jest/types": "^29.1.2", + "chalk": "^4.0.0", + "jest-get-type": "^29.0.0", + "jest-util": "^29.1.2", + "pretty-format": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/pretty-format": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", + "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.1.2.tgz", + "integrity": "sha512-D+XNIKia5+uDjSMwL/G1l6N9MCb7LymKI8FpcLo7kkISjc/Sa9w+dXXEa7u1Wijo3f8sVLqfxdGqYtRhmca+Xw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.1.2", + "@jest/fake-timers": "^29.1.2", + "@jest/types": "^29.1.2", + "@types/jsdom": "^20.0.0", + "@types/node": "*", + "jest-mock": "^29.1.2", + "jest-util": "^29.1.2", + "jsdom": "^20.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.1.2.tgz", + "integrity": "sha512-C59yVbdpY8682u6k/lh8SUMDJPbOyCHOTgLVVi1USWFxtNV+J8fyIwzkg+RJIVI30EKhKiAGNxYaFr3z6eyNhQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.1.2", + "@jest/fake-timers": "^29.1.2", + "@jest/types": "^29.1.2", + "@types/node": "*", + "jest-mock": "^29.1.2", + "jest-util": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", + "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.1.2.tgz", + "integrity": "sha512-xSjbY8/BF11Jh3hGSPfYTa/qBFrm3TPM7WU8pU93m2gqzORVLkHFWvuZmFsTEBPRKndfewXhMOuzJNHyJIZGsw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.1.2", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.0.0", + "jest-util": "^29.1.2", + "jest-worker": "^29.1.2", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.1.2.tgz", + "integrity": "sha512-TG5gAZJpgmZtjb6oWxBLf2N6CfQ73iwCe6cofu/Uqv9iiAm6g502CAnGtxQaTfpHECBdVEMRBhomSXeLnoKjiQ==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.0.0", + "pretty-format": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-leak-detector/node_modules/pretty-format": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", + "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.1.2.tgz", + "integrity": "sha512-PFDAdjjWbjPUtQPkQufvniXIS3N9Tv7tbibePEjIIprzjgo0qQlyUiVMrT4vL8FaSJo1QXifQUOuPH3HQC/aMA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.1.2", + "@types/node": "*", + "jest-util": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.0.0.tgz", + "integrity": "sha512-BV7VW7Sy0fInHWN93MMPtlClweYv2qrSCwfeFWmpribGZtQPWNvRSq9XOVgOEjU1iBGRKXUZil0o2AH7Iy9Lug==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.1.2.tgz", + "integrity": "sha512-7fcOr+k7UYSVRJYhSmJHIid3AnDBcLQX3VmT9OSbPWsWz1MfT7bcoerMhADKGvKCoMpOHUQaDHtQoNp/P9JMGg==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.1.2", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.1.2", + "jest-validate": "^29.1.2", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.1.2.tgz", + "integrity": "sha512-44yYi+yHqNmH3OoWZvPgmeeiwKxhKV/0CfrzaKLSkZG9gT973PX8i+m8j6pDrTYhhHoiKfF3YUFg/6AeuHw4HQ==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.0.0", + "jest-snapshot": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.1.2.tgz", + "integrity": "sha512-yy3LEWw8KuBCmg7sCGDIqKwJlULBuNIQa2eFSVgVASWdXbMYZ9H/X0tnXt70XFoGf92W2sOQDOIFAA6f2BG04Q==", + "dev": true, + "dependencies": { + "@jest/console": "^29.1.2", + "@jest/environment": "^29.1.2", + "@jest/test-result": "^29.1.2", + "@jest/transform": "^29.1.2", + "@jest/types": "^29.1.2", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.0.0", + "jest-environment-node": "^29.1.2", + "jest-haste-map": "^29.1.2", + "jest-leak-detector": "^29.1.2", + "jest-message-util": "^29.1.2", + "jest-resolve": "^29.1.2", + "jest-runtime": "^29.1.2", + "jest-util": "^29.1.2", + "jest-watcher": "^29.1.2", + "jest-worker": "^29.1.2", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/jest-message-util": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.1.2.tgz", + "integrity": "sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.1.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.1.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/pretty-format": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", + "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.1.2.tgz", + "integrity": "sha512-jr8VJLIf+cYc+8hbrpt412n5jX3tiXmpPSYTGnwcvNemY+EOuLNiYnHJ3Kp25rkaAcTWOEI4ZdOIQcwYcXIAZw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.1.2", + "@jest/fake-timers": "^29.1.2", + "@jest/globals": "^29.1.2", + "@jest/source-map": "^29.0.0", + "@jest/test-result": "^29.1.2", + "@jest/transform": "^29.1.2", + "@jest/types": "^29.1.2", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.1.2", + "jest-message-util": "^29.1.2", + "jest-mock": "^29.1.2", + "jest-regex-util": "^29.0.0", + "jest-resolve": "^29.1.2", + "jest-snapshot": "^29.1.2", + "jest-util": "^29.1.2", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/jest-message-util": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.1.2.tgz", + "integrity": "sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.1.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.1.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/pretty-format": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", + "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.1.2.tgz", + "integrity": "sha512-rYFomGpVMdBlfwTYxkUp3sjD6usptvZcONFYNqVlaz4EpHPnDvlWjvmOQ9OCSNKqYZqLM2aS3wq01tWujLg7gg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.1.2", + "@jest/transform": "^29.1.2", + "@jest/types": "^29.1.2", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.1.2", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.1.2", + "jest-get-type": "^29.0.0", + "jest-haste-map": "^29.1.2", + "jest-matcher-utils": "^29.1.2", + "jest-message-util": "^29.1.2", + "jest-util": "^29.1.2", + "natural-compare": "^1.4.0", + "pretty-format": "^29.1.2", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@jest/expect-utils": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.1.2.tgz", + "integrity": "sha512-4a48bhKfGj/KAH39u0ppzNTABXQ8QPccWAFUFobWBaEMSMp+sB31Z2fK/l47c4a/Mu1po2ffmfAIPxXbVTXdtg==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/expect": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.1.2.tgz", + "integrity": "sha512-AuAGn1uxva5YBbBlXb+2JPxJRuemZsmlGcapPXWNSBNsQtAULfjioREGBWuI0EOvYUKjDnrCy8PW5Zlr1md5mw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.1.2", + "jest-get-type": "^29.0.0", + "jest-matcher-utils": "^29.1.2", + "jest-message-util": "^29.1.2", + "jest-util": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.1.2.tgz", + "integrity": "sha512-4GQts0aUopVvecIT4IwD/7xsBaMhKTYoM4/njE/aVw9wpw+pIUVp8Vab/KnSzSilr84GnLBkaP3JLDnQYCKqVQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.0.0", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.1.2.tgz", + "integrity": "sha512-MV5XrD3qYSW2zZSHRRceFzqJ39B2z11Qv0KPyZYxnzDHFeYZGJlgGi0SW+IXSJfOewgJp/Km/7lpcFT+cgZypw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.1.2", + "jest-get-type": "^29.0.0", + "pretty-format": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-message-util": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.1.2.tgz", + "integrity": "sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.1.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.1.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", + "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.1.2.tgz", + "integrity": "sha512-vPCk9F353i0Ymx3WQq3+a4lZ07NXu9Ca8wya6o4Fe4/aO1e1awMMprZ3woPFpKwghEOW+UXgd15vVotuNN9ONQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.1.2", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.1.2.tgz", + "integrity": "sha512-k71pOslNlV8fVyI+mEySy2pq9KdXdgZtm7NHrBX8LghJayc3wWZH0Yr0mtYNGaCU4F1OLPXRkwZR0dBm/ClshA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.1.2", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.0.0", + "leven": "^3.1.0", + "pretty-format": "^29.1.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", + "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.1.2.tgz", + "integrity": "sha512-6JUIUKVdAvcxC6bM8/dMgqY2N4lbT+jZVsxh0hCJRbwkIEnbr/aPjMQ28fNDI5lB51Klh00MWZZeVf27KBUj5w==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.1.2", + "@jest/types": "^29.1.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^29.1.2", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.1.2.tgz", + "integrity": "sha512-AdTZJxKjTSPHbXT/AIOjQVmoFx0LHFcVabWu0sxI7PAy7rFf8c0upyvgBKgguVXdM4vY74JdwkyD4hSmpTW8jA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.1.2", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest/node_modules/jest-cli": { + "version": "29.1.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.1.2.tgz", + "integrity": "sha512-vsvBfQ7oS2o4MJdAH+4u9z76Vw5Q8WBQF5MchDbkylNknZdrPTX1Ix7YRJyTlOWqRaS7ue/cEAn+E4V1MWyMzw==", + "dev": true, + "dependencies": { + "@jest/core": "^29.1.2", + "@jest/test-result": "^29.1.2", + "@jest/types": "^29.1.2", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.1.2", + "jest-util": "^29.1.2", + "jest-validate": "^29.1.2", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest/node_modules/yargs": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/js-sdsl": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", + "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.1.tgz", + "integrity": "sha512-pksjj7Rqoa+wdpkKcLzQRHhJCEE42qQhl/xLMUKHgoSejaKOdaXEAnqs6uDNwMl/fciHTzKeR8Wm8cw7N+g98A==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "acorn": "^8.8.0", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.1", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^3.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.9.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/loglevel": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", + "integrity": "sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, + "node_modules/loglevel-colored-level-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz", + "integrity": "sha512-u45Wcxxc+SdAlh4yeF/uKlC1SPUPCy0gullSNKXod5I4bmifzk+Q4lSLExNEVn19tGaJipbZ4V4jbFn79/6mVA==", + "dev": true, + "dependencies": { + "chalk": "^1.1.3", + "loglevel": "^1.4.1" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nwsapi": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", + "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", + "dev": true + }, + "node_modules/obsidian": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-0.16.3.tgz", + "integrity": "sha512-hal9qk1A0GMhHSeLr2/+o3OpLmImiP+Y+sx2ewP13ds76KXsziG96n+IPFT0mSkup1zSwhEu+DeRhmbcyCCXWw==", + "dev": true, + "dependencies": { + "@types/codemirror": "0.0.108", + "moment": "2.29.4" + }, + "peerDependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz", + "integrity": "sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-eslint": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-15.0.1.tgz", + "integrity": "sha512-mGOWVHixSvpZWARqSDXbdtTL54mMBxc5oQYQ6RAqy8jecuNJBgN3t9E5a81G66F8x8fsKNiR1HWaBV66MJDOpg==", + "dev": true, + "dependencies": { + "@types/eslint": "^8.4.2", + "@types/prettier": "^2.6.0", + "@typescript-eslint/parser": "^5.10.0", + "common-tags": "^1.4.0", + "dlv": "^1.1.0", + "eslint": "^8.7.0", + "indent-string": "^4.0.0", + "lodash.merge": "^4.6.0", + "loglevel-colored-level-prefix": "^1.0.0", + "prettier": "^2.5.1", + "pretty-format": "^23.0.1", + "require-relative": "^0.8.7", + "typescript": "^4.5.4", + "vue-eslint-parser": "^8.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/pretty-format": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", + "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0", + "ansi-styles": "^3.2.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pretty-format/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/pretty-format/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha512-AKGr4qvHiryxRb19m3PsLRGuKVAbJLUD7E6eOaHkfKhwc+vSgVOCY5xNvm9EkolBKTOf0GrQAZKLimOCz81Khg==", + "dev": true + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", + "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ts-jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", + "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", + "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vue-eslint-parser": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", + "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", + "dev": true, + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", + "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..9b4fe9e --- /dev/null +++ b/package.json @@ -0,0 +1,42 @@ +{ + "name": "mtg-deck", + "version": "1.0.0", + "description": "A plugin for managing Magic: The Gathering decks and card lists as Obsidian notes", + "main": "main.js", + "scripts": { + "dev": "node esbuild.config.mjs", + "lint": "eslint --fix main.ts", + "format": "npx prettier --write . ", + "format-check": "npx prettier --check .", + "test": "jest", + "verify": "npm run test && npm run lint && npm run format-check", + "prepare": "husky install", + "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", + "version": "node version-bump.mjs && git add manifest.json versions.json" + }, + "engines": { + "node": "16.17.1" + }, + "keywords": [], + "author": "Samir Boulema", + "license": "MIT", + "devDependencies": { + "@types/node": "^16.11.6", + "@typescript-eslint/eslint-plugin": "5.29.0", + "@typescript-eslint/parser": "5.29.0", + "builtin-modules": "3.3.0", + "esbuild": "0.14.47", + "eslint": "^8.24.0", + "jest": "^29.1.2", + "jest-environment-jsdom": "^29.1.2", + "jsdom": "^20.0.1", + "obsidian": "latest", + "prettier": "2.7.1", + "prettier-eslint": "^15.0.1", + "ts-jest": "^29.0.3", + "ts-node": "^10.9.1", + "tslib": "2.4.0", + "typescript": "4.7.4" + }, + "dependencies": {} +} diff --git a/register.js b/register.js new file mode 100644 index 0000000..1a4b7b0 --- /dev/null +++ b/register.js @@ -0,0 +1,13 @@ +/** + * Overrides the tsconfig used for the app. + * In the test environment we need some tweaks. + */ + +const tsNode = require("ts-node"); +const testTSConfig = require("./test/tsconfig.json"); + +tsNode.register({ + files: true, + transpileOnly: true, + project: "./test/tsconfig.json", +}); diff --git a/src/collection.spec.ts b/src/collection.spec.ts new file mode 100644 index 0000000..5a03078 --- /dev/null +++ b/src/collection.spec.ts @@ -0,0 +1,78 @@ +import { describe, expect, test } from "@jest/globals"; + +import { createCardCountsMapping, nameToId } from "./collection"; +import { ObsidianPluginMtgSettings } from "./settings"; + +// Basic example +const EXAMPLE_CSV_1 = `Name,Count,Set +Delver of Secrets // Insectile Aberration,8,MID +"Otawara, Soaring City",4,NEO +"Rona's Vortex",2,DMU +`; + +// With some overlapping cards +const EXAMPLE_CSV_2 = `Name,Count,Set +Delver of Secrets // Insectile Aberration,1,MID +"Otawara, Soaring City",6,NEO +"Rona's Vortex",3,DMU +Ledger Shredder,5,SNC +`; + +// Empty +const EXAMPLE_CSV_3 = `Name,Count,Set`; + +describe("Collection", () => { + describe("#nameToId()", () => { + test("handles split cards", () => { + const result = nameToId( + "Delver of Secrets // Insectile Aberration" + ); + expect(result).toEqual("delver of secrets"); + }); + + test("handles spacing around name", () => { + const result = nameToId(" Black Lotus "); + expect(result).toEqual("black lotus"); + }); + + test("handles commas", () => { + const result = nameToId("Otawara, Soaring City"); + expect(result).toEqual("otawara, soaring city"); + }); + + test("handles apostrophes", () => { + const result = nameToId("Rona's Vortex"); + expect(result).toEqual("rona's vortex"); + }); + }); + + describe("#createCardCountsMapping", () => { + const settings: ObsidianPluginMtgSettings = { + collection: { + fileExtension: "mtg.collection.csv", + nameColumn: "Name", + countColumn: "Count", + syncIntervalMs: 10, + }, + decklist: { + preferredCurrency: "usd", + showCardNamesAsHyperlinks: true, + showCardPreviews: true, + showBuylist: true, + hidePrices: false, + }, + }; + test("handles multiple CSVs", async () => { + const contents = [EXAMPLE_CSV_1, EXAMPLE_CSV_2]; + + const mapping = await createCardCountsMapping(contents, settings); + + expect(mapping).toEqual({ + "delver of secrets": 9, + "otawara, soaring city": 10, + "rona's vortex": 5, + "ledger shredder": 5, + }); + }); + }); +}); diff --git a/src/collection.ts b/src/collection.ts new file mode 100644 index 0000000..3cd81e1 --- /dev/null +++ b/src/collection.ts @@ -0,0 +1,104 @@ +import { Vault } from "obsidian"; +import { parseCsvFile } from "./csv"; +import { ObsidianPluginMtgSettings } from "./settings"; + +export type CardCounts = Record; + +export const DEFAULT_COLLECTION_FILE_EXTENSION = "mtg.collection.csv"; +export const DEFAULT_COLLECTION_NAME_COLUMN = "Name"; +export const DEFAULT_COLLECTION_COUNT_COLUMN = "Count"; +export const DEFAULT_COLLECTION_SYNC_INTERVAL = 5000; + +export const UNKNOWN_CARD = "UNKNOWN_CARD"; + +export const nameToId = (rawName: string | undefined) => { + return ( + (rawName || "") + // handle double-faced cards (i.e. "Delver Of Secrets" and "Delver of Secrets // Insectile Aberration") + .split("//")[0] + // remove surrounding whitespace + .trim() + // normalizing casing + .toLowerCase() + ); +}; + +export const createCardCountsMapping = async ( + fileContents: string[], + settings: ObsidianPluginMtgSettings +) => { + const counts: CardCounts = {}; + const countsColumnName: string = settings.collection.countColumn; + const nameColumnName: string = settings.collection.nameColumn; + + const recordsList: Record[][] = fileContents.map( + (fileContent) => { + const records = parseCsvFile(fileContent, { + skip_empty_lines: true, + }); + return records; + } + ); + + recordsList.forEach((records) => { + records.forEach((record) => { + const count: number = parseInt(record[countsColumnName] || "0"); + const cardName: string = + nameToId(record[nameColumnName]) || UNKNOWN_CARD; + + if (!counts[cardName]) { + counts[cardName] = count; + } else { + counts[cardName] = counts[cardName] + count; + } + }); + }); + + return counts; +}; + +export const processCollectionFiles = async ( + vault: Vault, + settings: ObsidianPluginMtgSettings +): Promise => { + return ( + ( + await Promise.all( + vault + .getFiles() + .filter((f) => { + if (f.extension === "csv") { + return f.name.endsWith( + `${settings.collection.fileExtension}` + ); + } else { + return false; + } + }) + .map((fileContents) => { + try { + return vault.cachedRead(fileContents); + } catch (err) { + return ""; + } + }) + ) + ) + // remove any unreadable files + .filter((s) => s.length) + ); +}; + +export const syncCounts = async ( + vault: Vault, + settings: ObsidianPluginMtgSettings +): Promise => { + // Sync Collection + const collectionContents: string[] = await processCollectionFiles( + vault, + settings + ); + + // Create consolidationed collection dictionary + return createCardCountsMapping(collectionContents, settings); +}; diff --git a/src/csv.spec.ts b/src/csv.spec.ts new file mode 100644 index 0000000..727ed59 --- /dev/null +++ b/src/csv.spec.ts @@ -0,0 +1,27 @@ +import { describe, expect, test } from "@jest/globals"; +import { removeOuterQuotesFromString } from "./csv"; + +describe("CSV Parser", () => { + describe("#removeOuterQuotesFromString()", () => { + test("it handles empty string", () => { + expect(removeOuterQuotesFromString("")).toEqual(""); + }); + test("it handles a short string", () => { + expect(removeOuterQuotesFromString("a")).toEqual("a"); + }); + test("it handles a single quote inside other quotes", () => { + expect(removeOuterQuotesFromString('"')).toEqual('"'); + }); + test("it handles a string inside quotes", () => { + expect(removeOuterQuotesFromString('"foo"')).toEqual("foo"); + }); + test("it handles mismatched quotes", () => { + expect(removeOuterQuotesFromString('"foo')).toEqual('"foo'); + }); + test("it handles nested quotes", () => { + expect(removeOuterQuotesFromString('""foo" and "foo""')).toEqual( + '"foo" and "foo"' + ); + }); + }); +}); diff --git a/src/csv.ts b/src/csv.ts new file mode 100644 index 0000000..14b429c --- /dev/null +++ b/src/csv.ts @@ -0,0 +1,94 @@ +/** + * Adapted via answer from StackOverflow: + * + * https://stackoverflow.com/questions/1293147/how-to-parse-csv-data + * + */ +export const parseCsvCells = (str: string): string[][] => { + const arr: string[][] = []; + var quote = false; // 'true' means we're inside a quoted field + + // Iterate over each character, keep track of current row and column (of the returned array) + for (var row = 0, col = 0, c = 0; c < str.length; c++) { + var cc = str[c], + nc = str[c + 1]; // Current character, next character + arr[row] = arr[row] || []; // Create a new row if necessary + arr[row][col] = arr[row][col] || ""; // Create a new column (start with empty string) if necessary + + // If the current character is a quotation mark, and we're inside a + // quoted field, and the next character is also a quotation mark, + // add a quotation mark to the current column and skip the next character + if (cc == '"' && quote && nc == '"') { + arr[row][col] += cc; + ++c; + continue; + } + + // If it's just one quotation mark, begin/end quoted field + if (cc == '"') { + quote = !quote; + continue; + } + + // If it's a comma and we're not in a quoted field, move on to the next column + if (cc == "," && !quote) { + ++col; + continue; + } + + // If it's a newline (CRLF) and we're not in a quoted field, skip the next character + // and move on to the next row and move to column 0 of that new row + if (cc == "\r" && nc == "\n" && !quote) { + ++row; + col = 0; + ++c; + continue; + } + + // If it's a newline (LF or CR) and we're not in a quoted field, + // move on to the next row and move to column 0 of that new row + if (cc == "\n" && !quote) { + ++row; + col = 0; + continue; + } + if (cc == "\r" && !quote) { + ++row; + col = 0; + continue; + } + + // Otherwise, append the current character to the current column + arr[row][col] += cc; + } + + return arr; +}; + +export const parseCsvFile = ( + fileContent: string, + opts?: { skip_empty_lines?: boolean } +): Record[] => { + // Assumes that there is a columns header + const lines = fileContent.split("\n"); + const headerRow = lines[0]; + const columnNames = headerRow.split(",").map(removeOuterQuotesFromString); + const linesOfCells = parseCsvCells(fileContent); + // Attach the header names to each row + return linesOfCells.splice(1).map((cells) => { + const obj: Record = {}; + if (cells.length !== 0 || cells.length !== 0) { + columnNames.forEach((columnName: string, idx: number) => { + obj[columnName] = cells[idx]; + }); + } + return obj; + }); +}; + +export const removeOuterQuotesFromString = (s: string) => { + if (s.length > 2 && s[0] === '"' && s[s.length - 1] === '"') { + return s.slice(1, s.length - 1); + } + return s; +}; diff --git a/src/dom-utils.ts b/src/dom-utils.ts new file mode 100644 index 0000000..7fe93bc --- /dev/null +++ b/src/dom-utils.ts @@ -0,0 +1,65 @@ +export function createSpan( + root: Element, + params?: { cls?: string | string[]; text?: string } +): HTMLSpanElement { + // Use native method when available + if (root.createSpan) { + return root.createSpan(params); + } + + // Otherwise, fallback to this extension + const el = document.createElement("span"); + if (!params || Object.keys(params).length === 0) { + return el; + } + + const { cls, text } = params; + + if (Array.isArray(cls)) { + cls.forEach((c) => el.classList.add(c)); + } else { + if (cls) { + el.classList.add(cls); + } + } + if (text) { + el.textContent = text; + } + + root.appendChild(el as Node); + + return el; +} + +export function createDiv( + root: Element, + params?: { cls?: string | string[]; text?: string } +): HTMLDivElement { + if (root.createDiv) { + return root.createDiv(params); + } + + const el = document.createElement("div"); + + if (!params || Object.keys(params).length === 0) { + return el; + } + + const { cls, text } = params; + + if (Array.isArray(cls)) { + cls.forEach((c) => el.classList.add(c)); + } else { + if (cls) { + el.classList.add(cls); + } + } + + if (text) { + el.textContent = text; + } + + root.appendChild(el); + + return el; +} diff --git a/src/http.ts b/src/http.ts new file mode 100644 index 0000000..e5e1aef --- /dev/null +++ b/src/http.ts @@ -0,0 +1,26 @@ +import { requestUrl } from "obsidian"; + +export interface RequestOptions { + url: string; + method?: string; + body?: string; + contentType?: string; + throw?: boolean; + headers?: Record; +} + +export type Request = (options: RequestOptions) => Promise; + +export function promiseWrappedRequest(options: RequestOptions): Promise { + return new Promise(async (resolve, reject) => { + const response = await requestUrl(options); + if (response.status < 400) { + const scryfallData = response.json as T; + resolve(scryfallData); + } else { + reject( + new Error(`RequestError: ${response.status}: ${response.text}`) + ); + } + }); +} diff --git a/src/renderer.spec.ts b/src/renderer.spec.ts new file mode 100644 index 0000000..2a15d3e --- /dev/null +++ b/src/renderer.spec.ts @@ -0,0 +1,72 @@ +import { describe, expect, test } from "@jest/globals"; +import { renderDecklist } from "./renderer"; +import { JSDOM } from "jsdom"; +import { ObsidianPluginMtgSettings } from "./settings"; +import { EXAMPLE_DECKLIST_CARD_DATA } from "../jest/fixtures/scryfall-data"; +import { CardData } from "./scryfall"; +import { + EXAMPLE_COLLECTION, + EXAMPLE_DECK_1, + EXAMPLE_DECK_1_HTML, + EXAMPLE_DECK_1_HTML_WITHOUT_PRICES, +} from "../jest/fixtures/content"; + +const dom = new JSDOM(`

Hello world

`); +const doc = dom.window.document; + +const fakeFetcher = ( + distinctCardNames: string[] +): Promise> => + new Promise((resolve, reject) => { + resolve(EXAMPLE_DECKLIST_CARD_DATA as Record); + }); + +describe("Renderer", () => { + const settings: ObsidianPluginMtgSettings = { + collection: { + fileExtension: "mtg.collection.csv", + nameColumn: "Name", + countColumn: "Count", + syncIntervalMs: 10, + }, + decklist: { + preferredCurrency: "usd", + showCardNamesAsHyperlinks: true, + showCardPreviews: true, + showBuylist: true, + hidePrices: false, + }, + }; + + describe("#renderDecklist", () => { + test("with prices", async () => { + const el = await renderDecklist( + doc.body, + EXAMPLE_DECK_1, + EXAMPLE_COLLECTION, + settings, + fakeFetcher + ); + expect(el.innerHTML.trim()).toEqual(EXAMPLE_DECK_1_HTML.trim()); + }); + + test("witout prices", async () => { + const el = await renderDecklist( + doc.body, + EXAMPLE_DECK_1, + EXAMPLE_COLLECTION, + { + ...settings, + decklist: { + ...settings.decklist, + hidePrices: true, + }, + }, + fakeFetcher + ); + expect(el.innerHTML.trim()).toEqual( + EXAMPLE_DECK_1_HTML_WITHOUT_PRICES.trim() + ); + }); + }); +}); diff --git a/src/renderer.ts b/src/renderer.ts new file mode 100644 index 0000000..91115c4 --- /dev/null +++ b/src/renderer.ts @@ -0,0 +1,683 @@ +import { CardCounts, nameToId, UNKNOWN_CARD } from "./collection"; +import { + CardData, + getMultipleCardData, + MAX_SCRYFALL_BATCH_SIZE, + ScryfallResponse, +} from "./scryfall"; +import { ObsidianPluginMtgSettings } from "./settings"; +import { createDiv, createSpan } from "./dom-utils"; + +const DEFAULT_SECTION_NAME = "Deck:"; +const COMMENT_DELIMITER = "#"; + +interface Line { + lineType: "card" | "section" | "error" | "blank" | "comment"; + cardCount?: number; + globalCount?: number | null; + cardName?: string; + comments?: string[]; + errors?: string[]; + text?: string; +} + +const lineMatchRE = /(\d+)\s(.*)/; +const setCodesRE = /(\([A-Za-z0-9]{3}\)\s\d+)/; +const lineWithSetCodes = /(\d+)\s+([\w| ,']*)\s+(\([A-Za-z0-9]{3}\)\s\d+)/; +const blankLineRE = /^\s+$/; +const headingMatchRE = new RegExp("^[^[0-9|" + COMMENT_DELIMITER + "]"); + +const currencyMapping = { + usd: "$", + eur: "€", + tix: "Tx", +}; + +const idToNameMemo: Record = {}; + +export const getCardPrice = ( + cardName: string, + cardDataById: Record, + settings: ObsidianPluginMtgSettings +) => { + const cardId = nameToId(cardName); + const cardData = cardDataById[cardId]; + const preferredCurrency = settings.decklist.preferredCurrency; + const hidePrices = settings.decklist.hidePrices; + if (!cardData || hidePrices) { + return null; + } else { + if (preferredCurrency === "eur") { + return cardData.prices?.eur || null; + } else if (preferredCurrency === "tix") { + return cardData.prices?.tix || null; + } else { + return cardData.prices?.usd || null; + } + } +}; + +export const parseLines = ( + rawLines: string[], + cardCounts: CardCounts +): Line[] => { + // This means global counts are not available because they are missing or no collection files are present + let shouldSkipGlobalCounts = !Object.keys(cardCounts).length; + + // count, collection_count, card name, comment + return rawLines.map((line) => { + // Handle blank lines + if (!line.length || line.match(blankLineRE)) { + return { + lineType: "blank", + }; + } + + // Handle headings + if (line.match(headingMatchRE)) { + return { + lineType: "section", + text: line, + }; + } + + // Handle comment lines + if (line.startsWith(COMMENT_DELIMITER + " ")) { + return { + lineType: "comment", + comments: [line], + }; + } + + let lineWithoutComments: string = line; + const comments: string[] = []; + // Handle setcodes, etc + if (lineWithoutComments.match(lineWithSetCodes)) { + lineWithoutComments = lineWithoutComments + .replace(setCodesRE, "") + .trim(); + } + + // Handle comments + if (line.includes(COMMENT_DELIMITER)) { + const lineAndComments = line.split(COMMENT_DELIMITER); + lineAndComments + .slice(1) + .forEach((comment) => comments.push(comment)); + lineWithoutComments = lineAndComments[0]; + } + + // Handle card lines + let lineParts = lineWithoutComments.match(lineMatchRE); + + // Handle invalid line + if (lineParts == null) { + return { + lineType: "error", + errors: [`invalid line: ${line}`], + }; + } else { + const cardCount: number = parseInt(lineParts[1] || "0"); + const cardName: string = lineParts[2]; + const cardId: string = nameToId(cardName); + const errors: string[] = []; + + let globalCount = null; + + if (!shouldSkipGlobalCounts) { + globalCount = cardCounts[cardId] || 0; + } + + if (cardName.length === 0) { + errors.push(`Unable to parse card name from: ${line}`); + } + + return { + lineType: "card", + cardCount, + globalCount, + cardName, + comments, + errors, + }; + } + }); +}; + +export const buildDistinctCardNamesList = (lines: Line[]): string[] => { + return Array.from( + new Set( + lines + .map((line) => line.cardName || "") + // Remove missing values + .filter((line) => line !== "") + ) + ); +}; + +export const fetchCardDataFromScryfall = async ( + distinctCardNames: string[] +): Promise> => { + // Fetch in batches of 75, since that's the limit of Scryfall batch sizes + const batches: string[][] = []; + let currentBatch: string[] = []; + batches.push(currentBatch); + distinctCardNames.forEach((cardName: string, idx: number) => { + if (currentBatch.length === MAX_SCRYFALL_BATCH_SIZE) { + batches.push(currentBatch); + // Make new batch + currentBatch = []; + } + currentBatch.push(nameToId(cardName)); + }); + // Add remaining cards + batches.push(currentBatch); + + const cardDataInBatches: ScryfallResponse[] = await Promise.all( + batches.map((batch) => getMultipleCardData(batch)) + ); + const cardDataByCardId: Record = {}; + const cards = []; + + cardDataInBatches.forEach((batch) => { + batch.data.forEach((card: CardData) => { + cards.push(card); + if (card.name) { + const cardId = nameToId(card.name); + cardDataByCardId[cardId] = card; + } + }); + }); + + return cardDataByCardId; +}; + +export const renderDecklist = async ( + root: Element, + source: string, + cardCounts: CardCounts, + settings: ObsidianPluginMtgSettings, + dataFetcher = fetchCardDataFromScryfall +): Promise => { + const containerEl = createDiv(root, {}); + containerEl.classList.add("decklist"); + + const lines: string[] = source.split("\n"); + + const parsedLines: Line[] = parseLines(lines, cardCounts); + + const linesBySection: Record = {}; + + let currentSection = DEFAULT_SECTION_NAME; + let sections: string[] = []; + + // A reverse mapping for getting names from an id + const idsToNames: Record = {}; + + parsedLines.forEach((line, idx) => { + if (idx == 0 && line.lineType !== "section") { + currentSection = `${currentSection}`; + sections.push(`${currentSection}`); + } + if (line.lineType === "section") { + currentSection = line.text || DEFAULT_SECTION_NAME; + sections.push(`${currentSection}`); + } else { + if (!linesBySection[currentSection]) { + linesBySection[currentSection] = []; + } + linesBySection[currentSection].push(line); + } + }); + + // Create list of distinct card names + const distinctCardNames: string[] = buildDistinctCardNamesList(parsedLines); + let cardDataByCardId: Record = {}; + + // Try to fetch data from Scryfall + try { + cardDataByCardId = await dataFetcher(distinctCardNames); + } catch (err) { + console.log("Error fetching card data: ", err); + } + + // Determines whether any card info was found for the cards on the list + const hasCardInfo = Object.keys(cardDataByCardId).length > 0; + + // Make elements from parsedLines + const sectionContainers: Element[] = []; + + // Header section + const header = createDiv(containerEl, { + cls: "header", + }); + + const imgElContainer = document.createElement("div"); + imgElContainer.classList.add("card-image-container"); + const imgEl = document.createElement("img"); + imgEl.classList.add("card-image"); + imgElContainer.appendChild(imgEl); + + // Attach image container to header + header.appendChild(imgElContainer); + + // Footer Section + const footer = document.createElement("div"); + footer.classList.add("footer"); + + const sectionTotalCounts: Record = sections.reduce( + (acc, curr) => ({ ...acc, [curr]: 0 }), + {} + ); + const sectionTotalCost: Record = sections.reduce( + (acc, curr) => ({ ...acc, [curr]: 0.0 }), + {} + ); + const missingCardCounts: CardCounts = {}; + + sections.forEach((section: string) => { + // Put the entire deck in containing div for styling + const sectionContainer = document.createElement("div"); + sectionContainer.classList.add("decklist__section-container"); + + // Create a heading + const sectionHedingEl = document.createElement("h3"); + sectionHedingEl.classList.add("decklist__section-heading"); + sectionContainer.appendChild(sectionHedingEl); + + // Create container for the list items + const sectionList = document.createElement("ul"); + sectionList.classList.add("decklist__section-list"); + + const sectionMissingCardCounts: CardCounts = {}; + + // Create line item elements + linesBySection[section].forEach((line: Line) => { + const lineEl = document.createElement("li"); + lineEl.classList.add("decklist__section-list-item"); + + if (line.lineType === "card") { + const cardCountEl = createSpan(lineEl, { + cls: "count", + }); + + const cardNameEl = createSpan(lineEl, { + cls: "card-name", + }); + + // Add hyperlink when possible + if (line.cardName) { + const cardId = nameToId(line.cardName); + const cardInfo = cardDataByCardId[cardId]; + if ( + settings.decklist.showCardNamesAsHyperlinks && + cardInfo && + cardInfo.scryfall_uri + ) { + const cardLinkEl = document.createElement("a"); + const purchaseUri = cardInfo.scryfall_uri; + cardLinkEl.href = purchaseUri; + cardLinkEl.textContent = `${cardInfo.name}`; + cardNameEl.appendChild(cardLinkEl); + } else { + cardNameEl.textContent = `${ + (cardInfo && cardInfo.name) || + line.cardName || + UNKNOWN_CARD + }`; + } + } + + let cardErrorsEl = null; + if (line.errors && line.errors.length) { + cardErrorsEl = createSpan(lineEl, { + cls: "error", + text: line.errors?.join(",") || "", + }); + } + + const cardCommentsEl = createSpan(lineEl, { + cls: "comment", + text: line.comments?.join("#") || "", + }); + + const cardPriceEl = createSpan(lineEl, { + cls: "card-price", + }); + let cardPrice; + if (line.cardName) { + cardPrice = getCardPrice( + line.cardName, + cardDataByCardId, + settings + ); + } + + const lineCardCount = line.cardCount || 0; + const lineGlobalCount = + line.globalCount === null ? -1 : line.globalCount || 0; + + // Show missing card counts + if (lineGlobalCount !== -1 && lineCardCount > lineGlobalCount) { + const counts = createSpan(cardCountEl); + // Card error element + createSpan(counts, { + cls: "error", + text: `${lineGlobalCount}`, + }); + // Card counts row element + createSpan(counts, { + text: ` / ${lineCardCount}`, + }); + lineEl.classList.add("insufficient-count"); + + const cardId = nameToId(line.cardName); + missingCardCounts[cardId] = + (missingCardCounts[cardId] || 0) + + (lineCardCount - lineGlobalCount); + + sectionMissingCardCounts[cardId] = + (sectionMissingCardCounts[cardId] || 0) + + (lineCardCount - lineGlobalCount); + + if (cardPrice) { + cardPriceEl.classList.add("insufficient-count"); + + const totalPrice: number = + lineCardCount * parseFloat(cardPrice); + const amountOwned: number = + lineGlobalCount * parseFloat(cardPrice); + + const amountOwnedEl = createSpan(cardPriceEl, { + cls: "error", + text: `${ + currencyMapping[ + settings.decklist.preferredCurrency + ] + }${amountOwned.toFixed(2)}`, + }); + + // totalPriceEl + createSpan(cardPriceEl, { + text: ` / ${ + currencyMapping[ + settings.decklist.preferredCurrency + ] + }${totalPrice.toFixed(2)}`, + }); + + // Add cost to total + sectionTotalCost[section] = + sectionTotalCost[section] + (totalPrice || 0.0); + } + } else { + cardCountEl.textContent = `${lineCardCount}`; + + if (cardPrice) { + const totalPrice: number = + lineCardCount * parseFloat(cardPrice); + const displayPrice = `${ + currencyMapping[settings.decklist.preferredCurrency] + }${totalPrice.toFixed(2)}`; + cardPriceEl.textContent = displayPrice; + + // Add cost to total + sectionTotalCost[section] = + sectionTotalCost[section] + (totalPrice || 0.0); + } + } + + sectionTotalCounts[section] = + sectionTotalCounts[section] + (line.cardCount || 0); + + if (cardErrorsEl) { + lineEl.appendChild(cardErrorsEl); + } + + if (settings.decklist.showCardPreviews) { + // Event handlers for card artwork popover + lineEl.addEventListener("mouseenter", () => { + const cardId = nameToId(line.cardName); + const cardInfo = cardDataByCardId[cardId]; + let imgUri: string | undefined; + if (cardInfo) { + // For single-faced cards... + if (cardInfo.image_uris) { + imgUri = cardInfo.image_uris?.large; + // For double-faced cards... + } else if ( + cardInfo.card_faces && + cardInfo.card_faces.length > 1 + ) { + // Use the front-side of the card for preview + imgUri = + cardInfo.card_faces[0].image_uris?.large; + } + const offsetPaddingTop = 16; + imgElContainer.style.top = `${ + lineEl.offsetTop + offsetPaddingTop + }px`; + imgElContainer.style.left = `${cardCommentsEl.offsetLeft}px`; + } + if (typeof imgUri !== "undefined") { + imgEl.src = imgUri; + } + }); + + lineEl.addEventListener("mouseleave", () => { + imgEl.src = ""; + }); + } + + sectionList.appendChild(lineEl); + } else if (line.lineType === "comment") { + // Comments + createSpan(lineEl, { + cls: "comment", + text: line.comments?.join(" ") || "", + }); + + sectionList.appendChild(lineEl); + } + }); + + sectionHedingEl.textContent = `${section}`; + + sectionContainer.appendChild(sectionList); + + const horizontalDividorEl = document.createElement("hr"); + sectionContainer.appendChild(horizontalDividorEl); + + const totalsEl = createDiv(sectionContainer, { + cls: "decklist__section-totals", + }); + + const sectionMissingCardIds = Object.keys(sectionMissingCardCounts); + + const totalCardsEl = createSpan(sectionContainer); + const totalCostEl = createSpan(sectionContainer); + + // When there are missing cards, show fraction + if (sectionMissingCardIds.length) { + // Counts + const totalMissingCountInSection = Object.values( + sectionMissingCardCounts + ).reduce((acc, v) => acc + v, 0); + + const totalCardsOwned = + sectionTotalCounts[section] - totalMissingCountInSection; + + // Errors + createSpan(totalCardsEl, { + cls: "error", + text: `${totalCardsOwned}`, + }); + + // Counts + createSpan(totalCardsEl, { + cls: "insufficient-count", + text: ` / ${sectionTotalCounts[section]}`, + }); + + totalCardsEl.classList.add("decklist__section-totals__count"); + + const totalMissingCostInSection = Object.keys( + sectionMissingCardCounts + ).reduce((acc, cardId) => { + const countNeeded = sectionMissingCardCounts[cardId]; + const cardPrice: number = parseFloat( + getCardPrice(cardId, cardDataByCardId, settings) || "0.00" + ); + return acc + cardPrice * countNeeded; + }, 0.0); + + // Value + if (hasCardInfo && !settings.decklist.hidePrices) { + const totalValueOwned = + sectionTotalCost[section] - totalMissingCostInSection; + const totalValueOwnedEl = createSpan(totalCostEl, { + cls: "error", + text: `${ + currencyMapping[settings.decklist.preferredCurrency] + }${totalValueOwned.toFixed(2)}`, + }); + + // Total value needed + createSpan(totalCostEl, { + cls: "insufficient-count", + text: ` / ${ + currencyMapping[settings.decklist.preferredCurrency] + }${sectionTotalCost[section].toFixed(2)}`, + }); + } + + // Otherwise show simple values + } else { + totalCardsEl.classList.add("decklist__section-totals__count"); + totalCardsEl.textContent = `${sectionTotalCounts[section]}`; + if (!settings.decklist.hidePrices) { + totalCostEl.textContent = `${ + currencyMapping[settings.decklist.preferredCurrency] + }${sectionTotalCost[section].toFixed(2)}`; + } + } + + totalsEl.appendChild(totalCardsEl); + + const totalCardsUnitEl = createSpan(totalsEl, { + cls: "card-name", + text: "cards", + }); + + if (hasCardInfo && !settings.decklist.hidePrices) { + totalsEl.appendChild(totalCostEl); + } + + sectionContainer.appendChild(totalsEl); + + sectionContainers.push(sectionContainer); + }); + + sectionContainers.forEach((sectionContainer) => + containerEl.appendChild(sectionContainer) + ); + + const buylistCardIds = Object.keys(missingCardCounts); + const buylistCardCounts = Object.values(missingCardCounts).reduce( + (acc, val) => acc + val, + 0 + ); + + // Only show the buylist element when there are missing cards + if (buylistCardIds.length && settings.decklist.showBuylist) { + // Build Buylist + const buylist = document.createElement("div"); + buylist.classList.add("buylist-container"); + + const buylistHeader = document.createElement("h3"); + buylistHeader.classList.add("decklist__section-heading"); + buylistHeader.textContent = "Buylist: "; + + buylist.appendChild(buylistHeader); + + let totalCostOfBuylist = 0.0; + + let buylistLines = ""; + + buylistCardIds.forEach((cardId) => { + const cardInfo = cardDataByCardId[cardId]; + let buylistLine = ""; + + const countNeeded = missingCardCounts[cardId]; + + // const countEl = createSpan(buylistLineEl, { + // cls: "decklist__section-totals__count", + // text: `${countNeeded}`, + // }); + + // Add count + buylistLine += `${countNeeded}` + " "; + + if (cardInfo) { + const cardName = cardInfo.name || ""; + + buylistLine += `${cardName}`; + + // Retrieve price + const cardPrice: number = parseFloat( + getCardPrice(cardName, cardDataByCardId, settings) || "0.00" + ); + + totalCostOfBuylist = + totalCostOfBuylist + cardPrice * countNeeded; + + buylistLines += buylistLine + "\n"; + } else { + // Card name might be unknown + buylistLines += buylistLine + `${cardId || UNKNOWN_CARD}\n`; + } + }); + + const buylistPre = document.createElement("pre"); + buylistPre.classList.add("buylist-container"); + buylistPre.textContent = buylistLines; + + buylist.appendChild(buylistPre); + + const horizontalDividorEl = document.createElement("hr"); + buylist.appendChild(horizontalDividorEl); + + const buylistLineEl = document.createElement("div"); + buylistLineEl.classList.add("buylist-line"); + + // countEl + createSpan(buylistLineEl, { + cls: "decklist__section-totals__count", + text: `${buylistCardCounts} `, + }); + + // cardNameEl + createSpan(buylistLineEl, { + cls: "card-name", + text: "cards", + }); + + let totalPriceEl = null; + if (hasCardInfo && !settings.decklist.hidePrices) { + totalPriceEl = createSpan(buylistLineEl, { + cls: "decklist__section-totals", + text: `${ + currencyMapping[settings.decklist.preferredCurrency] + }${totalCostOfBuylist.toFixed(2)}`, + }); + } + + buylist.appendChild(buylistLineEl); + + footer.appendChild(buylist); + } + + containerEl.appendChild(footer); + + return containerEl; +}; diff --git a/src/scryfall.spec.ts b/src/scryfall.spec.ts new file mode 100644 index 0000000..26ba82f --- /dev/null +++ b/src/scryfall.spec.ts @@ -0,0 +1,44 @@ +import { describe, expect, test, jest } from "@jest/globals"; + +import { getCardData, getMultipleCardData, RequestOptions } from "./scryfall"; +import { + EXAMPLE_MULTI_CARD_RESPONSE, + EXAMPLE_SCRYFALL_RESPONSE_1, +} from "../jest/fixtures/scryfall-data"; + +describe("Scryfall", () => { + describe("#getCardData()", () => { + test("for a single card", async () => { + function httpReq( + options: RequestOptions + ): Promise { + return new Promise((res) => { + res( + EXAMPLE_SCRYFALL_RESPONSE_1 as unknown as ScryfallResponse + ); + }); + } + const data = await getCardData("Delver of Secrets", httpReq); + expect(data).toEqual(EXAMPLE_SCRYFALL_RESPONSE_1); + }); + }); + + describe("#getMultipleCardData()", () => { + test("for a single card", async () => { + function httpReq( + options: RequestOptions + ): Promise { + return new Promise((res) => { + res( + EXAMPLE_MULTI_CARD_RESPONSE as unknown as ScryfallResponse + ); + }); + } + const data = await getMultipleCardData( + ["Delver of Secrets", "Ledger Shredder", "Dark Ritual"], + httpReq + ); + expect(data).toEqual(EXAMPLE_MULTI_CARD_RESPONSE); + }); + }); +}); diff --git a/src/scryfall.ts b/src/scryfall.ts new file mode 100644 index 0000000..2e55d39 --- /dev/null +++ b/src/scryfall.ts @@ -0,0 +1,189 @@ +import { promiseWrappedRequest } from "./http"; + +const querystring = require("querystring"); + +export interface RequestOptions { + url: string; + method?: string; + body?: string; + contentType?: string; + throw?: boolean; + headers?: Record; +} + +export type Request = (options: RequestOptions) => Promise; + +// This is the maximum number of cards that can be requested at the same time +export const MAX_SCRYFALL_BATCH_SIZE = 75; + +export interface CardFace { + object?: string; // card_face + name?: string; + mana_cost?: string; + type_line?: string; + oracle_text?: string; + colors?: string[]; + power?: string; + toughness?: string; + flavor_text?: string; + flavor_name?: string; + color_indicator?: string[]; + artist?: string; + artist_id?: string; + illustration_id?: string; + image_uris?: { + small: string; + normal: string; + large: string; + png: string; + art_crop: string; + border_crop: string; + }; +} + +export interface CardData { + object?: string; // card + id?: string; + oracle_id?: string; + multiverse_ids?: number[]; + mtgo_id?: number; + arena_id?: number; + tcgplayer_id?: number; + cardmarket_id?: number; + name?: string; + lang?: string; + released_at?: string; + uri?: string; + scryfall_uri?: string; + layout?: string; + highres_image?: boolean; + image_status?: string; + cmc?: number; + type_line?: string; + color_identity?: string[]; + keywords?: string[]; + card_faces?: CardFace[]; + legalities?: Record; + games?: string[]; + reserved?: boolean; + foil?: boolean; + nonfoil?: boolean; + finishes?: string[]; + oversized?: boolean; + promo?: boolean; + reprint?: boolean; + variation?: boolean; + set_id?: string; + set: string; + set_name: string; + set_type: string; + set_uri: string; + set_search_uri: string; + scryfall_set_uri: string; + rulings_uri: string; + prints_search_uri: string; + collector_number: string; + digital: boolean; + rarity: string; + artist: string; + artist_ids: string[]; + border_color: string; + frame?: string; + frame_effects?: string[]; + full_art?: boolean; + textless?: boolean; + booster?: boolean; + image_uris?: { + art_crop?: string; + border_crop?: string; + large?: string; + normal?: string; + png?: string; + small?: string; + }; + story_spotlight?: boolean; + edhrec_rank?: number; + penny_rank?: number; + preview?: { + source?: string; + source_uri?: string; + previewed_at?: string; + }; + prices?: { + usd?: string | null; + usd_foil?: string | null; + usd_etched?: string | null; + eur?: string | null; + eur_foil?: string | null; + tix: string | null; + }; + related_uris?: { + gatherer: string; + tcgplayer_infinite_articles: string; + tcgplayer_infinite_decks: string; + edhrec: string; + }; + purchase_uris?: { + tcgplayer: string; + cardmarket: string; + cardhoarder: string; + }; +} + +export interface ScryfallResponse { + data: CardData[]; + has_more: boolean; + not_found?: string[]; + object: "list"; + total_cards: number; +} + +export const getCardData = async ( + cardName: string, + request = promiseWrappedRequest +): Promise => { + const query: string = querystring.stringify({ q: cardName }); + const params: RequestOptions = { + url: `https://api.scryfall.com/cards/search?${query}`, + }; + return request(params); +}; + +export const getMultipleCardData = async ( + cardNames: string[], + request = promiseWrappedRequest +): Promise => { + if (cardNames.length === 0) { + // Return an empty response + return new Promise((resolve, reject) => { + resolve({ + data: [], + has_more: false, + object: "list", + total_cards: 0, + } as ScryfallResponse); + }); + } + + const cardIdentifiers = cardNames.map((cardName) => ({ + name: cardName, + })); + + const postData = JSON.stringify({ + identifiers: cardIdentifiers, + }); + + const params: RequestOptions = { + url: "https://api.scryfall.com/cards/collection", + method: "POST", + body: postData, + contentType: "application/json", + throw: false, + headers: { + accept: "application/json", + "user-agent": "obsidian-mtg", + }, + }; + + return request(params); +}; diff --git a/src/settings.ts b/src/settings.ts new file mode 100644 index 0000000..f352194 --- /dev/null +++ b/src/settings.ts @@ -0,0 +1,24 @@ +export interface ObsidianPluginMtgSettings { + collection: { + // The file extension used for your collection CSV files + fileExtension: string; + // The name of the column where card names are stored + nameColumn: string; + // The name of the column in your csv where your counts are stored + countColumn: string; + // The number of milliseconds between collection count syncs + syncIntervalMs: number; + }; + decklist: { + // Card Price Currency: + preferredCurrency: "usd" | "eur" | "tix"; + // Show hyperlinks + showCardNamesAsHyperlinks: boolean; + // Show card previews + showCardPreviews: boolean; + // Show buylist + showBuylist: boolean; + // Show prices + hidePrices: boolean; + }; +} diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..073afae --- /dev/null +++ b/styles.css @@ -0,0 +1,133 @@ +/* + +This CSS file will be included with your plugin, and +available in the app when your plugin is enabled. + +If your plugin does not need CSS, delete this file. + +*/ + +.decklist { + padding: 8px; +} + +ul.decklist__section-list { + list-style: none; + margin: 0; + padding: 0; +} + +.decklist__section-totals { + display: flex; +} + +.decklist__section-totals span { + flex: 1; +} + +span.decklist__section-totals__count { + flex: 1; +} + +.decklist__section-list-item { + font-weight: 400; + display: flex; +} + +.decklist__section-list-item span { + flex: 1; +} + +.count { + flex: 1; +} + +span.card-name { + flex: 2; +} + +.insufficient-count { + color: #666; + font-style: italic; +} + +span.comment { + color: #999; + font-style: italic; + flex: 2; +} + +.card-price { +} + +.error { + color: #a33; + font-style: italic; +} + +.decklist__section-heading { + font-weight: 800; +} + +.footer { +} + +.card-image { + height: 400px; +} + +.buylist-container { + z-index: 0; +} + +.buylist-line { + display: flex; +} + +.buylist-line span { + flex: 1; +} + +/* decklist__section-totals { + font-weight: 800; +} */ + +.decklist__section-totals .card-name { + flex: 4; +} + +.buylist-line decklist__section-totals__count { + flex: 1; +} + +.buylist-line .card-name { + flex: 4; +} + +.buylist-line .decklist__section-totals { + flex: 1; +} + +.card-image-container { + text-align: right; + position: absolute; + z-index: 1; +} + +.buy-button { + flex: 1; + margin: 5px; +} + +.buy-buttons-container { + flex: 2 2; + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.markdown-source-view.mod-cm6 + .cm-preview-code-block:has(> .block-language-mtg-deck) { + overflow: visible; + contain: initial !important; +} diff --git a/test/tsconfig.json b/test/tsconfig.json new file mode 100644 index 0000000..f35183e --- /dev/null +++ b/test/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "baseUrl": "./", + "module": "commonjs", + "experimentalDecorators": true, + "strictPropertyInitialization": false, + "isolatedModules": false, + "strict": false, + "noImplicitAny": false, + "typeRoots": ["../node_modules/@types"] + }, + "exclude": ["../node_modules"], + "include": ["./**/*.ts"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..4d02297 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "inlineSourceMap": true, + "inlineSources": true, + "module": "ESNext", + "target": "ES6", + "allowJs": true, + "experimentalDecorators": true, + "strictPropertyInitialization": false, + "noImplicitAny": true, + "moduleResolution": "node", + "importHelpers": true, + "isolatedModules": true, + "strictNullChecks": true, + "lib": ["DOM", "ES5", "ES6", "ES7"] + }, + "include": ["**/*.ts"] +} diff --git a/version-bump.mjs b/version-bump.mjs new file mode 100644 index 0000000..d409fa0 --- /dev/null +++ b/version-bump.mjs @@ -0,0 +1,14 @@ +import { readFileSync, writeFileSync } from "fs"; + +const targetVersion = process.env.npm_package_version; + +// read minAppVersion from manifest.json and bump version to target version +let manifest = JSON.parse(readFileSync("manifest.json", "utf8")); +const { minAppVersion } = manifest; +manifest.version = targetVersion; +writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t")); + +// update versions.json with target version and minAppVersion from manifest.json +let versions = JSON.parse(readFileSync("versions.json", "utf8")); +versions[targetVersion] = minAppVersion; +writeFileSync("versions.json", JSON.stringify(versions, null, "\t")); diff --git a/versions.json b/versions.json new file mode 100644 index 0000000..26382a1 --- /dev/null +++ b/versions.json @@ -0,0 +1,3 @@ +{ + "1.0.0": "0.15.0" +}