From 4e7ecb5397211904d81f9b65ec7dfdb758ce1a71 Mon Sep 17 00:00:00 2001 From: AlacrisDevs Date: Mon, 8 Dec 2025 12:32:43 +0200 Subject: [PATCH] Added quality of life changes, improved animations, added basic tutorials (need to add more pages), MVP is robust and only needs sound effects and music pretty much, besides a lot of user testing. --- messages/en.json | 17 +- messages/et.json | 17 +- package-lock.json | 2021 ++++++++++++++++- package.json | 9 +- src/lib/assets/favicon-kuldvillak.svg | 8 + src/lib/components/ConfirmDialog.svelte | 6 +- src/lib/components/ErrorBoundary.svelte | 104 + src/lib/components/Settings.svelte | 53 +- src/lib/components/index.ts | 1 + .../kuldvillak/ui/KvButtonPrimary.svelte | 22 +- .../kuldvillak/ui/KvButtonSecondary.svelte | 26 +- .../kuldvillak/ui/KvGameLogo.svelte | 6 +- .../components/kuldvillak/ui/KvSpinner.svelte | 36 + .../kuldvillak/ui/TutorialModal.svelte | 172 ++ src/lib/components/kuldvillak/ui/index.ts | 6 +- src/lib/example_testing_game.json | 425 +++- src/lib/stores/gameSession.svelte.ts | 20 +- src/lib/stores/persistence.test.ts | 209 ++ src/lib/types/kuldvillak.test.ts | 145 ++ src/routes/+layout.svelte | 17 +- src/routes/+page.svelte | 4 +- src/routes/kuldvillak/+layout.svelte | 5 + src/routes/kuldvillak/+page.svelte | 6 +- src/routes/kuldvillak/edit/+page.svelte | 98 +- src/routes/kuldvillak/play/+page.svelte | 67 +- .../kuldvillak/play/ModeratorView.svelte | 103 +- .../kuldvillak/play/ProjectorView.svelte | 305 ++- static/kuldvillak_favicon.svg | 3 + static/tutorials/en/.gitkeep | 0 static/tutorials/en/howto-1.png | Bin 0 -> 1535278 bytes static/tutorials/en/howto-2.png | Bin 0 -> 228537 bytes static/tutorials/en/howto-3.png | Bin 0 -> 228551 bytes static/tutorials/en/howto-4.png | Bin 0 -> 228550 bytes static/tutorials/en/howto-5.png | Bin 0 -> 228502 bytes static/tutorials/en/howto-6.png | Bin 0 -> 200766 bytes static/tutorials/en/howto-7.png | Bin 0 -> 258923 bytes static/tutorials/et/.gitkeep | 0 static/tutorials/et/howto-1.png | Bin 0 -> 1535278 bytes static/tutorials/et/howto-2.png | Bin 0 -> 238742 bytes static/tutorials/et/howto-3.png | Bin 0 -> 238758 bytes static/tutorials/et/howto-4.png | Bin 0 -> 238758 bytes static/tutorials/et/howto-5.png | Bin 0 -> 238704 bytes static/tutorials/et/howto-6.png | Bin 0 -> 205960 bytes static/tutorials/et/howto-7.png | Bin 0 -> 258726 bytes vitest.config.ts | 13 + 45 files changed, 3689 insertions(+), 235 deletions(-) create mode 100644 src/lib/assets/favicon-kuldvillak.svg create mode 100644 src/lib/components/ErrorBoundary.svelte create mode 100644 src/lib/components/kuldvillak/ui/KvSpinner.svelte create mode 100644 src/lib/components/kuldvillak/ui/TutorialModal.svelte create mode 100644 src/lib/stores/persistence.test.ts create mode 100644 src/lib/types/kuldvillak.test.ts create mode 100644 static/kuldvillak_favicon.svg create mode 100644 static/tutorials/en/.gitkeep create mode 100644 static/tutorials/en/howto-1.png create mode 100644 static/tutorials/en/howto-2.png create mode 100644 static/tutorials/en/howto-3.png create mode 100644 static/tutorials/en/howto-4.png create mode 100644 static/tutorials/en/howto-5.png create mode 100644 static/tutorials/en/howto-6.png create mode 100644 static/tutorials/en/howto-7.png create mode 100644 static/tutorials/et/.gitkeep create mode 100644 static/tutorials/et/howto-1.png create mode 100644 static/tutorials/et/howto-2.png create mode 100644 static/tutorials/et/howto-3.png create mode 100644 static/tutorials/et/howto-4.png create mode 100644 static/tutorials/et/howto-5.png create mode 100644 static/tutorials/et/howto-6.png create mode 100644 static/tutorials/et/howto-7.png create mode 100644 vitest.config.ts diff --git a/messages/en.json b/messages/en.json index dd2cee4..beefae4 100644 --- a/messages/en.json +++ b/messages/en.json @@ -17,7 +17,7 @@ "kv_settings_close": "Close", "kv_error_404": "404", "kv_error_not_found": "Not Found", - "kv_error_hint": "(pssst... make sure you're on the right page)", + "kv_error_hint": "(pssst... have you tried restarting your computer?)", "kv_edit_title": "Game Editor", "kv_edit_back": "Back", "kv_edit_game_name": "Game name...", @@ -166,5 +166,18 @@ "kv_confirm_close_message": "Are you sure you want to close? Any unsaved changes will be lost.", "kv_confirm_discard": "Discard", "kv_confirm_cancel": "Cancel", - "kv_final_round": "Final Round" + "kv_final_round": "Final Round", + "kv_tutorial_rules_placeholder": "Placeholder: Add your rules explanation here", + "kv_tutorial_howto_1": "Hello! Let's do a quick introduction on how you can start playing Jeopardy.\nI'll try to be as detailed as possible to cover potential questions, but hopefully the platform is simple enough that not much explanation is needed.\nYou can come back here at any time.", + "kv_tutorial_howto_2": "This is your game creation screen.\nHere you can set the game length, points, additional rules, players, questions, and much more that goes into organizing a Jeopardy game.", + "kv_tutorial_howto_3": "Back arrow - back to home page\nGame name - you can name your game (changes file name)\nOpen game - open a previously created game\nSave game - save the current game as a file to your computer for later use\nreset - reset current work\nsettings - all necessary settings from sound to colors. Go try it!\nStart - starts the game", + "kv_tutorial_howto_4": "Rounds - either 1 round (Jeopardy) or 2 rounds (Jeopardy + Double Jeopardy). 2 rounds is the default setting\nTime to answer - set how long players can answer in seconds. 5 seconds is the default setting\nAnswer reveal - set how long the game shows the answer on screen. 5 seconds is the default setting.\nFinal round - edit the final round question. You can choose whether the final round comes at the end of the game or not.\n\nPoints - normal is 10-50, double jeopardy 20-100. custom lets you set jeopardy round points that double in double jeopardy.\nNegative points - set whether player scores can go negative. negative points are the default setting.\nplayers - add players. player count is 2-6.", + "kv_tutorial_howto_5": "Each round has 6 categories and each category has 5 questions. All categories and questions must be filled to start the game.\nTo edit, click on the category or question tile.\n\nJeopardy round has 1 Daily Double, Double Jeopardy round has 2 Daily Doubles. For each question, you can choose whether it's a Daily Double or not.\nYou can find the Daily Double explanation in the Jeopardy rules.", + "kv_tutorial_howto_6": "For each question, you can see the category and how many points it's worth.\nTo complete a question, you need to fill in the question and answer.\nYou can also add an image to the question, which means that when showing the question, only the image will appear on screen, not the question text. The game host can read the question from their own screen.\n\nAdditionally, you can set whether the question is a Daily Double or not and see how many Daily Doubles are already set in that round.", + "kv_tutorial_howto_7": "Music - change the music volume.\nSound effects - change the sound effects volume.\nLanguage - currently Estonian and English are supported.\n\nDon't like the standard Jeopardy blue-gold style? You can change every color as much as you want and the whole game will share your style! You won't know unless you try!", + "error_title": "Something went wrong", + "error_description": "An unexpected error occurred. Please try again.", + "error_details": "Technical details", + "error_retry": "Try Again", + "error_go_home": "Go Home" } \ No newline at end of file diff --git a/messages/et.json b/messages/et.json index a185d7c..e9e49ae 100644 --- a/messages/et.json +++ b/messages/et.json @@ -17,7 +17,7 @@ "kv_settings_close": "Välju", "kv_error_404": "404", "kv_error_not_found": "Lehte ei leitud", - "kv_error_hint": "(pssst... vaata, et oled ikka õigel lehel)", + "kv_error_hint": "(pssst... oled proovinud arvuti taaskäivitamist?)", "kv_edit_title": "Mängu redaktor", "kv_edit_back": "Tagasi", "kv_edit_game_name": "Mängu nimi...", @@ -166,5 +166,18 @@ "kv_confirm_close_message": "Kas oled kindel, et soovid sulgeda? Salvestamata muudatused lähevad kaotsi.", "kv_confirm_discard": "Loobu", "kv_confirm_cancel": "Tühista", - "kv_final_round": "Kuldvillak" + "kv_final_round": "Kuldvillak", + "kv_tutorial_rules_placeholder": "Platvormikoht: Lisa siia reeglite seletus", + "kv_tutorial_howto_1": "Tervist! Teeme kerge sissejuhatuse, kuidas sa saad hakata kuldvillakut mängima.\nProovin olla võimalikult detailne, et katta võimalikud küsimused ära, aga loodetavasti on platvormi kasutada piisavalt lihtne, et palju seletust pole vaja.\nSul on võimalik tulla siia tagasi igal ajal.", + "kv_tutorial_howto_2": "See on sinu mänguloomise ekraan.\nSiin on sul võimalik seada mängu pikkust, punkte, lisareegleid, mängijaid, küsimusi ja palju muud, mis läheb ühe kuldvillaku korraldamisse.", + "kv_tutorial_howto_3": "Tagasi nool - tagasi kodulehele\nMängu nimi - saad panna enda mängule nime (muudab failinime)\nAva mäng - ava varasemalt tehtud mäng\nSalvesta mäng - salvesta praegune mäng failina arvutisse hiljem kasutamiseks\nreset - lähtesta senine töö\nseaded - kõik vajalikud seaded helist kuni värvideni välja. Mine proovi!\nAlusta - alustab mängu", + "kv_tutorial_howto_4": "voorude arv - kas 1 voor (villak) või 2 vooru (villak + Topeltvillak). 2 vooru on originaalne formaat\nVastamisaeg - määra, kui kaua mängijad vastata saavad sekundites. 5 sekundit on originaalne formaat\nVastuse näitamine - määra, kui kaua mäng näitab vastust ekraanil. 5 sekundit on originaalne formaat.\nFinaalvoor - muuda finaalvooru küsimust. Saad valida, kas finaalvoor tuleb mängu lõpus või ei.\n\nPunktid - tavaline on 10-50, topeltvillakus 20-100. kohandatud laseb sul panna villaku vooru punktid, mis duubelduvad topeltvillakus.\nNegatiivsed punktid - määra, kas mängijate skoorid saavad minna negatiivseks. negatiivsed punktid on sees originaalses formaadis.\nmängijad - lisa mängijad. mängijate arv on 2-6.", + "kv_tutorial_howto_5": "Igas voorus on 6 kategooriat ja igas kategoorias on 5 küsimust. Kõik kategooriad ja küsimused peavad olema täidetud selleks, et mängu alustada.\nMuutmiseks kliki kategooria või küsimuse ruudu peale.\n\nVillaku voorus on 1 hõbevillak, topeltvillaku voorus 2 hõbevillakut. Iga küsimuse juures on võimalik valida, kas küsimus on hõbevillak või mitte.\nHõbevillaku seletuse leiad kuldvillaku reeglitest.", + "kv_tutorial_howto_6": "Iga küsimuse juures on võimalik näha kategooriat ja mitu punkti saab.\nSelleks, et küsimus oleks täidetud, on vaja panna küsimus ja vastus kirja.\nKüsimuse juurde on võimalik panna ka pilt, mis tähendab seda, et küsimuse näitamisel tuleb ekraanile ainult pilt, mitte küsimus. Mängu läbiviijal on võimalik küsimust oma ekraanilt lugeda.\n\nLisaks on võimalik määrata, kas küsimus on hõbevillak või mitte ja näha, mitu hõbevillakut selles voorus juba on määratud.", + "kv_tutorial_howto_7": "Muusika - muuda muusika helitugevust.\nHeliefektid - muuda heliefektide helitugevust.\nKeel - praegu on toetatud eesti ja inglise keel.\n\nEi meeldi tavaline kuldvillaku sinine-koldne stiil? Võid muuta igat värvi nii palju kui tahad ja kogu mäng jagab sinu stiili! Muudmoodi teada ei saa, kui ei proovi!", + "error_title": "Midagi läks valesti", + "error_description": "Tekkis ootamatu viga. Palun proovi uuesti.", + "error_details": "Tehnilised detailid", + "error_retry": "Proovi uuesti", + "error_go_home": "Mine avalehele" } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d1f0135..d6a4016 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,11 +13,195 @@ "@sveltejs/kit": "^2.48.5", "@sveltejs/vite-plugin-svelte": "^6.2.1", "@tailwindcss/vite": "^4.1.17", + "jsdom": "^27.2.0", "svelte": "^5.43.8", "svelte-check": "^4.3.4", "tailwindcss": "^4.1.17", "typescript": "^5.9.3", - "vite": "^7.2.2" + "vite": "^7.2.2", + "vitest": "^2.1.0" + } + }, + "node_modules/@acemir/cssom": { + "version": "0.9.28", + "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.28.tgz", + "integrity": "sha512-LuS6IVEivI75vKN8S04qRD+YySP0RmU/cV8UNukhQZvprxF+76Z43TNo/a08eCodaGhT1Us8etqS1ZRY9/Or0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@asamuzakjp/css-color": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.0.tgz", + "integrity": "sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "lru-cache": "^11.2.2" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "6.7.6", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.6.tgz", + "integrity": "sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.1.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.2.4" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.14.tgz", + "integrity": "sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/aix-ppc64": { @@ -1309,6 +1493,92 @@ "dev": true, "license": "MIT" }, + "node_modules/@vitest/expect": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz", + "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz", + "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "2.1.9", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz", + "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz", + "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", + "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -1323,6 +1593,16 @@ "node": ">=0.4.0" } }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/aria-query": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", @@ -1340,6 +1620,16 @@ "dev": true, "license": "MIT" }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -1350,6 +1640,53 @@ "node": ">= 0.4" } }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", @@ -1428,6 +1765,49 @@ "dev": true, "license": "MIT" }, + "node_modules/css-tree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.12.2", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/cssstyle": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.4.tgz", + "integrity": "sha512-KyOS/kJMEq5O9GdPnaf82noigg5X5DYn0kZPJTaAsCUaBizp6Xa1y9D4Qoqf/JazEXWuruErHgVXwjN5391ZJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^4.1.0", + "@csstools/css-syntax-patches-for-csstree": "1.0.14", + "css-tree": "^3.1.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/data-urls": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz", + "integrity": "sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^15.0.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -1446,6 +1826,13 @@ } } }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, "node_modules/dedent": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", @@ -1461,6 +1848,16 @@ } } }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -1502,6 +1899,26 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, "node_modules/esbuild": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", @@ -1575,6 +1992,26 @@ "@jridgewell/sourcemap-codec": "^1.4.15" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -1615,18 +2052,79 @@ "dev": true, "license": "ISC" }, - "node_modules/human-id": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.1.3.tgz", - "integrity": "sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==", + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "dev": true, "license": "MIT", - "bin": { - "human-id": "dist/cli.js" + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" } }, - "node_modules/is-reference": { - "version": "3.0.3", + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-id": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.1.3.tgz", + "integrity": "sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==", + "dev": true, + "license": "MIT", + "bin": { + "human-id": "dist/cli.js" + } + }, + "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, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.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, + "license": "MIT" + }, + "node_modules/is-reference": { + "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", "dev": true, @@ -1652,6 +2150,47 @@ "dev": true, "license": "MIT" }, + "node_modules/jsdom": { + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.2.0.tgz", + "integrity": "sha512-454TI39PeRDW1LgpyLPyURtB4Zx1tklSr6+OFOipsxGUH1WMTvk6C65JQdrj455+DP2uJ1+veBEHTGFKWVLFoA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@acemir/cssom": "^0.9.23", + "@asamuzakjp/dom-selector": "^6.7.4", + "cssstyle": "^5.3.3", + "data-urls": "^6.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "parse5": "^8.0.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^15.1.0", + "ws": "^8.18.3", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -1954,6 +2493,23 @@ "dev": true, "license": "MIT" }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -1964,6 +2520,13 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/mdn-data": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -2010,6 +2573,36 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", + "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2050,6 +2643,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -2059,6 +2653,16 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -2073,6 +2677,16 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/rollup": { "version": "4.53.3", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz", @@ -2128,6 +2742,26 @@ "node": ">=6" } }, + "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, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/set-cookie-parser": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", @@ -2135,6 +2769,13 @@ "dev": true, "license": "MIT" }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/sirv": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", @@ -2172,6 +2813,20 @@ "kysely": "*" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, "node_modules/svelte": { "version": "5.45.2", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.45.2.tgz", @@ -2224,6 +2879,13 @@ "typescript": ">=5.0.0" } }, + "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, + "license": "MIT" + }, "node_modules/tailwindcss": { "version": "4.1.17", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz", @@ -2245,6 +2907,20 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -2262,6 +2938,56 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "7.0.19", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.19.tgz", + "integrity": "sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.0.19" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.0.19", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.19.tgz", + "integrity": "sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==", + "dev": true, + "license": "MIT" + }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", @@ -2272,6 +2998,32 @@ "node": ">=6" } }, + "node_modules/tough-cookie": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", + "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -2400,30 +3152,1243 @@ } } }, - "node_modules/vitefu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", - "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", + "node_modules/vite-node": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz", + "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==", "dev": true, "license": "MIT", - "workspaces": [ - "tests/deps/*", - "tests/projects/*", - "tests/projects/workspace/packages/*" - ], - "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" }, - "peerDependenciesMeta": { - "vite": { - "optional": true - } + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/webpack-virtual-modules": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", - "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "node_modules/vite-node/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite-node/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vite-node/node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", + "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz", + "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "2.1.9", + "@vitest/mocker": "2.1.9", + "@vitest/pretty-format": "^2.1.9", + "@vitest/runner": "2.1.9", + "@vitest/snapshot": "2.1.9", + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.9", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.9", + "@vitest/ui": "2.1.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@vitest/mocker": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz", + "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vitest/node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.0.tgz", + "integrity": "sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-15.1.0.tgz", + "integrity": "sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "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": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "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, "license": "MIT" }, diff --git a/package.json b/package.json index 829353f..88be462 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,10 @@ "preview": "vite preview", "prepare": "svelte-kit sync || echo ''", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "test": "vitest", + "test:run": "vitest run", + "test:coverage": "vitest run --coverage" }, "devDependencies": { "@inlang/paraglide-js": "^2.5.0", @@ -17,10 +20,12 @@ "@sveltejs/kit": "^2.48.5", "@sveltejs/vite-plugin-svelte": "^6.2.1", "@tailwindcss/vite": "^4.1.17", + "jsdom": "^27.2.0", "svelte": "^5.43.8", "svelte-check": "^4.3.4", "tailwindcss": "^4.1.17", "typescript": "^5.9.3", - "vite": "^7.2.2" + "vite": "^7.2.2", + "vitest": "^2.1.0" } } diff --git a/src/lib/assets/favicon-kuldvillak.svg b/src/lib/assets/favicon-kuldvillak.svg new file mode 100644 index 0000000..e3d8814 --- /dev/null +++ b/src/lib/assets/favicon-kuldvillak.svg @@ -0,0 +1,8 @@ + + + + diff --git a/src/lib/components/ConfirmDialog.svelte b/src/lib/components/ConfirmDialog.svelte index 93fb331..d6be99d 100644 --- a/src/lib/components/ConfirmDialog.svelte +++ b/src/lib/components/ConfirmDialog.svelte @@ -41,7 +41,7 @@ {#if open}
{title} -

+

{message}

diff --git a/src/lib/components/ErrorBoundary.svelte b/src/lib/components/ErrorBoundary.svelte new file mode 100644 index 0000000..245ec96 --- /dev/null +++ b/src/lib/components/ErrorBoundary.svelte @@ -0,0 +1,104 @@ + + +{#if hasError && error} + {#if fallback} + {@render fallback(error)} + {:else} + + {/if} +{:else} + {@render children()} +{/if} diff --git a/src/lib/components/Settings.svelte b/src/lib/components/Settings.svelte index f209eea..3b7e3a0 100644 --- a/src/lib/components/Settings.svelte +++ b/src/lib/components/Settings.svelte @@ -149,30 +149,59 @@
diff --git a/src/lib/components/index.ts b/src/lib/components/index.ts index e3cca50..59cd386 100644 --- a/src/lib/components/index.ts +++ b/src/lib/components/index.ts @@ -5,6 +5,7 @@ export { default as LanguageSwitcher } from './LanguageSwitcher.svelte'; export { default as Toast } from './Toast.svelte'; export { default as ConfirmDialog } from './ConfirmDialog.svelte'; export { default as ColorPicker } from './ColorPicker.svelte'; +export { default as ErrorBoundary } from './ErrorBoundary.svelte'; // Kuldvillak Components export * from './kuldvillak'; diff --git a/src/lib/components/kuldvillak/ui/KvButtonPrimary.svelte b/src/lib/components/kuldvillak/ui/KvButtonPrimary.svelte index ff3d24d..999d7e8 100644 --- a/src/lib/components/kuldvillak/ui/KvButtonPrimary.svelte +++ b/src/lib/components/kuldvillak/ui/KvButtonPrimary.svelte @@ -7,6 +7,8 @@ onclick?: () => void; children: Snippet; class?: string; + reload?: boolean; + ariaLabel?: string; } let { @@ -15,18 +17,32 @@ onclick, children, class: className = "", + reload = false, + ariaLabel, }: Props = $props(); const baseClasses = - "inline-flex items-center justify-center px-6 py-4 bg-kv-blue text-kv-white kv-btn-text cursor-pointer transition-opacity hover:opacity-80 disabled:opacity-50 disabled:cursor-not-allowed kv-shadow-button border-4 border-black box-border"; + "inline-flex items-center justify-center px-6 py-4 bg-kv-blue text-kv-white kv-btn-text cursor-pointer transition-opacity hover:opacity-80 disabled:opacity-50 disabled:cursor-not-allowed kv-shadow-button border-4 border-black box-border focus:outline-none focus:ring-2 focus:ring-kv-yellow focus:ring-offset-2 focus:ring-offset-black"; {#if href && !disabled} - + {@render children()} {:else} - {/if} diff --git a/src/lib/components/kuldvillak/ui/KvButtonSecondary.svelte b/src/lib/components/kuldvillak/ui/KvButtonSecondary.svelte index 90e81e4..b932944 100644 --- a/src/lib/components/kuldvillak/ui/KvButtonSecondary.svelte +++ b/src/lib/components/kuldvillak/ui/KvButtonSecondary.svelte @@ -7,6 +7,8 @@ onclick?: () => void; children: Snippet; class?: string; + reload?: boolean; + ariaLabel?: string; } let { @@ -15,18 +17,32 @@ onclick, children, class: className = "", + reload = false, + ariaLabel, }: Props = $props(); const baseClasses = - "inline-flex items-center justify-center px-6 py-4 bg-kv-yellow text-black kv-btn-text cursor-pointer transition-opacity hover:opacity-80 disabled:opacity-50 disabled:cursor-not-allowed kv-shadow-button border-4 border-black box-border"; + "inline-flex items-center justify-center px-6 py-4 bg-kv-yellow text-black kv-btn-text cursor-pointer transition-opacity hover:opacity-80 disabled:opacity-50 disabled:cursor-not-allowed kv-shadow-button border-4 border-black box-border focus:outline-none focus:ring-2 focus:ring-kv-blue focus:ring-offset-2 focus:ring-offset-black"; {#if href && !disabled} - - {@render children()} + + {@render children()} {:else} - {/if} diff --git a/src/lib/components/kuldvillak/ui/KvGameLogo.svelte b/src/lib/components/kuldvillak/ui/KvGameLogo.svelte index 5583bee..a44655c 100644 --- a/src/lib/components/kuldvillak/ui/KvGameLogo.svelte +++ b/src/lib/components/kuldvillak/ui/KvGameLogo.svelte @@ -90,12 +90,14 @@ {:else} + interface Props { + class?: string; + } + + let { class: className = "" }: Props = $props(); + + + + + + + diff --git a/src/lib/components/kuldvillak/ui/TutorialModal.svelte b/src/lib/components/kuldvillak/ui/TutorialModal.svelte new file mode 100644 index 0000000..0646332 --- /dev/null +++ b/src/lib/components/kuldvillak/ui/TutorialModal.svelte @@ -0,0 +1,172 @@ + + + + +{#if open} + +
e.key === "Enter" && close()} + role="button" + tabindex="-1" + aria-label="Close modal" + > + + +
+{/if} diff --git a/src/lib/components/kuldvillak/ui/index.ts b/src/lib/components/kuldvillak/ui/index.ts index 3d616fa..1edb4f0 100644 --- a/src/lib/components/kuldvillak/ui/index.ts +++ b/src/lib/components/kuldvillak/ui/index.ts @@ -11,5 +11,9 @@ export { default as KvNumberInput } from './KvNumberInput.svelte'; export { default as KvEditCard } from './KvEditCard.svelte'; // Branding -export { default as KvLogo } from './KvGameLogo.svelte'; export { default as KvGameLogo } from './KvGameLogo.svelte'; +export { default as KvSpinner } from './KvSpinner.svelte'; + +// Modals +export { default as TutorialModal } from './TutorialModal.svelte'; +export type { TutorialSlide } from './TutorialModal.svelte'; diff --git a/src/lib/example_testing_game.json b/src/lib/example_testing_game.json index f09e194..9f490a2 100644 --- a/src/lib/example_testing_game.json +++ b/src/lib/example_testing_game.json @@ -1,7 +1,7 @@ { - "name": "9. Klassi Viktoriini", + "name": "9. Klassi Viktoriin", "settings": { - "numberOfRounds": 1, + "numberOfRounds": 2, "pointValuePreset": "round1", "pointValues": [ 10, @@ -14,24 +14,30 @@ "categoriesPerRound": 6, "questionsPerCategory": 5, "dailyDoublesPerRound": [ - 1 + 1, + 2 ], "enableFinalRound": true, "enableSoundEffects": true, "allowNegativeScores": true, "maxTeams": 6, - "defaultTimerSeconds": 15, + "defaultTimerSeconds": 5, "answerRevealSeconds": 5 }, "teams": [ { "id": "r5f48jjat", - "name": "Tiim 1", + "name": "Teet", "score": 0 }, { "id": "lnbeg51uo", - "name": "Tiim 2", + "name": "Kristjan", + "score": 0 + }, + { + "id": "x7k2mq9pf", + "name": "Eeva", "score": 0 } ], @@ -46,40 +52,40 @@ "questions": [ { "id": "a11mxf6ra", - "question": "Mis aastal kuulutati välja Eesti Vabariik?", - "answer": "1918", + "question": "Sellel aastal kuulutati Pärnus välja Eesti Vabariigi iseseisvus", + "answer": "Mis on 1918?", "points": 10, "isDailyDouble": false, "isRevealed": false }, { "id": "j7ztvxf7l", - "question": "Kes oli Eesti Vabariigi esimene riigivanem?", - "answer": "Konstantin Päts", + "question": "See mees oli Eesti Vabariigi esimene riigivanem ja hilisem president", + "answer": "Kes on Konstantin Päts?", "points": 20, "isDailyDouble": false, "isRevealed": false }, { "id": "cwcx4jf7m", - "question": "Mis aastal toimus Laulev revolutsioon?", - "answer": "1988", + "question": "Sellel aastal toimus Laulev revolutsioon, mis viis Eesti taasiseseisvumiseni", + "answer": "Mis on 1988?", "points": 30, "isDailyDouble": false, "isRevealed": false }, { "id": "7m6e1qdwx", - "question": "Mis oli Balti keti kuupäev 1989. aastal?", - "answer": "23. august", + "question": "Sellel kuupäeval 1989. aastal moodustasid eestlased, lätlased ja leedulased inimketi Tallinnast Vilniuseni", + "answer": "Mis on 23. august?", "points": 40, "isDailyDouble": false, "isRevealed": false }, { "id": "mmudm4kjd", - "question": "Mis aastal toimus Jüriöö ülestõus?", - "answer": "1343", + "question": "Sellel aastal toimus Jüriöö ülestõus, kus eestlased tõusid Taani ülemvõimu vastu", + "answer": "Mis on 1343?", "points": 50, "isDailyDouble": false, "isRevealed": false @@ -92,40 +98,40 @@ "questions": [ { "id": "zfg5pe8pl", - "question": "Mis on ruutjuur 144-st?", - "answer": "12", + "question": "Täpselt nii suur arv saadakse, kui võtta ruutjuur arvust 144", + "answer": "Mis on 12?", "points": 10, "isDailyDouble": false, "isRevealed": false }, { "id": "ds2bmll5z", - "question": "Mis on Pythagorase teoreemi valem?", - "answer": "a² + b² = c²", + "question": "See valem kirjeldab täisnurkse kolmnurga külgede vahelist seost Pythagorase teoreemis", + "answer": "Mis on a² + b² = c²?", "points": 20, "isDailyDouble": false, "isRevealed": false }, { "id": "6jkk4qkwo", - "question": "Mis on arvu pi (π) väärtus kahe komakohani?", - "answer": "3,14", + "question": "Täpselt selline on arvu pi (π) väärtus kahe komakohani ümardatuna", + "answer": "Mis on 3,14?", "points": 30, "isDailyDouble": false, "isRevealed": false }, { "id": "h32bk4gll", - "question": "Kui kolmnurga alus on 8 cm ja kõrgus 6 cm, mis on pindala?", - "answer": "24 cm²", + "question": "Täpselt nii suur on kolmnurga pindala ruutsentimeetrites, kui selle alus on 8 cm ja kõrgus 6 cm", + "answer": "Mis on 24 cm²?", "points": 40, "isDailyDouble": true, "isRevealed": false }, { "id": "a2vjrjbuo", - "question": "Lahenda võrrand: 3x + 7 = 22", - "answer": "x = 5", + "question": "Täpselt selline on x-i väärtus võrrandis 3x + 7 = 22", + "answer": "Mis on x = 5?", "points": 50, "isDailyDouble": false, "isRevealed": false @@ -138,40 +144,40 @@ "questions": [ { "id": "a0tz6k2a5", - "question": "Mis on vee keemik valem?", - "answer": "H₂O", + "question": "See keemiline valem tähistab vett, mis koosneb kahest vesiniku ja ühest hapniku aatomist", + "answer": "Mis on H₂O?", "points": 10, "isDailyDouble": false, "isRevealed": false }, { "id": "1kjss32t3", - "question": "Mitu planeeti on meie päikesesüsteemis?", - "answer": "8", + "question": "Täpselt nii palju planeete tiirleb meie päikesesüsteemis ümber Päikese", + "answer": "Mis on 8?", "points": 20, "isDailyDouble": false, "isRevealed": false }, { "id": "4acp3zwgh", - "question": "Mis on fotosünteesi põhiprodukt?", - "answer": "Glükoos (suhkur) ja hapnik", + "question": "Need kaks ainet on fotosünteesi põhiproduktid, mida taimed valgusel toodavad", + "answer": "Mis on glükoos ja hapnik?", "points": 30, "isDailyDouble": false, "isRevealed": false }, { "id": "fh1jn2z6f", - "question": "Mis element on perioodilisustabelis tähisega Fe?", - "answer": "Raud", + "question": "See keemiline element kannab perioodilisustabelis tähist Fe ja on üks levinumaid metalle", + "answer": "Mis on raud?", "points": 40, "isDailyDouble": false, "isRevealed": false }, { "id": "wd96bi1d5", - "question": "Mis on DNA täisnimi?", - "answer": "Desoksüribonukleiinhape", + "question": "See on DNA täisnimi ehk molekul, mis kannab pärilikku informatsiooni", + "answer": "Mis on desoksüribonukleiinhape?", "points": 50, "isDailyDouble": false, "isRevealed": false @@ -184,40 +190,40 @@ "questions": [ { "id": "he7in5nor", - "question": "Kes kirjutas eepose 'Kalevipoeg'?", - "answer": "Friedrich Reinhold Kreutzwald", + "question": "See Eesti arst ja kirjanik pani kokku rahvuseepose 'Kalevipoeg' rahvaluule põhjal", + "answer": "Kes on Friedrich Reinhold Kreutzwald?", "points": 10, "isDailyDouble": false, "isRevealed": false }, { "id": "pafvsp6t9", - "question": "Mis on A. H. Tammsaare tuntuim romaan?", - "answer": "Tõde ja õigus", + "question": "See viieosaline romaan on A. H. Tammsaare tuntuim teos ja Eesti kirjanduse tippude hulgas", + "answer": "Mis on 'Tõde ja õigus'?", "points": 20, "isDailyDouble": false, "isRevealed": false }, { "id": "rjjp0h8s4", - "question": "Kes kirjutas luuletuse 'Mu isamaa on minu arm'?", - "answer": "Lydia Koidula", + "question": "See Eesti luuletaja, keda kutsutakse 'koidulaulikuks', kirjutas luuletuse 'Mu isamaa on minu arm'", + "answer": "Kes on Lydia Koidula?", "points": 30, "isDailyDouble": false, "isRevealed": false }, { "id": "n7o3vkkcn", - "question": "Mis on soneti traditsiooniline värsside arv?", - "answer": "14 rida", + "question": "Täpselt nii palju värsse ehk ridu on traditsioonilises sonetis", + "answer": "Mis on 14 rida?", "points": 40, "isDailyDouble": false, "isRevealed": false }, { "id": "4hxuoa1fy", - "question": "Kes kirjutas romaani 'Kevade'?", - "answer": "Oskar Luts", + "question": "See Eesti kirjanik lõi armastatud romaani 'Kevade', mis räägib Paunvere koolipoistest", + "answer": "Kes on Oskar Luts?", "points": 50, "isDailyDouble": false, "isRevealed": false @@ -230,40 +236,40 @@ "questions": [ { "id": "4qkzwwe7r", - "question": "Mis on Eesti pealinn?", - "answer": "Tallinn", + "question": "See linn on Eesti pealinn ja suurim linn, mis asub Soome lahe kaldal", + "answer": "Mis on Tallinn?", "points": 10, "isDailyDouble": false, "isRevealed": false }, { "id": "7z3113es0", - "question": "Mis on Eesti kõrgeim mägi?", - "answer": "Suur Munamägi", + "question": "See mägi Võrumaal on Eesti ja kogu Baltimaade kõrgeim punkt", + "answer": "Mis on Suur Munamägi?", "points": 20, "isDailyDouble": false, "isRevealed": false }, { "id": "so7tqkk16", - "question": "Mis on maailma suurim ookean?", - "answer": "Vaikne ookean", + "question": "See ookean on maailma suurim ja katab rohkem kui kolmandiku Maa pinnast", + "answer": "Mis on Vaikne ookean?", "points": 30, "isDailyDouble": false, "isRevealed": false }, { "id": "h3gyk1yi3", - "question": "Mis riik on pindalalt maailma suurim?", - "answer": "Venemaa", + "question": "See riik on pindalalt maailma suurim, ulatudes Euroopast Aasiani", + "answer": "Mis on Venemaa?", "points": 40, "isDailyDouble": false, "isRevealed": false }, { "id": "385aprc7p", - "question": "Mis on Eesti suurim saar?", - "answer": "Saaremaa", + "question": "See saar on Eesti suurim ja asub Lääne-Eesti saarestikus", + "answer": "Mis on Saaremaa?", "points": 50, "isDailyDouble": false, "isRevealed": false @@ -276,40 +282,40 @@ "questions": [ { "id": "jzcjmb4ef", - "question": "Mis värvid on Eesti lipul?", - "answer": "Sinine, must, valge", + "question": "Need kolm värvi moodustavad Eesti lipu trikoloori, mis kehtestati juba 19. sajandil", + "answer": "Mis on sinine, must ja valge?", "points": 10, "isDailyDouble": false, "isRevealed": false }, { "id": "n86mk1kg0", - "question": "Mis on Eesti rahvuslind?", - "answer": "Suitsupääsuke", + "question": "See väike lind kahestunud sabaga on Eesti rahvuslind ja sümboliseerib õnne", + "answer": "Mis on suitsupääsuke?", "points": 20, "isDailyDouble": false, "isRevealed": false }, { "id": "04e5zactm", - "question": "Mis aastal liitus Eesti Euroopa Liiduga?", - "answer": "2004", + "question": "Sellel aastal liitus Eesti koos üheksa teise riigiga Euroopa Liiduga", + "answer": "Mis on 2004?", "points": 30, "isDailyDouble": false, "isRevealed": false }, { "id": "xwhxh99j6", - "question": "Mis on Eesti rahvuslill?", - "answer": "Rukkilill", + "question": "See sinine põllulill on Eesti rahvuslill ja sümboliseerib igapäevast leiba", + "answer": "Mis on rukkilill?", "points": 40, "isDailyDouble": false, "isRevealed": false }, { "id": "n54fmwmg8", - "question": "Mis aastal võttis Eesti kasutusele euro?", - "answer": "2011", + "question": "Sellel aastal võttis Eesti kasutusele euro, olles 17. euroala riik", + "answer": "Mis on 2011?", "points": 50, "isDailyDouble": false, "isRevealed": false @@ -318,11 +324,294 @@ } ], "pointMultiplier": 1 + }, + { + "id": "e84612e7-2694-4174-9a8f-a2741a02633b", + "name": "Double Jeopardy", + "categories": [ + { + "id": "c57b9a5b-0e5d-4feb-ab1f-60bc9c88650a", + "name": "MAAILMA AJALUGU", + "questions": [ + { + "id": "bbc398fa-8f8d-47ac-9cf7-eb980873acd5", + "question": "Sellel aastal algas Teine maailmasõda, kui Saksamaa tungis Poolasse", + "answer": "Mis on 1939?", + "points": 20, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "af4d9436-b532-4da4-acf3-d6ede530cea5", + "question": "See Vana-Egiptuse legendaarne kuninganna oli armastajaks nii Julius Caesarile kui ka Marcus Antoniusele", + "answer": "Kes on Kleopatra?", + "points": 40, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "f3c21526-4111-471f-9e59-54cb3180da04", + "question": "Sellel aastal langes Berliini müür ja Saksamaa taasühendamine sai võimalikuks", + "answer": "Mis on 1989?", + "points": 60, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "a7230d01-4d94-4b1e-b6e5-15bfb423c983", + "question": "See Prantsuse keiser vallutas suure osa Euroopast, kuid kaotas lõpuks 1815. aastal Waterloo lahingu", + "answer": "Kes on Napoleon Bonaparte?", + "points": 80, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "9e4b114a-9253-4778-9d69-251bca34ace3", + "question": "Sellel aastal jõudis Itaalia meresõitja Christopher Columbus esimest korda Ameerika mandritele", + "answer": "Mis on 1492?", + "points": 100, + "isDailyDouble": false, + "isRevealed": false + } + ] + }, + { + "id": "019af247-c1e2-4d63-b780-eb5570ee9481", + "name": "TEADUS JA TEHNIKA", + "questions": [ + { + "id": "e7a227ed-e11f-4041-88c8-36fd9076e445", + "question": "Täpselt nii kiiresti liigub valgus vaakumis kilomeetrites sekundis - see on universumi kiireim võimalik kiirus", + "answer": "Mis on 300 000 km/s?", + "points": 20, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "1b0ce55c-d7c3-440d-8ed1-cb0b71388c60", + "question": "See Šoti teadlane avastas 1928. aastal juhuslikult penitsilliini, mis muutis meditsiini ajaloo", + "answer": "Kes on Alexander Fleming?", + "points": 40, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "6f553e0a-9e5a-478b-9efa-9602dc3494dc", + "question": "Sellel keemilisel elemendil on aatomnumber 79 ja see on üks kõige väärtuslikumaid metalleid maailmas", + "answer": "Mis on kuld?", + "points": 60, + "isDailyDouble": true, + "isRevealed": false + }, + { + "id": "f533d224-b5e6-4bd5-99a0-3f20c7348e22", + "question": "See Ameerika astronaut oli esimene inimene, kes astus 1969. aastal Kuu pinnale ja lausus kuulsad sõnad", + "answer": "Kes on Neil Armstrong?", + "points": 80, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "4d2e4e3e-122f-419f-94e2-32e4d05f6724", + "question": "See Saksa päritolu füüsik sõnastas relatiivsuse teooria ja on tuntud oma valemi E=mc² poolest", + "answer": "Kes on Albert Einstein?", + "points": 100, + "isDailyDouble": false, + "isRevealed": false + } + ] + }, + { + "id": "d3b51154-f8e8-492c-8062-438f8508f199", + "name": "MUUSIKA", + "questions": [ + { + "id": "abedd9e5-5d41-40be-8732-e3b4bae26734", + "question": "Sellest Inglismaa linnast pärineb legendaarne bänd The Beatles, kes muutis popmuusika ajalugu", + "answer": "Mis on Liverpool?", + "points": 20, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "7765f429-cf26-49cd-b224-476c6553dfbf", + "question": "See Austria päritolu helilooja oli üks Viini klassikutest ja lõi ooperi 'Võluflööt'", + "answer": "Kes on Wolfgang Amadeus Mozart?", + "points": 40, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "cb6c52c1-d1f4-4c6a-a1c7-ddfa49966da8", + "question": "See Eesti helilooja on maailmas üks enim esitatud elavaid heliloojaid ja lõi unikaalse 'tintinnabuli' tehnika", + "answer": "Kes on Arvo Pärt?", + "points": 60, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "f22016ba-ff28-4388-bbd5-05c98e96c05a", + "question": "Seda Ameerika lauljat kutsuti popikuningaks ja tema albumid 'Thriller' ning 'Bad' on ajaloo enimmüüdute seas", + "answer": "Kes on Michael Jackson?", + "points": 80, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "c368877a-3b6d-4d8b-b5e3-6ce65a009daf", + "question": "See Saksa helilooja kirjutas oma kuulsa 9. sümfoonia olles juba täielikult kurt", + "answer": "Kes on Ludwig van Beethoven?", + "points": 100, + "isDailyDouble": false, + "isRevealed": false + } + ] + }, + { + "id": "b1797b2c-85da-4ff9-8d32-b1b81d9943b9", + "name": "SPORT", + "questions": [ + { + "id": "bb8f371e-d9c3-4b8b-90a7-9dbb1b35f94c", + "question": "Täpselt nii palju mängijaid viibib ühest jalgpallimeeskonnast korraga väljakul", + "answer": "Mis on 11?", + "points": 20, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "8646c184-764a-4d23-9687-87ce0ef9352c", + "question": "Selles riigis toimusid 2024. aasta suveolümpiamängud, mille avamine toimus Seine'i jõel", + "answer": "Mis on Prantsusmaa?", + "points": 40, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "86899b2b-9b58-4f71-beed-9a266f5e954a", + "question": "See Leedu kettaheitja võitis 2024. aasta Pariisi olümpial kuldmedali maailmarekordiga", + "answer": "Kes on Mykolas Alekna?", + "points": 60, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "ca2feea9-5045-489c-bde7-29961fae5793", + "question": "Sellel Serbia tennisistil on kõige rohkem Grand Slam'i tiitleid meeste üksikmängus ajaloo jooksul", + "answer": "Kes on Novak Djokovic?", + "points": 80, + "isDailyDouble": true, + "isRevealed": false + }, + { + "id": "b3d3fc4f-a48d-42eb-9d2a-8e19e9a8a832", + "question": "See Lõuna-Ameerika riik on võitnud kõige rohkem jalgpalli maailmameistritiitleid - täpselt viis korda", + "answer": "Mis on Brasiilia?", + "points": 100, + "isDailyDouble": false, + "isRevealed": false + } + ] + }, + { + "id": "0df7359e-dee5-4633-8da4-d0e11d310673", + "name": "FILMID JA TV", + "questions": [ + { + "id": "26c86d36-db24-461a-9f49-dab3d99dc563", + "question": "See Ameerika animatsioonistuudio lõi sellised hitid nagu 'Shrek', 'Kung Fu Panda' ja 'Kuidas taltsutada lohet'", + "answer": "Mis on DreamWorks?", + "points": 20, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "1a86912a-13a0-46c9-8354-31575c7b1511", + "question": "See Ameerika näitleja kehastab ekstsentrilist piraati Captain Jack Sparrow'd filmisarjas 'Kariibi mere piraadid'", + "answer": "Kes on Johnny Depp?", + "points": 40, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "38479718-87cf-4241-90c1-815abeb2c894", + "question": "See Ameerika kirjanik lõi fantaasiasarja 'Jää ja tule laul', mille põhjal valmis HBO menukas sari 'Game of Thrones'", + "answer": "Kes on George R. R. Martin?", + "points": 60, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "8215f3fa-a1a4-473a-8a8b-839dce4f1087", + "question": "See Kanada režissöör on loonud mõned ajaloo kallimad filmid, sealhulgas 'Titanic', 'Avatar' ja 'Terminator'", + "answer": "Kes on James Cameron?", + "points": 80, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "ee178b0f-d48e-4750-8677-8a0e57b3601f", + "question": "See Christopher Nolani film aatomipommi loomisest võitis 2024. aastal parima filmi Oscari", + "answer": "Mis on 'Oppenheimer'?", + "points": 100, + "isDailyDouble": false, + "isRevealed": false + } + ] + }, + { + "id": "748b9491-8f36-4071-bee8-23d24e59063c", + "name": "TOIT JA JOOK", + "questions": [ + { + "id": "71a422b5-b63a-4b1f-a3ce-2f6b51e73814", + "question": "Sellest Aasia riigist pärineb sushi - roog, mis koosneb riisist ja toorast kalast", + "answer": "Mis on Jaapan?", + "points": 20, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "eb178502-6317-4d6b-b79e-6fff66aa690a", + "question": "Seda pehmet Itaalia juustu kasutatakse traditsioonilises Caprese salatis koos tomatite ja basiilikuga", + "answer": "Mis on mozzarella?", + "points": 40, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "e3f07655-7032-49ab-909b-10dd6c3c74c1", + "question": "See India köögist pärit vürts annab karriroogadele iseloomuliku kollase värvi ja maitse", + "answer": "Mis on kurkum?", + "points": 60, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "11f6ca47-e31e-4ea1-b44e-9c4fa7bb0382", + "question": "Seda Eesti traditsioonilist suppi valmistatakse hapendatud kapsast ja serveeritakse sageli hapukoore ning sealihaga", + "answer": "Mis on hapukapsasupp?", + "points": 80, + "isDailyDouble": false, + "isRevealed": false + }, + { + "id": "d7b02c21-4337-4049-9a49-565d4cc2a318", + "question": "See Prantsuse magustoit koosneb vaniljekoorest, mille peale põletatakse kõva karamellikiht", + "answer": "Mis on crème brûlée?", + "points": 100, + "isDailyDouble": false, + "isRevealed": false + } + ] + } + ], + "pointMultiplier": 2 } ], "finalRound": { "category": "EESTI KULTUUR", - "question": "Mis aastal võitis Eesti esimest korda Eurovisiooni lauluvõistluse ja mis laul see oli?", - "answer": "2001. aastal lauluga 'Everybody' (Tanel Padar, Dave Benton ja 2XL)" + "question": "Aasta ja laul, millega Eesti võitis esimest korda Eurovisiooni lauluvõistluse", + "answer": "Mis on 2001 ja 'Everybody' (Tanel Padar, Dave Benton ja 2XL)?" } } \ No newline at end of file diff --git a/src/lib/stores/gameSession.svelte.ts b/src/lib/stores/gameSession.svelte.ts index 186b330..6d1f442 100644 --- a/src/lib/stores/gameSession.svelte.ts +++ b/src/lib/stores/gameSession.svelte.ts @@ -63,6 +63,7 @@ class GameSessionStore { private channel: BroadcastChannel | null = null; private timerInterval: ReturnType | null = null; private isTimerOwner = false; // Only one tab should own the timer + private projectorWindow: Window | null = null; // Track projector window for cleanup state = $state(null); constructor() { @@ -217,6 +218,18 @@ class GameSessionStore { if (browser) { localStorage.removeItem(STORAGE_KEY); this.broadcast("STATE_UPDATE", null as any); + // Keep projectorWindow reference so we can detect if tab is still open + } + } + + // Open or focus the projector window + openProjector() { + if (browser) { + // Reuse existing window if still open + if (this.projectorWindow && !this.projectorWindow.closed) { + return; // Already open, don't switch focus + } + this.projectorWindow = window.open("/kuldvillak/play?view=projector", "kuldvillak-projector"); } } @@ -334,16 +347,17 @@ class GameSessionStore { } } - // Skip question - 5 second delay, then shows answer + // Skip question - immediately reveal answer skipQuestion() { if (!this.state || !this.state.currentQuestion) return; // Stop timer if running this.state.timerRunning = false; this.state.activeTeamId = null; - // Mark as skipping and start countdown + // Mark as skipping and immediately show answer this.state.skippingQuestion = true; - this.state.timeoutCountdown = 5; + this.state.showAnswer = true; + this.state.revealCountdown = this.state.settings.answerRevealSeconds ?? 5; this.persist(); } diff --git a/src/lib/stores/persistence.test.ts b/src/lib/stores/persistence.test.ts new file mode 100644 index 0000000..3f652a8 --- /dev/null +++ b/src/lib/stores/persistence.test.ts @@ -0,0 +1,209 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import type { KuldvillakGame } from '$lib/types/kuldvillak'; +import { DEFAULT_SETTINGS, DEFAULT_STATE } from '$lib/types/kuldvillak'; + +// Mock localStorage +const localStorageMock = (() => { + let store: Record = {}; + return { + getItem: vi.fn((key: string) => store[key] ?? null), + setItem: vi.fn((key: string, value: string) => { store[key] = value; }), + removeItem: vi.fn((key: string) => { delete store[key]; }), + clear: vi.fn(() => { store = {}; }), + get length() { return Object.keys(store).length; }, + key: vi.fn((i: number) => Object.keys(store)[i] ?? null), + }; +})(); + +Object.defineProperty(global, 'localStorage', { value: localStorageMock }); + +// Import after mocking localStorage +import { + getKuldvillakGamesList, + getAllKuldvillakGames, + loadKuldvillakGame, + saveKuldvillakGame, + deleteKuldvillakGame, + duplicateKuldvillakGame, + setActiveKuldvillakGame, + getActiveKuldvillakGameId, +} from './persistence'; + +// Helper to create a test game +function createTestGame(overrides: Partial = {}): KuldvillakGame { + return { + id: 'test-game-id', + name: 'Test Game', + createdAt: '2024-01-01T00:00:00.000Z', + updatedAt: '2024-01-01T00:00:00.000Z', + settings: { ...DEFAULT_SETTINGS }, + teams: [ + { id: 'team-1', name: 'Team 1', score: 0 }, + { id: 'team-2', name: 'Team 2', score: 0 }, + ], + rounds: [{ + id: 'round-1', + name: 'Round 1', + pointMultiplier: 1, + categories: [{ + id: 'cat-1', + name: 'Category 1', + questions: [{ + id: 'q-1', + question: 'Test Question', + answer: 'Test Answer', + points: 100, + isDailyDouble: false, + isRevealed: false, + }], + }], + }], + finalRound: null, + state: { ...DEFAULT_STATE }, + ...overrides, + }; +} + +describe('Persistence', () => { + beforeEach(() => { + localStorageMock.clear(); + vi.clearAllMocks(); + }); + + describe('saveKuldvillakGame', () => { + it('should save a new game', () => { + const game = createTestGame(); + const result = saveKuldvillakGame(game); + + expect(result).toBe(true); + expect(localStorageMock.setItem).toHaveBeenCalled(); + }); + + it('should update existing game', () => { + const game = createTestGame(); + saveKuldvillakGame(game); + + game.name = 'Updated Name'; + saveKuldvillakGame(game); + + const games = getAllKuldvillakGames(); + expect(games).toHaveLength(1); + expect(games[0].name).toBe('Updated Name'); + }); + + it('should update the updatedAt timestamp', () => { + const game = createTestGame(); + const originalUpdatedAt = game.updatedAt; + + // Wait a tiny bit to ensure different timestamp + saveKuldvillakGame(game); + + const games = getAllKuldvillakGames(); + expect(games[0].updatedAt).not.toBe(originalUpdatedAt); + }); + }); + + describe('loadKuldvillakGame', () => { + it('should return null for non-existent game', () => { + const result = loadKuldvillakGame('non-existent-id'); + expect(result).toBeNull(); + }); + + it('should load existing game', () => { + const game = createTestGame(); + saveKuldvillakGame(game); + + const loaded = loadKuldvillakGame(game.id); + expect(loaded).not.toBeNull(); + expect(loaded?.name).toBe(game.name); + }); + }); + + describe('deleteKuldvillakGame', () => { + it('should delete a game', () => { + const game = createTestGame(); + saveKuldvillakGame(game); + + const result = deleteKuldvillakGame(game.id); + + expect(result).toBe(true); + expect(getAllKuldvillakGames()).toHaveLength(0); + }); + + it('should handle deleting non-existent game', () => { + const result = deleteKuldvillakGame('non-existent'); + expect(result).toBe(true); // Should not fail + }); + }); + + describe('duplicateKuldvillakGame', () => { + it('should create a duplicate with new ID', () => { + const original = createTestGame(); + saveKuldvillakGame(original); + + const duplicate = duplicateKuldvillakGame(original.id); + + expect(duplicate).not.toBeNull(); + expect(duplicate?.id).not.toBe(original.id); + expect(duplicate?.name).toBe(`${original.name} (Copy)`); + }); + + it('should reset game state in duplicate', () => { + const original = createTestGame(); + original.state.phase = 'board'; + original.teams[0].score = 500; + saveKuldvillakGame(original); + + const duplicate = duplicateKuldvillakGame(original.id); + + expect(duplicate?.state.phase).toBe('lobby'); + expect(duplicate?.teams[0].score).toBe(0); + }); + + it('should reset revealed questions in duplicate', () => { + const original = createTestGame(); + original.rounds[0].categories[0].questions[0].isRevealed = true; + saveKuldvillakGame(original); + + const duplicate = duplicateKuldvillakGame(original.id); + + expect(duplicate?.rounds[0].categories[0].questions[0].isRevealed).toBe(false); + }); + + it('should return null for non-existent game', () => { + const result = duplicateKuldvillakGame('non-existent'); + expect(result).toBeNull(); + }); + }); + + describe('getKuldvillakGamesList', () => { + it('should return empty array when no games', () => { + const result = getKuldvillakGamesList(); + expect(result).toEqual([]); + }); + + it('should return metadata for all games', () => { + saveKuldvillakGame(createTestGame({ id: 'game-1', name: 'Game 1' })); + saveKuldvillakGame(createTestGame({ id: 'game-2', name: 'Game 2' })); + + const list = getKuldvillakGamesList(); + + expect(list).toHaveLength(2); + expect(list[0].teamCount).toBe(2); + expect(list[0].roundCount).toBe(1); + }); + }); + + describe('Active Game', () => { + it('should set and get active game ID', () => { + setActiveKuldvillakGame('test-id'); + expect(getActiveKuldvillakGameId()).toBe('test-id'); + }); + + it('should clear active game when set to null', () => { + setActiveKuldvillakGame('test-id'); + setActiveKuldvillakGame(null); + expect(getActiveKuldvillakGameId()).toBeNull(); + }); + }); +}); diff --git a/src/lib/types/kuldvillak.test.ts b/src/lib/types/kuldvillak.test.ts new file mode 100644 index 0000000..caae25e --- /dev/null +++ b/src/lib/types/kuldvillak.test.ts @@ -0,0 +1,145 @@ +import { describe, it, expect } from 'vitest'; +import { DEFAULT_SETTINGS, DEFAULT_STATE } from './kuldvillak'; +import type { Team, Round, Question, GameSettings } from './kuldvillak'; + +describe('Kuldvillak Types', () => { + describe('DEFAULT_SETTINGS', () => { + it('should have correct number of rounds', () => { + expect(DEFAULT_SETTINGS.numberOfRounds).toBe(2); + }); + + it('should have 5 point values', () => { + expect(DEFAULT_SETTINGS.pointValues).toHaveLength(5); + expect(DEFAULT_SETTINGS.pointValues).toEqual([10, 20, 30, 40, 50]); + }); + + it('should have 6 categories per round', () => { + expect(DEFAULT_SETTINGS.categoriesPerRound).toBe(6); + }); + + it('should have 5 questions per category', () => { + expect(DEFAULT_SETTINGS.questionsPerCategory).toBe(5); + }); + + it('should have daily doubles configuration', () => { + expect(DEFAULT_SETTINGS.dailyDoublesPerRound).toEqual([1, 2]); + }); + + it('should enable final round by default', () => { + expect(DEFAULT_SETTINGS.enableFinalRound).toBe(true); + }); + + it('should allow negative scores by default', () => { + expect(DEFAULT_SETTINGS.allowNegativeScores).toBe(true); + }); + + it('should have 6 max teams', () => { + expect(DEFAULT_SETTINGS.maxTeams).toBe(6); + }); + + it('should have default timer of 5 seconds', () => { + expect(DEFAULT_SETTINGS.defaultTimerSeconds).toBe(5); + }); + + it('should have answer reveal of 5 seconds', () => { + expect(DEFAULT_SETTINGS.answerRevealSeconds).toBe(5); + }); + }); + + describe('DEFAULT_STATE', () => { + it('should start in lobby phase', () => { + expect(DEFAULT_STATE.phase).toBe('lobby'); + }); + + it('should start at round index 0', () => { + expect(DEFAULT_STATE.currentRoundIndex).toBe(0); + }); + + it('should have no active team', () => { + expect(DEFAULT_STATE.activeTeamId).toBeNull(); + }); + + it('should have empty final round data', () => { + expect(DEFAULT_STATE.finalWagers).toEqual({}); + expect(DEFAULT_STATE.finalAnswers).toEqual({}); + }); + }); + + describe('Type Validation Helpers', () => { + it('should validate team structure', () => { + const validTeam: Team = { + id: 'team-1', + name: 'Test Team', + score: 100, + }; + + expect(validTeam.id).toBeDefined(); + expect(validTeam.name).toBeDefined(); + expect(typeof validTeam.score).toBe('number'); + }); + + it('should validate question structure', () => { + const validQuestion: Question = { + id: 'q-1', + question: 'What is 2+2?', + answer: 'What is 4?', + points: 100, + isDailyDouble: false, + isRevealed: false, + }; + + expect(validQuestion.id).toBeDefined(); + expect(validQuestion.question).toBeDefined(); + expect(validQuestion.answer).toBeDefined(); + expect(typeof validQuestion.points).toBe('number'); + expect(typeof validQuestion.isDailyDouble).toBe('boolean'); + expect(typeof validQuestion.isRevealed).toBe('boolean'); + }); + + it('should validate optional imageUrl in question', () => { + const questionWithImage: Question = { + id: 'q-1', + question: 'What is shown?', + answer: 'What is a cat?', + points: 200, + isDailyDouble: false, + isRevealed: false, + imageUrl: 'https://example.com/image.jpg', + }; + + expect(questionWithImage.imageUrl).toBeDefined(); + }); + + it('should calculate point values correctly', () => { + const baseValue = 10; + const multiplier = 2; + const expectedValues = [20, 40, 60, 80, 100]; + + const calculatedValues = DEFAULT_SETTINGS.pointValues.map( + (v) => v * multiplier + ); + + expect(calculatedValues).toEqual(expectedValues); + }); + + it('should validate game phases', () => { + const validPhases = [ + 'lobby', + 'intro', + 'intro-categories', + 'board', + 'question', + 'daily-double', + 'final-intro', + 'final-category', + 'final-wager', + 'final-question', + 'final-reveal', + 'final-scores', + 'finished', + ]; + + expect(validPhases).toContain(DEFAULT_STATE.phase); + }); + }); +}); diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index df04f9d..ba40a88 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,11 +1,12 @@ + + + + {@render children()} diff --git a/src/routes/kuldvillak/+page.svelte b/src/routes/kuldvillak/+page.svelte index c60b34c..5843cf2 100644 --- a/src/routes/kuldvillak/+page.svelte +++ b/src/routes/kuldvillak/+page.svelte @@ -1,6 +1,6 @@