From 45cc83bfb2d89efff2fd7aea4bcf7479911521dc Mon Sep 17 00:00:00 2001 From: Joel Therrien Date: Wed, 15 May 2024 17:00:49 -0700 Subject: [PATCH] feat: Change API for multiplayer direction --- .gitignore | 5 +- src/lib.rs | 21 - src/wasm.rs | 213 -- ui/package-lock.json | 1919 +++++++++-------- ui/package.json | 4 +- ui/src/Game.tsx | 433 ++-- ui/src/Menu.tsx | 7 +- ui/src/TileExchange.tsx | 4 +- ui/src/UI.tsx | 5 +- ui/src/api.ts | 90 + ui/src/index.tsx | 2 +- ui/src/utils.ts | 13 +- ui/src/wasm.ts | 66 + wasm/Cargo.lock | 289 +++ wasm/Cargo.toml | 14 + wasm/src/lib.rs | 60 + wordgrid/Cargo.lock | 267 +++ Cargo.toml => wordgrid/Cargo.toml | 11 +- wordgrid/src/api.rs | 217 ++ {src => wordgrid/src}/board.rs | 382 ++-- {src => wordgrid/src}/constants.rs | 7 +- {src => wordgrid/src}/dictionary.rs | 22 +- {src => wordgrid/src}/game.rs | 335 +-- wordgrid/src/lib.rs | 6 + {src => wordgrid/src}/player_interaction.rs | 27 +- .../src}/player_interaction/ai.rs | 316 ++- 26 files changed, 2903 insertions(+), 1832 deletions(-) delete mode 100644 src/lib.rs delete mode 100644 src/wasm.rs create mode 100644 ui/src/api.ts create mode 100644 ui/src/wasm.ts create mode 100644 wasm/Cargo.lock create mode 100644 wasm/Cargo.toml create mode 100644 wasm/src/lib.rs create mode 100644 wordgrid/Cargo.lock rename Cargo.toml => wordgrid/Cargo.toml (59%) create mode 100644 wordgrid/src/api.rs rename {src => wordgrid/src}/board.rs (76%) rename {src => wordgrid/src}/constants.rs (99%) rename {src => wordgrid/src}/dictionary.rs (95%) rename {src => wordgrid/src}/game.rs (62%) create mode 100644 wordgrid/src/lib.rs rename {src => wordgrid/src}/player_interaction.rs (86%) rename {src => wordgrid/src}/player_interaction/ai.rs (82%) diff --git a/.gitignore b/.gitignore index 6e1a9fe..3bf1e12 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -/target +target/ /Cargo.lock .idea/ -pkg/ \ No newline at end of file +pkg/ +.nvmrc diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 4ee28f0..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -use wasm_bindgen::prelude::wasm_bindgen; - -pub mod constants; -pub mod board; -pub mod dictionary; -pub mod player_interaction; -pub mod game; -pub mod wasm; - - -#[wasm_bindgen] -extern { - pub fn alert(s: &str); -} - - -#[wasm_bindgen] -pub fn greet(name: &str) { - alert(&format!("Hello, {}!", name)); -} - diff --git a/src/wasm.rs b/src/wasm.rs deleted file mode 100644 index 1aa4bd2..0000000 --- a/src/wasm.rs +++ /dev/null @@ -1,213 +0,0 @@ -use serde::{Deserialize, Serialize}; -use serde_wasm_bindgen::Error; -use tsify::Tsify; -use wasm_bindgen::JsValue; -use wasm_bindgen::prelude::wasm_bindgen; -use crate::board::{CellType, Letter}; -use crate::game::{Game, GameState, PlayedTile}; -use crate::player_interaction::ai::Difficulty; - -#[wasm_bindgen] -pub struct GameWasm(Game); - -#[derive(Serialize, Deserialize, Tsify)] -#[tsify(from_wasm_abi)] -pub enum ResponseType { - OK, - ERR, -} - -#[derive(Serialize, Deserialize, Tsify)] -#[tsify(from_wasm_abi)] -pub struct MyResult { - response_type: ResponseType, - value: E, - game_state: Option, -} - - - - -#[wasm_bindgen] -impl GameWasm { - - #[wasm_bindgen(constructor)] - pub fn new(seed: u64, dictionary_text: &str, ai_difficulty: JsValue) -> GameWasm { - - let difficulty: Difficulty = serde_wasm_bindgen::from_value(ai_difficulty).unwrap(); - - GameWasm(Game::new(seed, dictionary_text, vec!["Player".to_string()], vec![difficulty])) - } - - pub fn get_tray(&self, name: &str) -> Result { - let tray = self.0.player_states.get_tray(name); - - serde_wasm_bindgen::to_value(&tray) - } - - pub fn get_board_cell_types(&self) -> Result { - let board = self.0.get_board(); - - let cell_types: Vec = board.cells.iter().map(|cell| -> CellType { - cell.cell_type.clone() - }).collect(); - - serde_wasm_bindgen::to_value(&cell_types) - } - - pub fn get_board_letters(&self) -> Result { - let board = self.0.get_board(); - - let letters: Vec> = board.cells.iter().map(|cell| -> Option { - cell.value.clone() - }).collect(); - - serde_wasm_bindgen::to_value(&letters) - } - - pub fn receive_play(&mut self, tray_tile_locations: JsValue, commit_move: bool) -> Result { - let tray_tile_locations: Vec> = serde_wasm_bindgen::from_value(tray_tile_locations)?; - - let result = self.0.receive_play(tray_tile_locations, commit_move); - - match result { - Ok((x, game_state)) => { - serde_wasm_bindgen::to_value(&MyResult { - response_type: ResponseType::OK, - value: x, - game_state: Some(game_state) - }) - }, - Err(e) => { - serde_wasm_bindgen::to_value(&MyResult { - response_type: ResponseType::ERR, - value: e, - game_state: None, - }) - } - } - - - } - - pub fn get_scores(&self) -> Result { - - #[derive(Serialize, Deserialize, Tsify)] - #[tsify(from_wasm_abi)] - pub struct PlayerAndScore { - name: String, - score: u32, - } - - let scores: Vec = self.0.player_states.0.iter() - .map(|player_state| { - PlayerAndScore { - name: player_state.player.get_name().to_string(), - score: player_state.score, - } - }) - .collect(); - - Ok(serde_wasm_bindgen::to_value(&scores)?) - - } - - pub fn exchange_tiles(&mut self, tray_tile_locations: JsValue) -> Result{ - - let tray_tile_locations: Vec = serde_wasm_bindgen::from_value(tray_tile_locations)?; - - match self.0.exchange_tiles(tray_tile_locations) { - Ok((_, turn_action, state)) => { - serde_wasm_bindgen::to_value(&MyResult { - response_type: ResponseType::OK, - value: turn_action, - game_state: Some(state), - }) - }, - Err(e) => { - serde_wasm_bindgen::to_value(&MyResult { - response_type: ResponseType::ERR, - value: e, - game_state: None, - }) - } - } - - - } - - pub fn add_word(&mut self, word: String) { - self.0.add_word(word); - } - - pub fn skip_turn(&mut self) -> Result{ - let result = self.0.pass(); - match result { - Ok(game_state) => { - Ok(serde_wasm_bindgen::to_value(&MyResult { - response_type: ResponseType::OK, - value: "Turn passed", - game_state: Some(game_state), - })?) - }, - Err(e) => { - Ok(serde_wasm_bindgen::to_value(&MyResult { - response_type: ResponseType::ERR, - value: e, - game_state: None, - })?) - } - } - } - - pub fn advance_turn(&mut self) -> Result { - let result = self.0.advance_turn(); - - match result { - Ok((turn_advance_result, game_state)) => { - Ok(serde_wasm_bindgen::to_value(&MyResult { - response_type: ResponseType::OK, - value: turn_advance_result, - game_state: Some(game_state), - })?) - }, - Err(e) => { - Ok(serde_wasm_bindgen::to_value(&MyResult { - response_type: ResponseType::ERR, - value: e, - game_state: None, - })?) - } - } - - - } - - pub fn get_current_player(&self) -> String { - self.0.current_player_name() - } - - pub fn get_remaining_tiles(&self) -> usize { - self.0.get_remaining_tiles() - } - - pub fn get_player_tile_count(&self, player: &str) -> Result { - match self.0.get_player_tile_count(player) { - Ok(count) => { - Ok(serde_wasm_bindgen::to_value(&MyResult{ - response_type: ResponseType::OK, - value: count, - game_state: None, - })?) - }, - Err(msg) => { - Ok(serde_wasm_bindgen::to_value(&MyResult{ - response_type: ResponseType::OK, - value: msg, - game_state: None, - })?) - } - } - } - -} \ No newline at end of file diff --git a/ui/package-lock.json b/ui/package-lock.json index 5adedb5..11e8ebc 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -7,110 +7,55 @@ "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", - "word_grid": "file:../pkg" + "word_grid": "file:../wasm/pkg" }, "devDependencies": { "@parcel/transformer-less": "^2.9.3", "@types/react": "^18.2.18", "@types/react-dom": "^18.2.7", - "parcel": "^2.9.3", + "parcel": "^2.12.0", "process": "^0.11.10" } }, - "../pkg": {}, + "../wasm/pkg": { + "name": "wasm", + "version": "0.1.0" + }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", + "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" + "@babel/highlight": "^7.25.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", + "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", + "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.25.7", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -121,6 +66,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -133,6 +79,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -147,6 +94,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -155,13 +103,15 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -171,6 +121,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -179,16 +130,18 @@ } }, "node_modules/@lezer/common": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.1.0.tgz", - "integrity": "sha512-XPIN3cYDXsoJI/oDWoR2tD++juVrhgIago9xyKhZ7IhGlzdDM9QgC8D8saKNCz5pindGcznFr2HBSsEQSWnSjw==", - "dev": true + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.2.tgz", + "integrity": "sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw==", + "dev": true, + "license": "MIT" }, "node_modules/@lezer/lr": { - "version": "1.3.13", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.13.tgz", - "integrity": "sha512-RLAbau/4uSzKgIKj96mI5WUtG1qtiR0Frn0Ei9zhPj8YOkHM+1Bb8SgdVvmR/aWJCFIzjo2KFnDiRZ75Xf5NdQ==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", + "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", "dev": true, + "license": "MIT", "dependencies": { "@lezer/common": "^1.0.0" } @@ -201,6 +154,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -214,6 +168,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -227,6 +182,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -240,6 +196,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -253,6 +210,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -266,6 +224,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -276,6 +235,7 @@ "resolved": "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.1.tgz", "integrity": "sha512-iA7+tyVqfrATAIsIRWQG+a7ZLLD0VaOCKV2Wd/v4mqIU3J9c4jx9p7S0nw1XH3gJCKNBOOwACOPYYSUu9pgT+w==", "dev": true, + "license": "MIT", "dependencies": { "@lezer/common": "^1.0.0", "@lezer/lr": "^1.0.0", @@ -286,99 +246,106 @@ } }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", - "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", + "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", - "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", + "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", - "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", + "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", - "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", - "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", + "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", - "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", + "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@parcel/bundler-default": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.10.0.tgz", - "integrity": "sha512-pn8McDCuS02/D9jSo9QUTIv3tBQLlJl0PD4FvrndORXLAIFGoQR7jO4lxTSJB/eVBXwqKNVIR7WpB4sjsnBFyg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.12.0.tgz", + "integrity": "sha512-3ybN74oYNMKyjD6V20c9Gerdbh7teeNvVMwIoHIQMzuIFT6IGX53PyOLlOKRLbjxMc0TMimQQxIt2eQqxR5LsA==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/graph": "3.0.0", - "@parcel/plugin": "2.10.0", - "@parcel/rust": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/graph": "3.2.0", + "@parcel/plugin": "2.12.0", + "@parcel/rust": "2.12.0", + "@parcel/utils": "2.12.0", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -386,14 +353,15 @@ } }, "node_modules/@parcel/cache": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.10.0.tgz", - "integrity": "sha512-4FzZpMTAAEFE65+O+Cf7f5kLLWRCiA+04IJdDYyQG5YzW1WujKXzrbh8B6tSSlw712dsQ/cUqNW4O0Q3FFKrfw==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.12.0.tgz", + "integrity": "sha512-FX5ZpTEkxvq/yvWklRHDESVRz+c7sLTXgFuzz6uEnBcXV38j6dMSikflNpHA6q/L4GKkCqRywm9R6XQwhwIMyw==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/fs": "2.10.0", - "@parcel/logger": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/fs": "2.12.0", + "@parcel/logger": "2.12.0", + "@parcel/utils": "2.12.0", "lmdb": "2.8.5" }, "engines": { @@ -404,14 +372,15 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.10.0" + "@parcel/core": "^2.12.0" } }, "node_modules/@parcel/codeframe": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.10.0.tgz", - "integrity": "sha512-hHp457tddXEWrOgHHaA/NtkOhOAyt4mpBUzhnPbWDONLu5xeg1mu1Jffiu2rlw5xajhphrUFDWyJW0/xq1815g==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.12.0.tgz", + "integrity": "sha512-v2VmneILFiHZJTxPiR7GEF1wey1/IXPdZMcUlNXBiPZyWDfcuNgGGVQkx/xW561rULLIvDPharOMdxz5oHOKQg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0" }, @@ -424,16 +393,17 @@ } }, "node_modules/@parcel/compressor-raw": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.10.0.tgz", - "integrity": "sha512-TXjosh5+kNN4lxENeIZ/2ZFQKWXpXlOoHhJbW4cGPXBMHxm0eimVpnFpD8xbWxg7VCcWzbEaUTp20GQ153X+9A==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.12.0.tgz", + "integrity": "sha512-h41Q3X7ZAQ9wbQ2csP8QGrwepasLZdXiuEdpUryDce6rF9ZiHoJ97MRpdLxOhOPyASTw/xDgE1xyaPQr0Q3f5A==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0" + "@parcel/plugin": "2.12.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -441,72 +411,74 @@ } }, "node_modules/@parcel/config-default": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.10.0.tgz", - "integrity": "sha512-7Ucd+KNEC08To2NrduC/yIHBN5ayedBoiuI5OVrDeKvyqUnI1S1HRqPF3DsrM8pC2PIdnwJgoOviRXwJemW28A==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.12.0.tgz", + "integrity": "sha512-dPNe2n9eEsKRc1soWIY0yToMUPirPIa2QhxcCB3Z5RjpDGIXm0pds+BaiqY6uGLEEzsjhRO0ujd4v2Rmm0vuFg==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/bundler-default": "2.10.0", - "@parcel/compressor-raw": "2.10.0", - "@parcel/namer-default": "2.10.0", - "@parcel/optimizer-css": "2.10.0", - "@parcel/optimizer-htmlnano": "2.10.0", - "@parcel/optimizer-image": "2.10.0", - "@parcel/optimizer-svgo": "2.10.0", - "@parcel/optimizer-swc": "2.10.0", - "@parcel/packager-css": "2.10.0", - "@parcel/packager-html": "2.10.0", - "@parcel/packager-js": "2.10.0", - "@parcel/packager-raw": "2.10.0", - "@parcel/packager-svg": "2.10.0", - "@parcel/packager-wasm": "2.10.0", - "@parcel/reporter-dev-server": "2.10.0", - "@parcel/resolver-default": "2.10.0", - "@parcel/runtime-browser-hmr": "2.10.0", - "@parcel/runtime-js": "2.10.0", - "@parcel/runtime-react-refresh": "2.10.0", - "@parcel/runtime-service-worker": "2.10.0", - "@parcel/transformer-babel": "2.10.0", - "@parcel/transformer-css": "2.10.0", - "@parcel/transformer-html": "2.10.0", - "@parcel/transformer-image": "2.10.0", - "@parcel/transformer-js": "2.10.0", - "@parcel/transformer-json": "2.10.0", - "@parcel/transformer-postcss": "2.10.0", - "@parcel/transformer-posthtml": "2.10.0", - "@parcel/transformer-raw": "2.10.0", - "@parcel/transformer-react-refresh-wrap": "2.10.0", - "@parcel/transformer-svg": "2.10.0" + "@parcel/bundler-default": "2.12.0", + "@parcel/compressor-raw": "2.12.0", + "@parcel/namer-default": "2.12.0", + "@parcel/optimizer-css": "2.12.0", + "@parcel/optimizer-htmlnano": "2.12.0", + "@parcel/optimizer-image": "2.12.0", + "@parcel/optimizer-svgo": "2.12.0", + "@parcel/optimizer-swc": "2.12.0", + "@parcel/packager-css": "2.12.0", + "@parcel/packager-html": "2.12.0", + "@parcel/packager-js": "2.12.0", + "@parcel/packager-raw": "2.12.0", + "@parcel/packager-svg": "2.12.0", + "@parcel/packager-wasm": "2.12.0", + "@parcel/reporter-dev-server": "2.12.0", + "@parcel/resolver-default": "2.12.0", + "@parcel/runtime-browser-hmr": "2.12.0", + "@parcel/runtime-js": "2.12.0", + "@parcel/runtime-react-refresh": "2.12.0", + "@parcel/runtime-service-worker": "2.12.0", + "@parcel/transformer-babel": "2.12.0", + "@parcel/transformer-css": "2.12.0", + "@parcel/transformer-html": "2.12.0", + "@parcel/transformer-image": "2.12.0", + "@parcel/transformer-js": "2.12.0", + "@parcel/transformer-json": "2.12.0", + "@parcel/transformer-postcss": "2.12.0", + "@parcel/transformer-posthtml": "2.12.0", + "@parcel/transformer-raw": "2.12.0", + "@parcel/transformer-react-refresh-wrap": "2.12.0", + "@parcel/transformer-svg": "2.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.10.0" + "@parcel/core": "^2.12.0" } }, "node_modules/@parcel/core": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.10.0.tgz", - "integrity": "sha512-8jvLhLC2503HIBphJe/C1qL3bfiTSw6WgIDH0e7B8EL0v7v2JYnlTZ8o9myf+bMAxzwNLiZ2uEDCri9EWbi4tQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.12.0.tgz", + "integrity": "sha512-s+6pwEj+GfKf7vqGUzN9iSEPueUssCCQrCBUlcAfKrJe0a22hTUCjewpB0I7lNrCIULt8dkndD+sMdOrXsRl6Q==", "dev": true, + "license": "MIT", "dependencies": { "@mischnic/json-sourcemap": "^0.1.0", - "@parcel/cache": "2.10.0", - "@parcel/diagnostic": "2.10.0", - "@parcel/events": "2.10.0", - "@parcel/fs": "2.10.0", - "@parcel/graph": "3.0.0", - "@parcel/logger": "2.10.0", - "@parcel/package-manager": "2.10.0", - "@parcel/plugin": "2.10.0", - "@parcel/profiler": "2.10.0", - "@parcel/rust": "2.10.0", + "@parcel/cache": "2.12.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/events": "2.12.0", + "@parcel/fs": "2.12.0", + "@parcel/graph": "3.2.0", + "@parcel/logger": "2.12.0", + "@parcel/package-manager": "2.12.0", + "@parcel/plugin": "2.12.0", + "@parcel/profiler": "2.12.0", + "@parcel/rust": "2.12.0", "@parcel/source-map": "^2.1.1", - "@parcel/types": "2.10.0", - "@parcel/utils": "2.10.0", - "@parcel/workers": "2.10.0", + "@parcel/types": "2.12.0", + "@parcel/utils": "2.12.0", + "@parcel/workers": "2.12.0", "abortcontroller-polyfill": "^1.1.9", "base-x": "^3.0.8", "browserslist": "^4.6.6", @@ -514,7 +486,7 @@ "dotenv": "^7.0.0", "dotenv-expand": "^5.1.0", "json5": "^2.2.0", - "msgpackr": "^1.5.4", + "msgpackr": "^1.9.9", "nullthrows": "^1.1.1", "semver": "^7.5.2" }, @@ -527,10 +499,11 @@ } }, "node_modules/@parcel/diagnostic": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.10.0.tgz", - "integrity": "sha512-ibr+sUZLc0MW75b+nThOa6YEi9QXTNYbUNCo067mtMIfhKNYTx24DaiGzDWgy1Yv49eucBaQ4u7gFI2Qa98uIA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.12.0.tgz", + "integrity": "sha512-8f1NOsSFK+F4AwFCKynyIu9Kr/uWHC+SywAv4oS6Bv3Acig0gtwUjugk0C9UaB8ztBZiW5TQZhw+uPZn9T/lJA==", "dev": true, + "license": "MIT", "dependencies": { "@mischnic/json-sourcemap": "^0.1.0", "nullthrows": "^1.1.1" @@ -544,10 +517,11 @@ } }, "node_modules/@parcel/events": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.10.0.tgz", - "integrity": "sha512-mhykJBnP3BPMI6A9hLZmTtmNHZuE+HGzsF6vzmA2YBuU3/BGlQUmxdObsmwQ1O24eq0EfJVwTM+R/bdu+/nFrA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.12.0.tgz", + "integrity": "sha512-nmAAEIKLjW1kB2cUbCYSmZOGbnGj8wCzhqnK727zCCWaA25ogzAtt657GPOeFyqW77KyosU728Tl63Fc8hphIA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12.0.0" }, @@ -557,16 +531,17 @@ } }, "node_modules/@parcel/fs": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.10.0.tgz", - "integrity": "sha512-so39KdZ4o7tDekeuuQfQdbfTUvldUtzvIsuUtJMqxVOVJRZr9VjieR9GbeFhqRmi9fM5oYdzQn4lbduKdAtANA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.12.0.tgz", + "integrity": "sha512-NnFkuvou1YBtPOhTdZr44WN7I60cGyly2wpHzqRl62yhObyi1KvW0SjwOMa0QGNcBOIzp4G0CapoZ93hD0RG5Q==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/rust": "2.10.0", - "@parcel/types": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/rust": "2.12.0", + "@parcel/types": "2.12.0", + "@parcel/utils": "2.12.0", "@parcel/watcher": "^2.0.7", - "@parcel/workers": "2.10.0" + "@parcel/workers": "2.12.0" }, "engines": { "node": ">= 12.0.0" @@ -576,14 +551,15 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.10.0" + "@parcel/core": "^2.12.0" } }, "node_modules/@parcel/graph": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-3.0.0.tgz", - "integrity": "sha512-8Lussud6gWRM3Mysu+veBRsBdSlWgkM8y7PvF8AiRwEY2eiVxZ3Rgh8o9KJau3B8R8q+lyCaUElYpbnUT6Bkiw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-3.2.0.tgz", + "integrity": "sha512-xlrmCPqy58D4Fg5umV7bpwDx5Vyt7MlnQPxW68vae5+BA4GSWetfZt+Cs5dtotMG2oCHzZxhIPt7YZ7NRyQzLA==", "dev": true, + "license": "MIT", "dependencies": { "nullthrows": "^1.1.1" }, @@ -596,13 +572,14 @@ } }, "node_modules/@parcel/logger": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.10.0.tgz", - "integrity": "sha512-rDa48czGBZA313scvSEkuHSOQiGdoYLaWqInZBKtl0zke3qrgTFNG4b173H6IFdNq5KmKjafBxaV5jG87i4Gww==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.12.0.tgz", + "integrity": "sha512-cJ7Paqa7/9VJ7C+KwgJlwMqTQBOjjn71FbKk0G07hydUEBISU2aDfmc/52o60ErL9l+vXB26zTrIBanbxS8rVg==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/events": "2.10.0" + "@parcel/diagnostic": "2.12.0", + "@parcel/events": "2.12.0" }, "engines": { "node": ">= 12.0.0" @@ -613,10 +590,11 @@ } }, "node_modules/@parcel/markdown-ansi": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.10.0.tgz", - "integrity": "sha512-fuOuFglNANegE2nqVURwOJ/HzKM28O0hqy120Gl0NTbCAFbG34WCFxfkmVio8fondD4NcZcDj5GGv5P5TWcTIg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.12.0.tgz", + "integrity": "sha512-WZz3rzL8k0H3WR4qTHX6Ic8DlEs17keO9gtD4MNGyMNQbqQEvQ61lWJaIH0nAtgEetu0SOITiVqdZrb8zx/M7w==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0" }, @@ -629,18 +607,19 @@ } }, "node_modules/@parcel/namer-default": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.10.0.tgz", - "integrity": "sha512-N1IF6A8Y2fYz0BteU9IkhPQGezLA3cKkoSxoIOTiUf2LZPpUIuCGEAB1IgaUVNdAeMVsGw3UrdEYZg4xdMovEg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.12.0.tgz", + "integrity": "sha512-9DNKPDHWgMnMtqqZIMiEj/R9PNWW16lpnlHjwK3ciRlMPgjPJ8+UNc255teZODhX0T17GOzPdGbU/O/xbxVPzA==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/plugin": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/plugin": "2.12.0", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -648,16 +627,17 @@ } }, "node_modules/@parcel/node-resolver-core": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-3.1.0.tgz", - "integrity": "sha512-0KBdWIXCpnDzjoZgc1qHhgxtNe5CZ4r4+Iht+LExacXwG1A1O5qKLQE1bBAgcjqkgv1iglVuMx0kVe9G8oob8A==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-3.3.0.tgz", + "integrity": "sha512-rhPW9DYPEIqQBSlYzz3S0AjXxjN6Ub2yS6tzzsW/4S3Gpsgk/uEq4ZfxPvoPf/6TgZndVxmKwpmxaKtGMmf3cA==", "dev": true, + "license": "MIT", "dependencies": { "@mischnic/json-sourcemap": "^0.1.0", - "@parcel/diagnostic": "2.10.0", - "@parcel/fs": "2.10.0", - "@parcel/rust": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/fs": "2.12.0", + "@parcel/rust": "2.12.0", + "@parcel/utils": "2.12.0", "nullthrows": "^1.1.1", "semver": "^7.5.2" }, @@ -670,22 +650,23 @@ } }, "node_modules/@parcel/optimizer-css": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.10.0.tgz", - "integrity": "sha512-D7hFYjJpudlbSgMlzwSbSguLehwGe4vJrQ4s83jj7z0UlHd74Vir9fd9LQTPuUErgs2SOQIPxFwLGqR6Hi+mOg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.12.0.tgz", + "integrity": "sha512-ifbcC97fRzpruTjaa8axIFeX4MjjSIlQfem3EJug3L2AVqQUXnM1XO8L0NaXGNLTW2qnh1ZjIJ7vXT/QhsphsA==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/plugin": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/plugin": "2.12.0", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.10.0", + "@parcel/utils": "2.12.0", "browserslist": "^4.6.6", - "lightningcss": "^1.16.1", + "lightningcss": "^1.22.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -693,12 +674,13 @@ } }, "node_modules/@parcel/optimizer-htmlnano": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.10.0.tgz", - "integrity": "sha512-uYmluYpyyVumY7d/aHkGnFVLzOHoGqzVF9os/PkqVOnGEQ3qQibO3Hl9neTtm2GEUgeOfq1lrXLEfpW/k3qG1w==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.12.0.tgz", + "integrity": "sha512-MfPMeCrT8FYiOrpFHVR+NcZQlXAptK2r4nGJjfT+ndPBhEEZp4yyL7n1y7HfX9geg5altc4WTb4Gug7rCoW8VQ==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0", + "@parcel/plugin": "2.12.0", "htmlnano": "^2.0.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", @@ -706,7 +688,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -718,6 +700,7 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.0.1", @@ -734,6 +717,7 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", "dev": true, + "license": "MIT", "dependencies": { "mdn-data": "2.0.14", "source-map": "^0.6.1" @@ -747,6 +731,7 @@ "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", "dev": true, + "license": "MIT", "dependencies": { "css-tree": "^1.1.2" }, @@ -758,13 +743,15 @@ "version": "2.0.14", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true + "dev": true, + "license": "CC0-1.0" }, "node_modules/@parcel/optimizer-htmlnano/node_modules/svgo": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", "dev": true, + "license": "MIT", "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", @@ -782,43 +769,45 @@ } }, "node_modules/@parcel/optimizer-image": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.10.0.tgz", - "integrity": "sha512-uR/nd3kRxiQuPxB0nP5WLlydTUwRHcpFPAY0iV12cyjCQs+MaZHrhwoDO8kWVaT7jN7WXKYcSIHeP1kvR0HEQw==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.12.0.tgz", + "integrity": "sha512-bo1O7raeAIbRU5nmNVtx8divLW9Xqn0c57GVNGeAK4mygnQoqHqRZ0mR9uboh64pxv6ijXZHPhKvU9HEpjPjBQ==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/plugin": "2.10.0", - "@parcel/rust": "2.10.0", - "@parcel/utils": "2.10.0", - "@parcel/workers": "2.10.0" + "@parcel/diagnostic": "2.12.0", + "@parcel/plugin": "2.12.0", + "@parcel/rust": "2.12.0", + "@parcel/utils": "2.12.0", + "@parcel/workers": "2.12.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.10.0" + "@parcel/core": "^2.12.0" } }, "node_modules/@parcel/optimizer-svgo": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.10.0.tgz", - "integrity": "sha512-2IXClEpjlafidKAiOh/+amdDWOHGtA4Sil/3flmhLkjNFh7z2bGTYodO5xvC3Umw6N11fPNL1Wch1jn54fMO1g==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.12.0.tgz", + "integrity": "sha512-Kyli+ZZXnoonnbeRQdoWwee9Bk2jm/49xvnfb+2OO8NN0d41lblBoRhOyFiScRnJrw7eVl1Xrz7NTkXCIO7XFQ==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/plugin": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/plugin": "2.12.0", + "@parcel/utils": "2.12.0", "svgo": "^2.4.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -830,6 +819,7 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.0.1", @@ -846,6 +836,7 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", "dev": true, + "license": "MIT", "dependencies": { "mdn-data": "2.0.14", "source-map": "^0.6.1" @@ -859,6 +850,7 @@ "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", "dev": true, + "license": "MIT", "dependencies": { "css-tree": "^1.1.2" }, @@ -870,13 +862,15 @@ "version": "2.0.14", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true + "dev": true, + "license": "CC0-1.0" }, "node_modules/@parcel/optimizer-svgo/node_modules/svgo": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", "dev": true, + "license": "MIT", "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", @@ -894,21 +888,22 @@ } }, "node_modules/@parcel/optimizer-swc": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-swc/-/optimizer-swc-2.10.0.tgz", - "integrity": "sha512-yq17TG6uyzIbiouK57AngJa6rVwfJ8hPzgc2lqZ9LJxDX07t/5Z+k/+aq4Izy+7kQNR8kH+4asWaMXReSsXmNQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-swc/-/optimizer-swc-2.12.0.tgz", + "integrity": "sha512-iBi6LZB3lm6WmbXfzi8J3DCVPmn4FN2lw7DGXxUXu7MouDPVWfTsM6U/5TkSHJRNRogZ2gqy5q9g34NPxHbJcw==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/plugin": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/plugin": "2.12.0", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.10.0", + "@parcel/utils": "2.12.0", "@swc/core": "^1.3.36", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -916,18 +911,20 @@ } }, "node_modules/@parcel/package-manager": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.10.0.tgz", - "integrity": "sha512-BBUhwgX2Rz92SqGCyYp5Du4UEzm/bjrSSoeLtuRRevWKTVXhgHGbqcAlZmICoxb1lZGpn8x+pEivWd3w+5M7iA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.12.0.tgz", + "integrity": "sha512-0nvAezcjPx9FT+hIL+LS1jb0aohwLZXct7jAh7i0MLMtehOi0z1Sau+QpgMlA9rfEZZ1LIeFdnZZwqSy7Ccspw==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/fs": "2.10.0", - "@parcel/logger": "2.10.0", - "@parcel/node-resolver-core": "3.1.0", - "@parcel/types": "2.10.0", - "@parcel/utils": "2.10.0", - "@parcel/workers": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/fs": "2.12.0", + "@parcel/logger": "2.12.0", + "@parcel/node-resolver-core": "3.3.0", + "@parcel/types": "2.12.0", + "@parcel/utils": "2.12.0", + "@parcel/workers": "2.12.0", + "@swc/core": "^1.3.36", "semver": "^7.5.2" }, "engines": { @@ -938,24 +935,26 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.10.0" + "@parcel/core": "^2.12.0" } }, "node_modules/@parcel/packager-css": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.10.0.tgz", - "integrity": "sha512-BY1PoPPOngiJ6gFD+mUQ6YZvwDxlth8oCU9328T8kFwhmA4qL6pfIxNPI1I53Ig5f38tf1nhFkHACDCbs4MxaQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.12.0.tgz", + "integrity": "sha512-j3a/ODciaNKD19IYdWJT+TP+tnhhn5koBGBWWtrKSu0UxWpnezIGZetit3eE+Y9+NTePalMkvpIlit2eDhvfJA==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/plugin": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/plugin": "2.12.0", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.10.0", + "@parcel/utils": "2.12.0", + "lightningcss": "^1.22.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -963,20 +962,21 @@ } }, "node_modules/@parcel/packager-html": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.10.0.tgz", - "integrity": "sha512-EtxQwuQXQ6zrPRG9/pIdIcvuDCzBEsAnjN9kZ+XuxEYGoReX7weN4oALA6gCnw3w7U4cq6+VR1R08F6Cd8T2MQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.12.0.tgz", + "integrity": "sha512-PpvGB9hFFe+19NXGz2ApvPrkA9GwEqaDAninT+3pJD57OVBaxB8U+HN4a5LICKxjUppPPqmrLb6YPbD65IX4RA==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0", - "@parcel/types": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/plugin": "2.12.0", + "@parcel/types": "2.12.0", + "@parcel/utils": "2.12.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -984,23 +984,24 @@ } }, "node_modules/@parcel/packager-js": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.10.0.tgz", - "integrity": "sha512-9r1pv8GScZzgGempexikym9d1aehTAp0DxK71LUxBT0os9Br+nJOtV4wmJWnHapt4r108d75DcgtytdVM5nuqA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.12.0.tgz", + "integrity": "sha512-viMF+FszITRRr8+2iJyk+4ruGiL27Y6AF7hQ3xbJfzqnmbOhGFtLTQwuwhOLqN/mWR2VKdgbLpZSarWaO3yAMg==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/plugin": "2.10.0", - "@parcel/rust": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/plugin": "2.12.0", + "@parcel/rust": "2.12.0", "@parcel/source-map": "^2.1.1", - "@parcel/types": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/types": "2.12.0", + "@parcel/utils": "2.12.0", "globals": "^13.2.0", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1008,16 +1009,17 @@ } }, "node_modules/@parcel/packager-raw": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.10.0.tgz", - "integrity": "sha512-fk1XGqMP38uyWC1Jqg8/Mp1x0dLxfd9GnmLHQCUZ0OSQLwF9Nqpow1WR4tC8juxYNK5haGqKyL9X5pVN4KLNYQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.12.0.tgz", + "integrity": "sha512-tJZqFbHqP24aq1F+OojFbQIc09P/u8HAW5xfndCrFnXpW4wTgM3p03P0xfw3gnNq+TtxHJ8c3UFE5LnXNNKhYA==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0" + "@parcel/plugin": "2.12.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1025,19 +1027,20 @@ } }, "node_modules/@parcel/packager-svg": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.10.0.tgz", - "integrity": "sha512-+vXXZwENinz/N2m04tH5BDSc8Zv7XNd/fsXZ3BAcEWmYpiTHBYMgbIy+fsdQb1tpFwku7CezthHFDsXejyNtrg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.12.0.tgz", + "integrity": "sha512-ldaGiacGb2lLqcXas97k8JiZRbAnNREmcvoY2W2dvW4loVuDT9B9fU777mbV6zODpcgcHWsLL3lYbJ5Lt3y9cg==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0", - "@parcel/types": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/plugin": "2.12.0", + "@parcel/types": "2.12.0", + "@parcel/utils": "2.12.0", "posthtml": "^0.16.4" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1045,16 +1048,17 @@ } }, "node_modules/@parcel/packager-wasm": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/packager-wasm/-/packager-wasm-2.10.0.tgz", - "integrity": "sha512-G/OsV9Xpyu1D/mTwazw4FkWlFotcFMaRmejmc6km3+qjaFxMubRBLCNMCvGw2lDIhA40qz/DpZS/kblB/FGSPA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/packager-wasm/-/packager-wasm-2.12.0.tgz", + "integrity": "sha512-fYqZzIqO9fGYveeImzF8ll6KRo2LrOXfD+2Y5U3BiX/wp9wv17dz50QLDQm9hmTcKGWxK4yWqKQh+Evp/fae7A==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0" + "@parcel/plugin": "2.12.0" }, "engines": { "node": ">=12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1062,12 +1066,13 @@ } }, "node_modules/@parcel/plugin": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.10.0.tgz", - "integrity": "sha512-FaWchkYJxLOohNNb3ah9R/9gckew+iGOzcGZ1bUtLGc/Dwz1mTVeaAanqOjlZ6C5FCe9lMctkH7h0eQsJ0mlVQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.12.0.tgz", + "integrity": "sha512-nc/uRA8DiMoe4neBbzV6kDndh/58a4wQuGKw5oEoIwBCHUvE2W8ZFSu7ollSXUGRzfacTt4NdY8TwS73ScWZ+g==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/types": "2.10.0" + "@parcel/types": "2.12.0" }, "engines": { "node": ">= 12.0.0" @@ -1078,13 +1083,14 @@ } }, "node_modules/@parcel/profiler": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/profiler/-/profiler-2.10.0.tgz", - "integrity": "sha512-SGkslseYA5TQOb8Z7gepi7YiIv3uH4BYAM9nwduMZrRZENcICbgTh1Pb+dp10y+6k9hFFH748eHtxJqSWARDBw==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/profiler/-/profiler-2.12.0.tgz", + "integrity": "sha512-q53fvl5LDcFYzMUtSusUBZSjQrKjMlLEBgKeQHFwkimwR1mgoseaDBDuNz0XvmzDzF1UelJ02TUKCGacU8W2qA==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/events": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/events": "2.12.0", "chrome-trace-event": "^1.0.2" }, "engines": { @@ -1096,20 +1102,21 @@ } }, "node_modules/@parcel/reporter-cli": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.10.0.tgz", - "integrity": "sha512-+OtZUdmHFgNY8+w3/U7dEZKMTtIFh7EiFw5VelKIGdvJrZNa9j7vbFuZziK6zUW2uopCk4qsDinn6Rfi7M16KA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.12.0.tgz", + "integrity": "sha512-TqKsH4GVOLPSCanZ6tcTPj+rdVHERnt5y4bwTM82cajM21bCX1Ruwp8xOKU+03091oV2pv5ieB18pJyRF7IpIw==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0", - "@parcel/types": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/plugin": "2.12.0", + "@parcel/types": "2.12.0", + "@parcel/utils": "2.12.0", "chalk": "^4.1.0", "term-size": "^2.2.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1117,17 +1124,18 @@ } }, "node_modules/@parcel/reporter-dev-server": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.10.0.tgz", - "integrity": "sha512-1dMkVgbfx+AxRVjzX5on3LOY8Vhsr4wuwQdLhmN1kAveTNWUYBPSVzIt5ZPVj3Cmpwpaonj7tHkZ2YujaNWHQg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.12.0.tgz", + "integrity": "sha512-tIcDqRvAPAttRlTV28dHcbWT5K2r/MBFks7nM4nrEDHWtnrCwimkDmZTc1kD8QOCCjGVwRHcQybpHvxfwol6GA==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0", - "@parcel/utils": "2.10.0" + "@parcel/plugin": "2.12.0", + "@parcel/utils": "2.12.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1135,19 +1143,20 @@ } }, "node_modules/@parcel/reporter-tracer": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/reporter-tracer/-/reporter-tracer-2.10.0.tgz", - "integrity": "sha512-mlxF3ozH6Kys4hewG1Bze1q8wHJL1ue276Qek9xPJly8ed08wU7rPGZF0vz8fJfKT8vx+nGvnKFXYiHjF+w6bg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/reporter-tracer/-/reporter-tracer-2.12.0.tgz", + "integrity": "sha512-g8rlu9GxB8Ut/F8WGx4zidIPQ4pcYFjU9bZO+fyRIPrSUFH2bKijCnbZcr4ntqzDGx74hwD6cCG4DBoleq2UlQ==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/plugin": "2.12.0", + "@parcel/utils": "2.12.0", "chrome-trace-event": "^1.0.3", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1155,17 +1164,18 @@ } }, "node_modules/@parcel/resolver-default": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.10.0.tgz", - "integrity": "sha512-KWtKrmjf/CAyZkk+SSwHhMMwN6cjJJRtUSLCvwbrlevd0onRl3erUdVYrJrNB5X+N8ylCO6Vb0wCyMegOo/OwQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.12.0.tgz", + "integrity": "sha512-uuhbajTax37TwCxu7V98JtRLiT6hzE4VYSu5B7Qkauy14/WFt2dz6GOUXPgVsED569/hkxebPx3KCMtZW6cHHA==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/node-resolver-core": "3.1.0", - "@parcel/plugin": "2.10.0" + "@parcel/node-resolver-core": "3.3.0", + "@parcel/plugin": "2.12.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1173,17 +1183,18 @@ } }, "node_modules/@parcel/runtime-browser-hmr": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.10.0.tgz", - "integrity": "sha512-x22HHUAFuhycE/NGowkEaR7zeZsp8PcViHkmuNkSvLboe8PJvq4BFpnd+RUj+o8EjN31p+8K2pFqS1hYAmtdwg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.12.0.tgz", + "integrity": "sha512-4ZLp2FWyD32r0GlTulO3+jxgsA3oO1P1b5oO2IWuWilfhcJH5LTiazpL5YdusUjtNn9PGN6QLAWfxmzRIfM+Ow==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0", - "@parcel/utils": "2.10.0" + "@parcel/plugin": "2.12.0", + "@parcel/utils": "2.12.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1191,19 +1202,20 @@ } }, "node_modules/@parcel/runtime-js": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.10.0.tgz", - "integrity": "sha512-AyDY+tQ9jiip6YsDGbaw7Azj60qG4fWNniUMIRMsywKQZOySLpfMNGHUcwDkV8j1NTve87Cwr2EzMOMnQHaUsQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.12.0.tgz", + "integrity": "sha512-sBerP32Z1crX5PfLNGDSXSdqzlllM++GVnVQVeM7DgMKS8JIFG3VLi28YkX+dYYGtPypm01JoIHCkvwiZEcQJg==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/plugin": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/plugin": "2.12.0", + "@parcel/utils": "2.12.0", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1211,19 +1223,20 @@ } }, "node_modules/@parcel/runtime-react-refresh": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.10.0.tgz", - "integrity": "sha512-hmiK9i6iitdjfcCaI0888+pecQHA0dzf6wMKnwtJsYQxCv2TrwXPsSOMHjkKr1K3ALXi8vlauG4K0Rm7c+vfdw==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.12.0.tgz", + "integrity": "sha512-SCHkcczJIDFTFdLTzrHTkQ0aTrX3xH6jrA4UsCBL6ji61+w+ohy4jEEe9qCgJVXhnJfGLE43HNXek+0MStX+Mw==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/plugin": "2.12.0", + "@parcel/utils": "2.12.0", "react-error-overlay": "6.0.9", "react-refresh": "^0.9.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1231,18 +1244,19 @@ } }, "node_modules/@parcel/runtime-service-worker": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.10.0.tgz", - "integrity": "sha512-vi84PwAsyPI1P/5FTt1uNKjH1NGizQRdS4CmjBMz+VBT6GVuXMgZ9iQy3OYC8MsiyHlyG7mScftI74RWqw1DDg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.12.0.tgz", + "integrity": "sha512-BXuMBsfiwpIEnssn+jqfC3jkgbS8oxeo3C7xhSQsuSv+AF2FwY3O3AO1c1RBskEW3XrBLNINOJujroNw80VTKA==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/plugin": "2.12.0", + "@parcel/utils": "2.12.0", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1250,10 +1264,11 @@ } }, "node_modules/@parcel/rust": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/rust/-/rust-2.10.0.tgz", - "integrity": "sha512-9J7riqPI8mVlFSDphK9kVUH8nFQgeMbO/95Ycf4vaEOVE1ICQo1h18WHAy2DndmL1uSd/UTimirrP6yLt/I3KA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/rust/-/rust-2.12.0.tgz", + "integrity": "sha512-005cldMdFZFDPOjbDVEXcINQ3wT4vrxvSavRWI3Az0e3E18exO/x/mW9f648KtXugOXMAqCEqhFHcXECL9nmMw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12.0.0" }, @@ -1267,6 +1282,7 @@ "resolved": "https://registry.npmjs.org/@parcel/source-map/-/source-map-2.1.1.tgz", "integrity": "sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==", "dev": true, + "license": "MIT", "dependencies": { "detect-libc": "^1.0.3" }, @@ -1275,15 +1291,16 @@ } }, "node_modules/@parcel/transformer-babel": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.10.0.tgz", - "integrity": "sha512-XwlzHt7WPfueFlwl/bXItopgZ6ILSPzl5OmPeytHrM2TanymeLjJ1y3vxwY1C1BhNlrTwPHcf9U8aiuVSpE8RQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.12.0.tgz", + "integrity": "sha512-zQaBfOnf/l8rPxYGnsk/ufh/0EuqvmnxafjBIpKZ//j6rGylw5JCqXSb1QvvAqRYruKeccxGv7+HrxpqKU6V4A==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/plugin": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/plugin": "2.12.0", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.10.0", + "@parcel/utils": "2.12.0", "browserslist": "^4.6.6", "json5": "^2.2.0", "nullthrows": "^1.1.1", @@ -1291,7 +1308,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1299,22 +1316,23 @@ } }, "node_modules/@parcel/transformer-css": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.10.0.tgz", - "integrity": "sha512-hITticpUE/qilpsTc7HQP04qhXwyUSKGZKgcFnvf8+BJO/LoclbVK1nzbR61eYl5Jhj1XB67p3tCt5fSvPhOsQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.12.0.tgz", + "integrity": "sha512-vXhOqoAlQGATYyQ433Z1DXKmiKmzOAUmKysbYH3FD+LKEKLMEl/pA14goqp00TW+A/EjtSKKyeMyHlMIIUqj4Q==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/plugin": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/plugin": "2.12.0", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.10.0", + "@parcel/utils": "2.12.0", "browserslist": "^4.6.6", - "lightningcss": "^1.16.1", + "lightningcss": "^1.22.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1322,14 +1340,15 @@ } }, "node_modules/@parcel/transformer-html": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.10.0.tgz", - "integrity": "sha512-rc8YKjB+bE7yGHOf674CSzW8ii+m5caBo4akdRIUdhEHJS4FnSwxYIZlMcfV9pZM4Tj5PFMZyrlAHad6YrO8aA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.12.0.tgz", + "integrity": "sha512-5jW4dFFBlYBvIQk4nrH62rfA/G/KzVzEDa6S+Nne0xXhglLjkm64Ci9b/d4tKZfuGWUbpm2ASAq8skti/nfpXw==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/plugin": "2.10.0", - "@parcel/rust": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/plugin": "2.12.0", + "@parcel/rust": "2.12.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -1339,44 +1358,59 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/transformer-image": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.10.0.tgz", - "integrity": "sha512-qbNyAJvzqdO/OnHhCOoPAZN5aBD/xphyXvDNI0Fb3UPEr5MQtAnzv2lS1I63s4rKpphBntWj7nEIAio6s7c5bw==", + "node_modules/@parcel/transformer-html/node_modules/srcset": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", + "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@parcel/transformer-image": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.12.0.tgz", + "integrity": "sha512-8hXrGm2IRII49R7lZ0RpmNk27EhcsH+uNKsvxuMpXPuEnWgC/ha/IrjaI29xCng1uGur74bJF43NUSQhR4aTdw==", + "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0", - "@parcel/utils": "2.10.0", - "@parcel/workers": "2.10.0", + "@parcel/plugin": "2.12.0", + "@parcel/utils": "2.12.0", + "@parcel/workers": "2.12.0", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "peerDependencies": { - "@parcel/core": "^2.10.0" + "@parcel/core": "^2.12.0" } }, "node_modules/@parcel/transformer-js": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.10.0.tgz", - "integrity": "sha512-39ZNnje8dlmME1ipjFyAFHyhHaGCwZZpXYN9SCTl/+AnjZLamnmVFkesgBbrRSBRQixRG1VwCvrWsjLLeLkTUg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.12.0.tgz", + "integrity": "sha512-OSZpOu+FGDbC/xivu24v092D9w6EGytB3vidwbdiJ2FaPgfV7rxS0WIUjH4I0OcvHAcitArRXL0a3+HrNTdQQw==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/plugin": "2.10.0", - "@parcel/rust": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/plugin": "2.12.0", + "@parcel/rust": "2.12.0", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.10.0", - "@parcel/workers": "2.10.0", + "@parcel/utils": "2.12.0", + "@parcel/workers": "2.12.0", "@swc/helpers": "^0.5.0", "browserslist": "^4.6.6", "nullthrows": "^1.1.1", @@ -1385,28 +1419,29 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.10.0" + "@parcel/core": "^2.12.0" } }, "node_modules/@parcel/transformer-json": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.10.0.tgz", - "integrity": "sha512-4G6ZIt7IYu1l3BlsL55Hi3869X6KHE0CHybWf364h5ZUmzo3Xpc5i7cziQX+IhWDo1qn1jiziOPGY85LXlo8ug==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.12.0.tgz", + "integrity": "sha512-Utv64GLRCQILK5r0KFs4o7I41ixMPllwOLOhkdjJKvf1hZmN6WqfOmB1YLbWS/y5Zb/iB52DU2pWZm96vLFQZQ==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0", + "@parcel/plugin": "2.12.0", "json5": "^2.2.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1414,18 +1449,19 @@ } }, "node_modules/@parcel/transformer-less": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-less/-/transformer-less-2.10.0.tgz", - "integrity": "sha512-p3iui2OzIhu4t3pzkHQ2k2smor6igk92j/P07FiTEj0imzMc8YfLPEegFm+GTxVxAMmprXIq6rXDS02sODciJg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-less/-/transformer-less-2.12.0.tgz", + "integrity": "sha512-eBgDLKX+5HU2IhZxdKabUflt2Aza8ZlV70G95GPZAW80PKlXPHxI10JTlYLAUiUy3G38TM3dvL6W0FhtCRbgSQ==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0", + "@parcel/plugin": "2.12.0", "@parcel/source-map": "^2.1.1", "less": "^4.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1433,15 +1469,16 @@ } }, "node_modules/@parcel/transformer-postcss": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.10.0.tgz", - "integrity": "sha512-Xhz+MHr9Q31d3u3hsBOtmFGEQx7FsNbTumGpqIqaGkDDq4IIMKbEwyrpkmf7/02kyxcbwr6uaBqnMHm55j10sQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.12.0.tgz", + "integrity": "sha512-FZqn+oUtiLfPOn67EZxPpBkfdFiTnF4iwiXPqvst3XI8H+iC+yNgzmtJkunOOuylpYY6NOU5jT8d7saqWSDv2Q==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/plugin": "2.10.0", - "@parcel/rust": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/plugin": "2.12.0", + "@parcel/rust": "2.12.0", + "@parcel/utils": "2.12.0", "clone": "^2.1.1", "nullthrows": "^1.1.1", "postcss-value-parser": "^4.2.0", @@ -1449,7 +1486,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1457,13 +1494,14 @@ } }, "node_modules/@parcel/transformer-posthtml": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.10.0.tgz", - "integrity": "sha512-kmz8Yip5hh2y3bfA76mC2QtI9VHdS7k5dV96/yjar0CkLHJnr33Jh7MTfuCN+01nVU20Tn3YMqEMQ/ErPVJwlg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.12.0.tgz", + "integrity": "sha512-z6Z7rav/pcaWdeD+2sDUcd0mmNZRUvtHaUGa50Y2mr+poxrKilpsnFMSiWBT+oOqPt7j71jzDvrdnAF4XkCljg==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/plugin": "2.12.0", + "@parcel/utils": "2.12.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -1472,7 +1510,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1480,16 +1518,17 @@ } }, "node_modules/@parcel/transformer-raw": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.10.0.tgz", - "integrity": "sha512-1tR58kqzTh4baLq/++bp84H2lhOoAz8cJeJykgsYImva7aRWcjlTppNKjBF6Ef8etIRMPZOozTdbS53VdQ9IbA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.12.0.tgz", + "integrity": "sha512-Ht1fQvXxix0NncdnmnXZsa6hra20RXYh1VqhBYZLsDfkvGGFnXIgO03Jqn4Z8MkKoa0tiNbDhpKIeTjyclbBxQ==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0" + "@parcel/plugin": "2.12.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1497,18 +1536,19 @@ } }, "node_modules/@parcel/transformer-react-refresh-wrap": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.10.0.tgz", - "integrity": "sha512-4ab1tiwUA2XznTh/eb/IVKEA+Ynkbqc5sgNuobf1MLKF82FXTUT5szVshff/ODpwublvVBD3YbXlapxV5xyFvA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.12.0.tgz", + "integrity": "sha512-GE8gmP2AZtkpBIV5vSCVhewgOFRhqwdM5Q9jNPOY5PKcM3/Ff0qCqDiTzzGLhk0/VMBrdjssrfZkVx6S/lHdJw==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/plugin": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/plugin": "2.12.0", + "@parcel/utils": "2.12.0", "react-refresh": "^0.9.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1516,14 +1556,15 @@ } }, "node_modules/@parcel/transformer-svg": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.10.0.tgz", - "integrity": "sha512-qEZFk4gxyVNhm2V8R3YLo9qCyYNVBySWmZLjmwuhLLmAE+r0qGebc9oXyo7C6ML5d/4Tfj6NriCOeX+HMhPVxw==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.12.0.tgz", + "integrity": "sha512-cZJqGRJ4JNdYcb+vj94J7PdOuTnwyy45dM9xqbIMH+HSiiIkfrMsdEwYft0GTyFTdsnf+hdHn3tau7Qa5hhX+A==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/plugin": "2.10.0", - "@parcel/rust": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/plugin": "2.12.0", + "@parcel/rust": "2.12.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -1532,7 +1573,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.10.0" + "parcel": "^2.12.0" }, "funding": { "type": "opencollective", @@ -1540,31 +1581,33 @@ } }, "node_modules/@parcel/types": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.10.0.tgz", - "integrity": "sha512-iDFVvgN+jK02GY++V+WY3WuNTM6CGDPToGfL31/Sgf6/1PzT7kL6uXJ6+859u8wkTIrtkWD2XyTNkKJJ8jPwgg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.12.0.tgz", + "integrity": "sha512-8zAFiYNCwNTQcglIObyNwKfRYQK5ELlL13GuBOrSMxueUiI5ylgsGbTS1N7J3dAGZixHO8KhHGv5a71FILn9rQ==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/cache": "2.10.0", - "@parcel/diagnostic": "2.10.0", - "@parcel/fs": "2.10.0", - "@parcel/package-manager": "2.10.0", + "@parcel/cache": "2.12.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/fs": "2.12.0", + "@parcel/package-manager": "2.12.0", "@parcel/source-map": "^2.1.1", - "@parcel/workers": "2.10.0", + "@parcel/workers": "2.12.0", "utility-types": "^3.10.0" } }, "node_modules/@parcel/utils": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.10.0.tgz", - "integrity": "sha512-8qx9caJTjli6UKpKlcPjdSBblkwTc+BnIsSK3/7fX7kbtHLmEkQH/RWZbbOJItHbnzlsmaDJTfS7j6rrcFw2Pw==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.12.0.tgz", + "integrity": "sha512-z1JhLuZ8QmDaYoEIuUCVZlhcFrS7LMfHrb2OCRui5SQFntRWBH2fNM6H/fXXUkT9SkxcuFP2DUA6/m4+Gkz72g==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/codeframe": "2.10.0", - "@parcel/diagnostic": "2.10.0", - "@parcel/logger": "2.10.0", - "@parcel/markdown-ansi": "2.10.0", - "@parcel/rust": "2.10.0", + "@parcel/codeframe": "2.12.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/logger": "2.12.0", + "@parcel/markdown-ansi": "2.12.0", + "@parcel/rust": "2.12.0", "@parcel/source-map": "^2.1.1", "chalk": "^4.1.0", "nullthrows": "^1.1.1" @@ -1578,11 +1621,11 @@ } }, "node_modules/@parcel/watcher": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.3.0.tgz", - "integrity": "sha512-pW7QaFiL11O0BphO+bq3MgqeX/INAk9jgBldVDYjlQPO4VddoZnF22TcF9onMhnLVHuNqBJeRf+Fj7eezi/+rQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.4.1.tgz", + "integrity": "sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==", "dev": true, - "hasInstallScript": true, + "license": "MIT", "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", @@ -1597,28 +1640,29 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.3.0", - "@parcel/watcher-darwin-arm64": "2.3.0", - "@parcel/watcher-darwin-x64": "2.3.0", - "@parcel/watcher-freebsd-x64": "2.3.0", - "@parcel/watcher-linux-arm-glibc": "2.3.0", - "@parcel/watcher-linux-arm64-glibc": "2.3.0", - "@parcel/watcher-linux-arm64-musl": "2.3.0", - "@parcel/watcher-linux-x64-glibc": "2.3.0", - "@parcel/watcher-linux-x64-musl": "2.3.0", - "@parcel/watcher-win32-arm64": "2.3.0", - "@parcel/watcher-win32-ia32": "2.3.0", - "@parcel/watcher-win32-x64": "2.3.0" + "@parcel/watcher-android-arm64": "2.4.1", + "@parcel/watcher-darwin-arm64": "2.4.1", + "@parcel/watcher-darwin-x64": "2.4.1", + "@parcel/watcher-freebsd-x64": "2.4.1", + "@parcel/watcher-linux-arm-glibc": "2.4.1", + "@parcel/watcher-linux-arm64-glibc": "2.4.1", + "@parcel/watcher-linux-arm64-musl": "2.4.1", + "@parcel/watcher-linux-x64-glibc": "2.4.1", + "@parcel/watcher-linux-x64-musl": "2.4.1", + "@parcel/watcher-win32-arm64": "2.4.1", + "@parcel/watcher-win32-ia32": "2.4.1", + "@parcel/watcher-win32-x64": "2.4.1" } }, "node_modules/@parcel/watcher-android-arm64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.3.0.tgz", - "integrity": "sha512-f4o9eA3dgk0XRT3XhB0UWpWpLnKgrh1IwNJKJ7UJek7eTYccQ8LR7XUWFKqw6aEq5KUNlCcGvSzKqSX/vtWVVA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz", + "integrity": "sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -1632,13 +1676,14 @@ } }, "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.3.0.tgz", - "integrity": "sha512-mKY+oijI4ahBMc/GygVGvEdOq0L4DxhYgwQqYAz/7yPzuGi79oXrZG52WdpGA1wLBPrYb0T8uBaGFo7I6rvSKw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz", + "integrity": "sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1652,13 +1697,14 @@ } }, "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.3.0.tgz", - "integrity": "sha512-20oBj8LcEOnLE3mgpy6zuOq8AplPu9NcSSSfyVKgfOhNAc4eF4ob3ldj0xWjGGbOF7Dcy1Tvm6ytvgdjlfUeow==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz", + "integrity": "sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1672,13 +1718,14 @@ } }, "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.3.0.tgz", - "integrity": "sha512-7LftKlaHunueAEiojhCn+Ef2CTXWsLgTl4hq0pkhkTBFI3ssj2bJXmH2L67mKpiAD5dz66JYk4zS66qzdnIOgw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz", + "integrity": "sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -1692,13 +1739,14 @@ } }, "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.3.0.tgz", - "integrity": "sha512-1apPw5cD2xBv1XIHPUlq0cO6iAaEUQ3BcY0ysSyD9Kuyw4MoWm1DV+W9mneWI+1g6OeP6dhikiFE6BlU+AToTQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz", + "integrity": "sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1712,13 +1760,14 @@ } }, "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.3.0.tgz", - "integrity": "sha512-mQ0gBSQEiq1k/MMkgcSB0Ic47UORZBmWoAWlMrTW6nbAGoLZP+h7AtUM7H3oDu34TBFFvjy4JCGP43JlylkTQA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz", + "integrity": "sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1732,13 +1781,14 @@ } }, "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.3.0.tgz", - "integrity": "sha512-LXZAExpepJew0Gp8ZkJ+xDZaTQjLHv48h0p0Vw2VMFQ8A+RKrAvpFuPVCVwKJCr5SE+zvaG+Etg56qXvTDIedw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz", + "integrity": "sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1752,13 +1802,14 @@ } }, "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.3.0.tgz", - "integrity": "sha512-P7Wo91lKSeSgMTtG7CnBS6WrA5otr1K7shhSjKHNePVmfBHDoAOHYRXgUmhiNfbcGk0uMCHVcdbfxtuiZCHVow==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz", + "integrity": "sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1772,13 +1823,14 @@ } }, "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.3.0.tgz", - "integrity": "sha512-+kiRE1JIq8QdxzwoYY+wzBs9YbJ34guBweTK8nlzLKimn5EQ2b2FSC+tAOpq302BuIMjyuUGvBiUhEcLIGMQ5g==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz", + "integrity": "sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -1792,13 +1844,14 @@ } }, "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.3.0.tgz", - "integrity": "sha512-35gXCnaz1AqIXpG42evcoP2+sNL62gZTMZne3IackM+6QlfMcJLy3DrjuL6Iks7Czpd3j4xRBzez3ADCj1l7Aw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz", + "integrity": "sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -1812,13 +1865,14 @@ } }, "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.3.0.tgz", - "integrity": "sha512-FJS/IBQHhRpZ6PiCjFt1UAcPr0YmCLHRbTc00IBTrelEjlmmgIVLeOx4MSXzx2HFEy5Jo5YdhGpxCuqCyDJ5ow==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz", + "integrity": "sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -1832,13 +1886,14 @@ } }, "node_modules/@parcel/watcher-win32-x64": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.3.0.tgz", - "integrity": "sha512-dLx+0XRdMnVI62kU3wbXvbIRhLck4aE28bIGKbRGS7BJNt54IIj9+c/Dkqb+7DJEbHUZAX1bwaoM8PqVlHJmCA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz", + "integrity": "sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -1852,16 +1907,17 @@ } }, "node_modules/@parcel/workers": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.10.0.tgz", - "integrity": "sha512-PILDag4aW7G9w2AvYvBsMHe/NRCoOt+L7HJzp6UIvy6ssbafH/8fzdGjSpA99GXzC5AXpAHVt8RXhGMXmMP6QA==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.12.0.tgz", + "integrity": "sha512-zv5We5Jmb+ZWXlU6A+AufyjY4oZckkxsZ8J4dvyWL0W8IQvGO1JB4FGeryyttzQv3RM3OxcN/BpTGPiDG6keBw==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/diagnostic": "2.10.0", - "@parcel/logger": "2.10.0", - "@parcel/profiler": "2.10.0", - "@parcel/types": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/logger": "2.12.0", + "@parcel/profiler": "2.12.0", + "@parcel/types": "2.12.0", + "@parcel/utils": "2.12.0", "nullthrows": "^1.1.1" }, "engines": { @@ -1872,18 +1928,19 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.10.0" + "@parcel/core": "^2.12.0" } }, "node_modules/@swc/core": { - "version": "1.3.93", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.93.tgz", - "integrity": "sha512-690GRr1wUGmGYZHk7fUduX/JUwViMF2o74mnZYIWEcJaCcd9MQfkhsxPBtjeg6tF+h266/Cf3RPYhsFBzzxXcA==", + "version": "1.7.35", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.35.tgz", + "integrity": "sha512-3cUteCTbr2r5jqfgx0r091sfq5Mgh6F1SQh8XAOnSvtKzwv2bC31mvBHVAieD1uPa2kHJhLav20DQgXOhpEitw==", "dev": true, "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { - "@swc/counter": "^0.1.1", - "@swc/types": "^0.1.5" + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.13" }, "engines": { "node": ">=10" @@ -1893,19 +1950,19 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.93", - "@swc/core-darwin-x64": "1.3.93", - "@swc/core-linux-arm-gnueabihf": "1.3.93", - "@swc/core-linux-arm64-gnu": "1.3.93", - "@swc/core-linux-arm64-musl": "1.3.93", - "@swc/core-linux-x64-gnu": "1.3.93", - "@swc/core-linux-x64-musl": "1.3.93", - "@swc/core-win32-arm64-msvc": "1.3.93", - "@swc/core-win32-ia32-msvc": "1.3.93", - "@swc/core-win32-x64-msvc": "1.3.93" + "@swc/core-darwin-arm64": "1.7.35", + "@swc/core-darwin-x64": "1.7.35", + "@swc/core-linux-arm-gnueabihf": "1.7.35", + "@swc/core-linux-arm64-gnu": "1.7.35", + "@swc/core-linux-arm64-musl": "1.7.35", + "@swc/core-linux-x64-gnu": "1.7.35", + "@swc/core-linux-x64-musl": "1.7.35", + "@swc/core-win32-arm64-msvc": "1.7.35", + "@swc/core-win32-ia32-msvc": "1.7.35", + "@swc/core-win32-x64-msvc": "1.7.35" }, "peerDependencies": { - "@swc/helpers": "^0.5.0" + "@swc/helpers": "*" }, "peerDependenciesMeta": { "@swc/helpers": { @@ -1914,13 +1971,14 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.3.93", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.93.tgz", - "integrity": "sha512-gEKgk7FVIgltnIfDO6GntyuQBBlAYg5imHpRgLxB1zSI27ijVVkksc6QwISzFZAhKYaBWIsFSVeL9AYSziAF7A==", + "version": "1.7.35", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.35.tgz", + "integrity": "sha512-BQSSozVxjxS+SVQz6e3GC/+OBWGIK3jfe52pWdANmycdjF3ch7lrCKTHTU7eHwyoJ96mofszPf5AsiVJF34Fwg==", "cpu": [ "arm64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "darwin" @@ -1930,13 +1988,14 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.3.93", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.93.tgz", - "integrity": "sha512-ZQPxm/fXdDQtn3yrYSL/gFfA8OfZ5jTi33yFQq6vcg/Y8talpZ+MgdSlYM0FkLrZdMTYYTNFiuBQuuvkA+av+Q==", + "version": "1.7.35", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.7.35.tgz", + "integrity": "sha512-44TYdKN/EWtkU88foXR7IGki9JzhEJzaFOoPevfi9Xe7hjAD/x2+AJOWWqQNzDPMz9+QewLdUVLyR6s5okRgtg==", "cpu": [ "x64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "darwin" @@ -1946,13 +2005,14 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.3.93", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.93.tgz", - "integrity": "sha512-OYFMMI2yV+aNe3wMgYhODxHdqUB/jrK0SEMHHS44GZpk8MuBXEF+Mcz4qjkY5Q1EH7KVQqXb/gVWwdgTHpjM2A==", + "version": "1.7.35", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.35.tgz", + "integrity": "sha512-ccfA5h3zxwioD+/z/AmYtkwtKz9m4rWTV7RoHq6Jfsb0cXHrd6tbcvgqRWXra1kASlE+cDWsMtEZygs9dJRtUQ==", "cpu": [ "arm" ], "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ "linux" @@ -1962,13 +2022,14 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.93", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.93.tgz", - "integrity": "sha512-BT4dT78odKnJMNiq5HdjBsv29CiIdcCcImAPxeFqAeFw1LL6gh9nzI8E96oWc+0lVT5lfhoesCk4Qm7J6bty8w==", + "version": "1.7.35", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.35.tgz", + "integrity": "sha512-hx65Qz+G4iG/IVtxJKewC5SJdki8PAPFGl6gC/57Jb0+jA4BIoGLD/J3Q3rCPeoHfdqpkCYpahtyUq8CKx41Jg==", "cpu": [ "arm64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "linux" @@ -1978,13 +2039,14 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.93", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.93.tgz", - "integrity": "sha512-yH5fWEl1bktouC0mhh0Chuxp7HEO4uCtS/ly1Vmf18gs6wZ8DOOkgAEVv2dNKIryy+Na++ljx4Ym7C8tSJTrLw==", + "version": "1.7.35", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.35.tgz", + "integrity": "sha512-kL6tQL9No7UEoEvDRuPxzPTpxrvbwYteNRbdChSSP74j13/55G2/2hLmult5yFFaWuyoyU/2lvzjRL/i8OLZxg==", "cpu": [ "arm64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "linux" @@ -1994,13 +2056,14 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.93", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.93.tgz", - "integrity": "sha512-OFUdx64qvrGJhXKEyxosHxgoUVgba2ztYh7BnMiU5hP8lbI8G13W40J0SN3CmFQwPP30+3oEbW7LWzhKEaYjlg==", + "version": "1.7.35", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.35.tgz", + "integrity": "sha512-Ke4rcLQSwCQ2LHdJX1FtnqmYNQ3IX6BddKlUtS7mcK13IHkQzZWp0Dcu6MgNA3twzb/dBpKX5GLy07XdGgfmyw==", "cpu": [ "x64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "linux" @@ -2010,13 +2073,14 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.93", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.93.tgz", - "integrity": "sha512-4B8lSRwEq1XYm6xhxHhvHmKAS7pUp1Q7E33NQ2TlmFhfKvCOh86qvThcjAOo57x8DRwmpvEVrqvpXtYagMN6Ig==", + "version": "1.7.35", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.35.tgz", + "integrity": "sha512-T30tlLnz0kYyDFyO5RQF5EQ4ENjW9+b56hEGgFUYmfhFhGA4E4V67iEx7KIG4u0whdPG7oy3qjyyIeTb7nElEw==", "cpu": [ "x64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "linux" @@ -2026,13 +2090,14 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.93", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.93.tgz", - "integrity": "sha512-BHShlxtkven8ZjjvZ5QR6sC5fZCJ9bMujEkiha6W4cBUTY7ce7qGFyHmQd+iPC85d9kD/0cCiX/Xez8u0BhO7w==", + "version": "1.7.35", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.35.tgz", + "integrity": "sha512-CfM/k8mvtuMyX+okRhemfLt784PLS0KF7Q9djA8/Dtavk0L5Ghnq+XsGltO3d8B8+XZ7YOITsB14CrjehzeHsg==", "cpu": [ "arm64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "win32" @@ -2042,13 +2107,14 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.93", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.93.tgz", - "integrity": "sha512-nEwNWnz4JzYAK6asVvb92yeylfxMYih7eMQOnT7ZVlZN5ba9WF29xJ6kcQKs9HRH6MvWhz9+wRgv3FcjlU6HYA==", + "version": "1.7.35", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.35.tgz", + "integrity": "sha512-ATB3uuH8j/RmS64EXQZJSbo2WXfRNpTnQszHME/sGaexsuxeijrp3DTYSFAA3R2Bu6HbIIX6jempe1Au8I3j+A==", "cpu": [ "ia32" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "win32" @@ -2058,13 +2124,14 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.93", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.93.tgz", - "integrity": "sha512-jibQ0zUr4kwJaQVwgmH+svS04bYTPnPw/ZkNInzxS+wFAtzINBYcU8s2PMWbDb2NGYiRSEeoSGyAvS9H+24JFA==", + "version": "1.7.35", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.35.tgz", + "integrity": "sha512-iDGfQO1571NqWUXtLYDhwIELA/wadH42ioGn+J9R336nWx40YICzy9UQyslWRhqzhQ5kT+QXAW/MoCWc058N6Q==", "cpu": [ "x64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "win32" @@ -2074,78 +2141,83 @@ } }, "node_modules/@swc/counter": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz", - "integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==", - "dev": true + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" }, "node_modules/@swc/helpers": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz", - "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz", + "integrity": "sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.4.0" } }, "node_modules/@swc/types": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", - "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==", - "dev": true + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.13.tgz", + "integrity": "sha512-JL7eeCk6zWCbiYQg2xQSdLXQJl8Qoc9rXmG2cEKvHe3CKwMHwHGpfOb8frzNLmbycOo6I51qxnLnn9ESf4I20Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10.13.0" } }, "node_modules/@types/prop-types": { - "version": "15.7.8", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.8.tgz", - "integrity": "sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ==", - "dev": true + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/react": { - "version": "18.2.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.28.tgz", - "integrity": "sha512-ad4aa/RaaJS3hyGz0BGegdnSRXQBkd1CCYDCdNjBPg90UUpLgo+WlJqb9fMYUxtehmzF3PJaTWqRZjko6BRzBg==", + "version": "18.3.11", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.11.tgz", + "integrity": "sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.13", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.13.tgz", - "integrity": "sha512-eJIUv7rPP+EC45uNYp/ThhSpE16k22VJUknt5OLoH9tbXoi8bMhwLf5xRuWMywamNbWzhrSmU7IBJfPup1+3fw==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/react": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.16.4", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.4.tgz", - "integrity": "sha512-2L9ifAGl7wmXwP4v3pN4p2FLhD0O1qsJpvKmNin5VA8+UvNVb447UDaAEV6UdrkA+m/Xs58U1RFps44x6TFsVQ==", - "dev": true - }, "node_modules/abortcontroller-polyfill": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2160,13 +2232,15 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", + "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.0.1" } @@ -2175,24 +2249,26 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "dev": true, "funding": [ { @@ -2208,11 +2284,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -2226,14 +2303,15 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001547", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001547.tgz", - "integrity": "sha512-W7CrtIModMAxobGhz8iXmDfuJiiKg1WADMO/9x7/CLNin5cpSbuBjooyoIUVB5eyCc36QuTVlkVa1iB2S5+/eA==", + "version": "1.0.30001668", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001668.tgz", + "integrity": "sha512-nWLrdxqCdblixUO+27JtGJJE/txpJlyUy5YN1u53wLZkP0emYCo5zgS6QYft7VUYR42LGgi/S5hdLZTrnyIddw==", "dev": true, "funding": [ { @@ -2248,13 +2326,15 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2267,10 +2347,11 @@ } }, "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0" } @@ -2280,6 +2361,7 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } @@ -2289,6 +2371,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2300,13 +2383,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } @@ -2316,6 +2401,7 @@ "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", "dev": true, + "license": "MIT", "dependencies": { "is-what": "^3.14.1" }, @@ -2324,15 +2410,16 @@ } }, "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, + "license": "MIT", "dependencies": { + "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" + "parse-json": "^5.2.0" }, "engines": { "node": ">=14" @@ -2354,6 +2441,7 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, + "license": "BSD-2-Clause", "optional": true, "peer": true, "dependencies": { @@ -2372,6 +2460,7 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { @@ -2388,6 +2477,7 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, + "license": "BSD-2-Clause", "optional": true, "peer": true, "dependencies": { @@ -2405,6 +2495,7 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, + "license": "BSD-2-Clause", "optional": true, "peer": true, "dependencies": { @@ -2421,6 +2512,7 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, + "license": "BSD-2-Clause", "optional": true, "peer": true, "engines": { @@ -2435,6 +2527,7 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { @@ -2450,6 +2543,7 @@ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">= 6" }, @@ -2462,6 +2556,7 @@ "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { @@ -2477,6 +2572,7 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { @@ -2493,30 +2589,23 @@ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", "dev": true, + "license": "CC0-1.0", "optional": true, "peer": true }, "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true - }, - "node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "dev": true, - "optional": true, - "dependencies": { - "ms": "^2.1.1" - } + "license": "MIT" }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "dev": true, + "license": "Apache-2.0", "bin": { "detect-libc": "bin/detect-libc.js" }, @@ -2529,6 +2618,7 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -2543,6 +2633,7 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true, + "license": "BSD-2-Clause", "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } @@ -2557,13 +2648,15 @@ "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause" }, "node_modules/domhandler": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.2.0" }, @@ -2579,6 +2672,7 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -2593,6 +2687,7 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=6" } @@ -2601,19 +2696,22 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/electron-to-chromium": { - "version": "1.4.554", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.554.tgz", - "integrity": "sha512-Q0umzPJjfBrrj8unkONTgbKQXzXRrH7sVV7D9ea2yBV3Oaogz991yhbpfvo2LMNkJItmruXTEzVpP9cp7vaIiQ==", - "dev": true + "version": "1.5.36", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.36.tgz", + "integrity": "sha512-HYTX8tKge/VNp6FGO+f/uVDmUkq+cEfcxYhKf15Akc4M5yxt5YmorwlAitKWjWhWQnKcDRBAQKXkhqqXMqcrjw==", + "dev": true, + "license": "ISC" }, "node_modules/entities": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -2621,11 +2719,22 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/errno": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "prr": "~1.0.1" @@ -2639,15 +2748,17 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2657,15 +2768,17 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2678,15 +2791,17 @@ "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz", "integrity": "sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -2702,6 +2817,7 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, + "license": "ISC", "optional": true }, "node_modules/has-flag": { @@ -2709,26 +2825,28 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/htmlnano": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.0.4.tgz", - "integrity": "sha512-WGCkyGFwjKW1GeCBsPYacMvaMnZtFJ0zIRnC2NCddkA+IOEhTqskXrS7lep+3yYZw/nQ3dW1UAX4yA/GJyR8BA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.1.1.tgz", + "integrity": "sha512-kAERyg/LuNZYmdqgCdYvugyLWNFAm8MWXpQMz1pLpetmCbFwoMxvkSoaAMlFrOC4OKTWI4KlZGT/RsNxg4ghOw==", "dev": true, + "license": "MIT", "dependencies": { - "cosmiconfig": "^8.0.0", + "cosmiconfig": "^9.0.0", "posthtml": "^0.16.5", "timsort": "^0.3.0" }, "peerDependencies": { - "cssnano": "^6.0.0", + "cssnano": "^7.0.0", "postcss": "^8.3.11", - "purgecss": "^5.0.0", + "purgecss": "^6.0.0", "relateurl": "^0.2.7", - "srcset": "4.0.0", + "srcset": "5.0.1", "svgo": "^3.0.2", "terser": "^5.10.0", "uncss": "^0.17.3" @@ -2772,6 +2890,7 @@ "url": "https://github.com/sponsors/fb55" } ], + "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.2", @@ -2784,6 +2903,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -2797,6 +2917,7 @@ "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "dev": true, + "license": "MIT", "optional": true, "bin": { "image-size": "bin/image-size.js" @@ -2810,6 +2931,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -2825,13 +2947,15 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2841,6 +2965,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -2852,13 +2977,15 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz", "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -2867,18 +2994,21 @@ "version": "3.14.1", "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -2890,13 +3020,15 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -2909,6 +3041,7 @@ "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -2931,10 +3064,11 @@ } }, "node_modules/lightningcss": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.22.0.tgz", - "integrity": "sha512-+z0qvwRVzs4XGRXelnWRNwqsXUx8k3bSkbP8vD42kYKSk3z9OM2P3e/gagT7ei/gwh8DTS80LZOFZV6lm8Z8Fg==", + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.27.0.tgz", + "integrity": "sha512-8f7aNmS1+etYSLHht0fQApPc2kNO8qGRutifN5rVIc6Xo6ABsEbqOr758UwI7ALVbTt4x1fllKt0PYgzD9S3yQ==", "dev": true, + "license": "MPL-2.0", "dependencies": { "detect-libc": "^1.0.3" }, @@ -2946,25 +3080,27 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-darwin-arm64": "1.22.0", - "lightningcss-darwin-x64": "1.22.0", - "lightningcss-freebsd-x64": "1.22.0", - "lightningcss-linux-arm-gnueabihf": "1.22.0", - "lightningcss-linux-arm64-gnu": "1.22.0", - "lightningcss-linux-arm64-musl": "1.22.0", - "lightningcss-linux-x64-gnu": "1.22.0", - "lightningcss-linux-x64-musl": "1.22.0", - "lightningcss-win32-x64-msvc": "1.22.0" + "lightningcss-darwin-arm64": "1.27.0", + "lightningcss-darwin-x64": "1.27.0", + "lightningcss-freebsd-x64": "1.27.0", + "lightningcss-linux-arm-gnueabihf": "1.27.0", + "lightningcss-linux-arm64-gnu": "1.27.0", + "lightningcss-linux-arm64-musl": "1.27.0", + "lightningcss-linux-x64-gnu": "1.27.0", + "lightningcss-linux-x64-musl": "1.27.0", + "lightningcss-win32-arm64-msvc": "1.27.0", + "lightningcss-win32-x64-msvc": "1.27.0" } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.22.0.tgz", - "integrity": "sha512-aH2be3nNny+It5YEVm8tBSSdRlBVWQV8m2oJ7dESiYRzyY/E/bQUe2xlw5caaMuhlM9aoTMtOH25yzMhir0qPg==", + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.27.0.tgz", + "integrity": "sha512-Gl/lqIXY+d+ySmMbgDf0pgaWSqrWYxVHoc88q+Vhf2YNzZ8DwoRzGt5NZDVqqIW5ScpSnmmjcgXP87Dn2ylSSQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MPL-2.0", "optional": true, "os": [ "darwin" @@ -2978,13 +3114,14 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.22.0.tgz", - "integrity": "sha512-9KHRFA0Y6mNxRHeoQMp0YaI0R0O2kOgUlYPRjuasU4d+pI8NRhVn9bt0yX9VPs5ibWX1RbDViSPtGJvYYrfVAQ==", + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.27.0.tgz", + "integrity": "sha512-0+mZa54IlcNAoQS9E0+niovhyjjQWEMrwW0p2sSdLRhLDc8LMQ/b67z7+B5q4VmjYCMSfnFi3djAAQFIDuj/Tg==", "cpu": [ "x64" ], "dev": true, + "license": "MPL-2.0", "optional": true, "os": [ "darwin" @@ -2998,13 +3135,14 @@ } }, "node_modules/lightningcss-freebsd-x64": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.22.0.tgz", - "integrity": "sha512-xaYL3xperGwD85rQioDb52ozF3NAJb+9wrge3jD9lxGffplu0Mn35rXMptB8Uc2N9Mw1i3Bvl7+z1evlqVl7ww==", + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.27.0.tgz", + "integrity": "sha512-n1sEf85fePoU2aDN2PzYjoI8gbBqnmLGEhKq7q0DKLj0UTVmOTwDC7PtLcy/zFxzASTSBlVQYJUhwIStQMIpRA==", "cpu": [ "x64" ], "dev": true, + "license": "MPL-2.0", "optional": true, "os": [ "freebsd" @@ -3018,13 +3156,14 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.22.0.tgz", - "integrity": "sha512-epQGvXIjOuxrZpMpMnRjK54ZqzhiHhCPLtHvw2fb6NeK2kK9YtF0wqmeTBiQ1AkbWfnnXGTstYaFNiadNK+StQ==", + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.27.0.tgz", + "integrity": "sha512-MUMRmtdRkOkd5z3h986HOuNBD1c2lq2BSQA1Jg88d9I7bmPGx08bwGcnB75dvr17CwxjxD6XPi3Qh8ArmKFqCA==", "cpu": [ "arm" ], "dev": true, + "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -3038,13 +3177,14 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.22.0.tgz", - "integrity": "sha512-AArGtKSY4DGTA8xP8SDyNyKtpsUl1Rzq6FW4JomeyUQ4nBrR71uPChksTpj3gmWuGhZeRKLeCUI1DBid/zhChg==", + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.27.0.tgz", + "integrity": "sha512-cPsxo1QEWq2sfKkSq2Bq5feQDHdUEwgtA9KaB27J5AX22+l4l0ptgjMZZtYtUnteBofjee+0oW1wQ1guv04a7A==", "cpu": [ "arm64" ], "dev": true, + "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -3058,13 +3198,14 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.22.0.tgz", - "integrity": "sha512-RRraNgP8hnBPhInTTUdlFm+z16C/ghbxBG51Sw00hd7HUyKmEUKRozyc5od+/N6pOrX/bIh5vIbtMXIxsos0lg==", + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.27.0.tgz", + "integrity": "sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==", "cpu": [ "arm64" ], "dev": true, + "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -3078,13 +3219,14 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.22.0.tgz", - "integrity": "sha512-grdrhYGRi2KrR+bsXJVI0myRADqyA7ekprGxiuK5QRNkv7kj3Yq1fERDNyzZvjisHwKUi29sYMClscbtl+/Zpw==", + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.27.0.tgz", + "integrity": "sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==", "cpu": [ "x64" ], "dev": true, + "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -3098,13 +3240,14 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.22.0.tgz", - "integrity": "sha512-t5f90X+iQUtIyR56oXIHMBUyQFX/zwmPt72E6Dane3P8KNGlkijTg2I75XVQS860gNoEFzV7Mm5ArRRA7u5CAQ==", + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.27.0.tgz", + "integrity": "sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==", "cpu": [ "x64" ], "dev": true, + "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -3117,14 +3260,36 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.27.0.tgz", + "integrity": "sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.22.0.tgz", - "integrity": "sha512-64HTDtOOZE9PUCZJiZZQpyqXBbdby1lnztBccnqh+NtbKxjnGzP92R2ngcgeuqMPecMNqNWxgoWgTGpC+yN5Sw==", + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.27.0.tgz", + "integrity": "sha512-/OJLj94Zm/waZShL8nB5jsNj3CfNATLCTyFxZyouilfTmSoLDX7VlVAmhPHoZWVFp4vdmoiEbPEYC8HID3m6yw==", "cpu": [ "x64" ], "dev": true, + "license": "MPL-2.0", "optional": true, "os": [ "win32" @@ -3141,7 +3306,8 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lmdb": { "version": "2.8.5", @@ -3149,6 +3315,7 @@ "integrity": "sha512-9bMdFfc80S+vSldBmG3HOuLVHnxRdNTlpzR6QDnzqCQtCzGUEAGTzBKYMeIM+I/sU4oZfgbcbS7X7F65/z/oxQ==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "msgpackr": "^1.9.5", "node-addon-api": "^6.1.0", @@ -3172,12 +3339,14 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -3185,23 +3354,12 @@ "loose-envify": "cli.js" } }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "pify": "^4.0.1", @@ -3216,6 +3374,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "optional": true, "bin": { "semver": "bin/semver" @@ -3226,16 +3385,18 @@ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "dev": true, + "license": "CC0-1.0", "optional": true, "peer": true }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -3247,6 +3408,7 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, + "license": "MIT", "optional": true, "bin": { "mime": "cli.js" @@ -3255,50 +3417,60 @@ "node": ">=4" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "optional": true - }, "node_modules/msgpackr": { - "version": "1.9.9", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.9.9.tgz", - "integrity": "sha512-sbn6mioS2w0lq1O6PpGtsv6Gy8roWM+o3o4Sqjd6DudrL/nOugY+KyJUimoWzHnf9OkO0T6broHFnYE/R05t9A==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.0.tgz", + "integrity": "sha512-I8qXuuALqJe5laEBYoFykChhSXLikZmUhccjGsPuSJ/7uPip2TJ7lwdIQwWSAi0jGZDXv4WOP8Qg65QZRuXxXw==", "dev": true, + "license": "MIT", "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "node_modules/msgpackr-extract": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", - "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", + "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "dependencies": { - "node-gyp-build-optional-packages": "5.0.7" + "node-gyp-build-optional-packages": "5.2.2" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" }, "optionalDependencies": { - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", - "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", - "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", - "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", - "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", - "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2" + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" + } + }, + "node_modules/msgpackr-extract/node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" } }, "node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", - "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", "dev": true, + "license": "MIT", "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", @@ -3306,13 +3478,13 @@ } }, "node_modules/needle": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", - "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { - "debug": "^3.2.6", "iconv-lite": "^0.6.3", "sax": "^1.2.4" }, @@ -3324,16 +3496,18 @@ } }, "node_modules/node-addon-api": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.0.0.tgz", - "integrity": "sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==", - "dev": true + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT" }, "node_modules/node-gyp-build-optional-packages": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz", "integrity": "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==", "dev": true, + "license": "MIT", "dependencies": { "detect-libc": "^2.0.1" }, @@ -3344,25 +3518,28 @@ } }, "node_modules/node-gyp-build-optional-packages/node_modules/detect-libc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", - "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=8" } }, "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "dev": true + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, + "license": "MIT" }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -3374,31 +3551,34 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ordered-binary": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.4.1.tgz", - "integrity": "sha512-9LtiGlPy982CsgxZvJGNNp2/NnrgEr6EAyN3iIEP3/8vd3YLgAZQHbQ75ZrkfBRGrNg37Dk3U6tuVb+B4Xfslg==", - "dev": true + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.2.tgz", + "integrity": "sha512-JTo+4+4Fw7FreyAvlSLjb1BBVaxEQAacmjD3jjuyPZclpbEghTvQZbXBb2qPd2LeIMxiHwXBZUcpmG2Gl/mDEA==", + "dev": true, + "license": "MIT" }, "node_modules/parcel": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.10.0.tgz", - "integrity": "sha512-YJmWEsiv1ClpPcJiWkr3gFj40sRvfeK89GGGwJjpzQMQsBmN6h6OHrSkByx0jrsPIvdsOIccU702upYpRAypuw==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.12.0.tgz", + "integrity": "sha512-W+gxAq7aQ9dJIg/XLKGcRT0cvnStFAQHPaI0pvD0U2l6IVLueUAm3nwN7lkY62zZNmlvNx6jNtE4wlbS+CyqSg==", "dev": true, + "license": "MIT", "dependencies": { - "@parcel/config-default": "2.10.0", - "@parcel/core": "2.10.0", - "@parcel/diagnostic": "2.10.0", - "@parcel/events": "2.10.0", - "@parcel/fs": "2.10.0", - "@parcel/logger": "2.10.0", - "@parcel/package-manager": "2.10.0", - "@parcel/reporter-cli": "2.10.0", - "@parcel/reporter-dev-server": "2.10.0", - "@parcel/reporter-tracer": "2.10.0", - "@parcel/utils": "2.10.0", + "@parcel/config-default": "2.12.0", + "@parcel/core": "2.12.0", + "@parcel/diagnostic": "2.12.0", + "@parcel/events": "2.12.0", + "@parcel/fs": "2.12.0", + "@parcel/logger": "2.12.0", + "@parcel/package-manager": "2.12.0", + "@parcel/reporter-cli": "2.12.0", + "@parcel/reporter-dev-server": "2.12.0", + "@parcel/reporter-tracer": "2.12.0", + "@parcel/utils": "2.12.0", "chalk": "^4.1.0", "commander": "^7.0.0", "get-port": "^4.2.0" @@ -3419,6 +3599,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -3431,6 +3612,7 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -3449,30 +3631,24 @@ "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -3485,6 +3661,7 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=6" @@ -3494,13 +3671,15 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/posthtml": { "version": "0.16.6", "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz", "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==", "dev": true, + "license": "MIT", "dependencies": { "posthtml-parser": "^0.11.0", "posthtml-render": "^3.0.0" @@ -3514,6 +3693,7 @@ "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.10.2.tgz", "integrity": "sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==", "dev": true, + "license": "MIT", "dependencies": { "htmlparser2": "^7.1.1" }, @@ -3526,6 +3706,7 @@ "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz", "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==", "dev": true, + "license": "MIT", "dependencies": { "is-json": "^2.0.1" }, @@ -3538,6 +3719,7 @@ "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz", "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==", "dev": true, + "license": "MIT", "dependencies": { "htmlparser2": "^7.1.1" }, @@ -3550,6 +3732,7 @@ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6.0" } @@ -3559,12 +3742,14 @@ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" }, @@ -3573,28 +3758,31 @@ } }, "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.3.1" } }, "node_modules/react-error-overlay": { "version": "6.0.9", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/react-refresh": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.9.0.tgz", "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3603,13 +3791,15 @@ "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -3632,38 +3822,40 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "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", "optional": true }, "node_modules/sax": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", - "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", "dev": true, + "license": "ISC", "optional": true }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" } }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3676,15 +3868,17 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "optional": true, "peer": true, "engines": { @@ -3692,12 +3886,15 @@ } }, "node_modules/srcset": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", - "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-5.0.1.tgz", + "integrity": "sha512-/P1UYbGfJVlxZag7aABNRrulEXAwCSDo7fklafOQrantuPTDmYgijJMks2zusPCVzgW9+4P69mq7w6pYuZpgxw==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "engines": { - "node": ">=12" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3708,13 +3905,15 @@ "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3723,17 +3922,19 @@ } }, "node_modules/svgo": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", - "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", "dev": true, + "license": "MIT", "optional": true, "peer": true, "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", "css-select": "^5.1.0", - "css-tree": "^2.2.1", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.0.0" }, @@ -3753,6 +3954,7 @@ "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -3764,13 +3966,15 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -3779,16 +3983,18 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, + "license": "0BSD" }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -3797,9 +4003,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "funding": [ { @@ -3815,9 +4021,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -3827,10 +4034,11 @@ } }, "node_modules/utility-types": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", - "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -3839,17 +4047,12 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/word_grid": { - "resolved": "../pkg", + "resolved": "../wasm/pkg", "link": true - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true } } } diff --git a/ui/package.json b/ui/package.json index bbe68a3..65740b0 100644 --- a/ui/package.json +++ b/ui/package.json @@ -2,13 +2,13 @@ "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", - "word_grid": "file:../pkg" + "word_grid": "file:../wasm/pkg" }, "devDependencies": { "@parcel/transformer-less": "^2.9.3", "@types/react": "^18.2.18", "@types/react-dom": "^18.2.7", - "parcel": "^2.9.3", + "parcel": "^2.12.0", "process": "^0.11.10" }, "scripts": { diff --git a/ui/src/Game.tsx b/ui/src/Game.tsx index 91d84f2..ede9f81 100644 --- a/ui/src/Game.tsx +++ b/ui/src/Game.tsx @@ -1,16 +1,5 @@ import * as React from "react"; -import {useEffect, useMemo, useReducer, useRef, useState} from "react"; -import { - GameState, - GameWasm, - MyResult, - PlayedTile, - PlayerAndScore, - ScoreResult, - Tray, - TurnAction, - TurnAdvanceResult -} from "../../pkg/word_grid"; +import {useEffect, useReducer, useRef, useState} from "react"; import { Direction, GRID_LENGTH, @@ -28,29 +17,55 @@ import { } from "./utils"; import {TileExchangeModal} from "./TileExchange"; import {Grid, Scores, TileTray} from "./UI"; +import {API, APIState, GameState, TurnAction, Tray, PlayedTile, Letter} from "./api"; function addLogInfo(existingLog: React.JSX.Element[], newItem: React.JSX.Element) { - newItem = React.cloneElement(newItem, { key: existingLog.length }) + newItem = React.cloneElement(newItem, {key: existingLog.length}) existingLog.push(newItem); return existingLog.slice(); } export function Game(props: { - wasm: GameWasm, + api: API, settings: Settings, end_game_fn: () => void, }) { - const cellTypes = useMemo(() => { - return props.wasm.get_board_cell_types(); - }, []); - - const [isGameOver, setGameOver] = useState(false); + const [api_state, setAPIState] = useState(undefined); + const [isLoading, setIsLoading] = useState(true); const [confirmedScorePoints, setConfirmedScorePoints] = useState(-1); + const [currentTurnNumber, setCurrentTurnNumber] = useState(0); + + let isGameOver = false; + if (api_state !== undefined) { + isGameOver = api_state.public_information.game_state.type === "Ended"; + } + + + function load() { + // setAPIState(undefined); + // setIsLoading(true); + const result = props.api.load(); + + result.then( + (state) => { + setAPIState(state); + setIsLoading(false); + } + ) + .catch((error) => { + console.log("load() failed") + console.log(error); + }); + } + + useEffect(() => { + load(); + }, []) const [boardLetters, setBoardLetters] = useState(() => { const newLetterData = [] as HighlightableLetterData[]; - for(let i=0; i) { + const result = props.api.exchange(selectedArray); - const result: MyResult = props.wasm.exchange_tiles(selectedArray); - - if(result.response_type === "ERR") { - logDispatch(
{(result.value as string)}
); - } else { - handlePlayerAction(result.value as TurnAction, props.settings.playerName); - setTurnCount(turnCount + 1); - - if(result.game_state.type === "Ended") { - endGame(result.game_state); - } - } + result + .then( + (_api_state) => { + load(); + }) + .catch((error) => { + console.error({error}); + logDispatch(
{error}
); + }); } - function addWordFn(word: string) { - props.wasm.add_word(word); - } - - const [gridArrow, gridArrowDispatch] = useReducer(adjustGridArrow, null); const [logInfo, logDispatch] = useReducer(addLogInfo, []); function movePlayableLetters(playerLetters: PlayableLetterData[], update: TileDispatchAction) { + if (update.action === TileDispatchActionType.RETRIEVE) { - if(update.action === TileDispatchActionType.RETRIEVE) { + let tray: Tray = api_state.tray; - let tray: Tray = props.wasm.get_tray("Player"); - - if(update.override) { + if (update.override) { playerLetters = []; } @@ -160,13 +165,13 @@ export function Game(props: { let startIndex = matchCoordinate(playerLetters, update.start); let endIndex = matchCoordinate(playerLetters, update.end); - if(startIndex != null) { + if (startIndex != null) { let startLetter = playerLetters[startIndex]; startLetter.location = update.end.location; startLetter.index = update.end.index; } - if(endIndex != null) { + if (endIndex != null) { let endLetter = playerLetters[endIndex]; endLetter.location = update.start.location; endLetter.index = update.start.index; @@ -178,7 +183,7 @@ export function Game(props: { } else if (update.action === TileDispatchActionType.SET_BLANK) { const blankLetter = playerLetters[update.blankIndex]; - if(blankLetter.text !== update.newBlankValue) { + if (blankLetter.text !== update.newBlankValue) { blankLetter.text = update.newBlankValue; if (blankLetter.location == LocationType.GRID) { setConfirmedScorePoints(-1); @@ -190,7 +195,7 @@ export function Game(props: { return mergeTrays(playerLetters, playerLetters); } else if (update.action === TileDispatchActionType.MOVE_TO_ARROW) { // let's verify that the arrow is defined, otherwise do nothing - if(gridArrow != null) { + if (gridArrow != null) { const end_position = { location: LocationType.GRID, index: gridArrow.position, @@ -215,35 +220,6 @@ export function Game(props: { } const [playerLetters, trayDispatch] = useReducer(movePlayableLetters, []); - - const [turnCount, setTurnCount] = useState(1); - const playerAndScores: PlayerAndScore[] = useMemo(() => { - return props.wasm.get_scores(); - }, [turnCount, isGameOver]); - - - - useEffect(() => { - const newLetterData = props.wasm.get_board_letters() as HighlightableLetterData[]; - - // we need to go through and set 'highlight' field to either true or false - // it will always be false if the player that just went was the AI - // TODO - build in support for multiple other players - for(let i=0; i { - return props.wasm.get_current_player(); - }, [turnCount]); - const logDivRef = useRef(null); const [isTileExchangeOpen, setIsTileExchangeOpen] = useState(false); @@ -255,34 +231,21 @@ export function Game(props: { } }, [logInfo]); - const remainingTiles = useMemo(() => { - return props.wasm.get_remaining_tiles(); - }, [turnCount, isGameOver]); - - const remainingAITiles = useMemo(() => { - let result = props.wasm.get_player_tile_count(props.settings.aiName) as MyResult; - if(result.response_type == "OK") { - return result.value as number; - } else { - console.error(result.value); - return -1; - } - - }, [turnCount, isGameOver]); - function handlePlayerAction(action: TurnAction, playerName: string) { - - if (action.type == "PlayTiles"){ + + if (action.type == "PlayTiles") { const result = action.result; result.words.sort((a, b) => b.score - a.score); - for(let word of result.words) { + for (let word of result.words) { logDispatch(
{playerName} received {word.score} points for playing '{word.word}.'
); } - logDispatch(
{playerName} received a total of {result.total} points for their turn.
); - } else if(action.type == "ExchangeTiles") { - logDispatch(
{playerName} exchanged {action.tiles_exchanged} tile{action.tiles_exchanged > 1 ? 's' : ''} for their turn.
); - } - else if(action.type == "Pass"){ + logDispatch(
{playerName} received a total of {result.total} points for their turn. +
); + } else if (action.type == "ExchangeTiles") { + logDispatch( +
{playerName} exchanged {action.tiles_exchanged} tile{action.tiles_exchanged > 1 ? 's' : ''} for + their turn.
); + } else if (action.type == "Pass") { logDispatch(
{playerName} passed.
); } @@ -292,28 +255,26 @@ export function Game(props: { function endGame(state: GameState) { - if(state.type != "InProgress") { - - setGameOver(true); + if (state.type != "InProgress") { logDispatch(

Scoring

); - const scores = props.wasm.get_scores() as PlayerAndScore[]; + const scores = api_state.public_information.players; let pointsBonus = 0; - for(const playerAndScore of scores) { + for (const playerAndScore of scores) { const name = playerAndScore.name; - if(name == state.finisher) { + if (name == state.finisher) { // we'll do the finisher last continue } const letters = state.remaining_tiles.get(name); - if(letters.length == 0) { + if (letters.length == 0) { logDispatch(
{name} has no remaining tiles.
); } else { let pointsLost = 0; let letterListStr = ''; - for(let i=0; i 2) { - if(i == letters.length - 2) { + if (letters.length > 2) { + if (i == letters.length - 2) { letterListStr += ', and '; } else if (i < letters.length - 2) { letterListStr += ', '; } - } else if (i == 0 && letters.length == 2){ + } else if (i == 0 && letters.length == 2) { // list of 2 letterListStr += ' and '; } @@ -338,7 +299,7 @@ export function Game(props: { } } - if(state.finisher != null) { + if (state.finisher != null) { logDispatch(
{state.finisher} receives {pointsBonus} bonus for completing first.
); } @@ -348,15 +309,14 @@ export function Game(props: { .at(0); const playersAtHighest = scores.filter((score) => score.score == highestScore); - let endGameMsg: string = ''; + let endGameMsg: string; - if(playersAtHighest.length > 1 && state.finisher == null) { + if (playersAtHighest.length > 1 && state.finisher == null) { endGameMsg = "Tie game!"; } else if (playersAtHighest.length > 1 && state.finisher != null) { // if there's a tie then the finisher gets the win endGameMsg = `${playersAtHighest[0].name} won by finishing first!`; - } - else { + } else { endGameMsg = `${playersAtHighest[0].name} won!`; } logDispatch(

Game over - {endGameMsg}

); @@ -367,34 +327,78 @@ export function Game(props: { } - function runAI() { - const result: MyResult = props.wasm.advance_turn(); - if(result.response_type === "OK" && result.value.type == "AIMove") { - handlePlayerAction(result.value.action, props.settings.aiName); - if(result.game_state.type === "Ended") { - endGame(result.game_state); - } + function updateBoardLetters(newLetters: Array) { + const newLetterData = newLetters as HighlightableLetterData[]; - } else { - // this would be quite surprising - console.error({result}); + for (let i = 0; i < newLetterData.length; i++) { + const newLetter = newLetterData[i]; + if (newLetter != null) { + newLetter.highlight = false; + } } - setTurnCount(turnCount + 1); + // loop through the histories backwards until we reach our player + for (let j = api_state.public_information.history.length - 1; j >= 0; j--) { + const update = api_state.public_information.history[j]; + if (update.player == props.settings.playerName) { + break + } + if (update.type.type === "PlayTiles") { + for (let i of update.type.locations) { + newLetterData[i].highlight = true; + } + } + } + + setBoardLetters(newLetterData); } useEffect(() => { - trayDispatch({action: TileDispatchActionType.RETRIEVE}); - setConfirmedScorePoints(-1); - if(!isGameOver){ - logDispatch(

Turn {turnCount}

); - logDispatch(
{playerTurnName}'s turn
); - if(playerTurnName != props.settings.playerName && !isGameOver) { - runAI(); - } - } - }, [turnCount]); + if (api_state) { + console.debug(api_state); + gridArrowDispatch({action: GridArrowDispatchActionType.CLEAR}); + trayDispatch({action: TileDispatchActionType.RETRIEVE}); + setConfirmedScorePoints(-1); + updateBoardLetters(api_state.public_information.board); + for (let i = currentTurnNumber; i < api_state.public_information.history.length; i++) { + if (i > currentTurnNumber) { + logDispatch(

Turn {i + 1}

); + const playerAtTurn = api_state.public_information.players[i % api_state.public_information.players.length].name; + logDispatch(
{playerAtTurn}'s turn
); + } + const update = api_state.public_information.history[i]; + handlePlayerAction(update.type, update.player); + + } + + setCurrentTurnNumber(api_state.public_information.history.length); + + if (!isGameOver) { + logDispatch(

Turn {api_state.public_information.history.length + 1}

); + logDispatch(
{api_state.public_information.current_player}'s turn
); + } else { + endGame(api_state.public_information.game_state); + } + + + } + }, [api_state]); + + + if (isLoading) { + return
Still loading
; + } + + const playerAndScores = api_state.public_information.players; + const remainingTiles = api_state.public_information.remaining_tiles; + let remainingAITiles = null; + for (let player of playerAndScores) { + if (player.name == 'AI') { + remainingAITiles = player.tray_tiles; + break; + } + } return <>
@@ -437,101 +441,108 @@ export function Game(props: { + trayDispatch({action: TileDispatchActionType.RETURN}); // want all tiles back on tray for tile exchange + setIsTileExchangeOpen(true); + }}>Open Tile Exchange +
-
+ }}>{confirmedScorePoints > -1 ? `Score ${confirmedScorePoints} points` : "Check"} + trayDispatch({action: TileDispatchActionType.RETURN}); + }}>Return Tiles + + }}>Pass +
- - ; } -function AddWordButton(props: {word: string, addWordFn: (x: string) => void}) { +function AddWordButton(props: { word: string, addWordFn: (x: string) => void }) { const [isClicked, setIsClicked] = useState(false); if (!isClicked) { diff --git a/ui/src/Menu.tsx b/ui/src/Menu.tsx index f3e6bc5..6d0578a 100644 --- a/ui/src/Menu.tsx +++ b/ui/src/Menu.tsx @@ -1,8 +1,9 @@ import * as React from "react"; import {useState} from "react"; -import {Difficulty, GameWasm} from '../../pkg/word_grid'; import {Settings} from "./utils"; import {Game} from "./Game"; +import {API, Difficulty} from "./api"; +import {GameWasm} from "./wasm"; export function Menu(props: {settings: Settings, dictionary_text: string}) { @@ -70,8 +71,8 @@ export function Menu(props: {settings: Settings, dictionary_text: string}) { proportion: processedProportionDictionary, randomness: processedAIRandomness, }; - const game_wasm = new GameWasm(BigInt(seed), props.dictionary_text, difficulty); - const game = setGame(null)}/> + const game_wasm: API = new GameWasm(BigInt(seed), props.dictionary_text, difficulty); + const game = setGame(null)}/> setGame(game); }}>New Game diff --git a/ui/src/TileExchange.tsx b/ui/src/TileExchange.tsx index 73b8f30..c272a73 100644 --- a/ui/src/TileExchange.tsx +++ b/ui/src/TileExchange.tsx @@ -1,8 +1,8 @@ import {addNTimes, PlayableLetterData} from "./utils"; import {useEffect, useState} from "react"; import {Modal} from "./Modal"; -import {Letter as LetterData} from "../../pkg/word_grid"; import * as React from "react"; +import {Letter} from "./api"; export function TileExchangeModal(props: { playerLetters: PlayableLetterData[], @@ -105,7 +105,7 @@ function TilesExchangedTray(props: { } function DummyExchangeTile(props: { - letter: LetterData, + letter: Letter, isSelected: boolean, onClick: () => void, }){ diff --git a/ui/src/UI.tsx b/ui/src/UI.tsx index b056a2e..be2237b 100644 --- a/ui/src/UI.tsx +++ b/ui/src/UI.tsx @@ -1,8 +1,6 @@ import * as React from "react"; import {ChangeEvent, JSX} from "react"; -import {PlayerAndScore} from "../../pkg/word_grid"; import { - CellType, cellTypeToDetails, CoordinateData, GridArrowData, @@ -14,6 +12,7 @@ import { TileDispatch, TileDispatchActionType, } from "./utils"; +import {APIPlayer, CellType} from "./api"; export function TileSlot(props: { @@ -234,7 +233,7 @@ export function Grid(props: { } -export function Scores(props: {playerScores: Array}){ +export function Scores(props: {playerScores: Array}){ let elements = props.playerScores.map((ps) => { return

{ps.name}

diff --git a/ui/src/api.ts b/ui/src/api.ts new file mode 100644 index 0000000..cd79956 --- /dev/null +++ b/ui/src/api.ts @@ -0,0 +1,90 @@ + +export interface Tray { + letters: (Letter | undefined)[]; +} + +export interface ScoreResult { + words: WordResult[]; + total: number; +} + +export interface WordResult { + word: string; + score: number; +} + +export interface PlayedTile { + index: number; + character: string | undefined; +} + +export interface Difficulty { + proportion: number; + randomness: number; +} + +export interface Letter { + text: string; + points: number; + ephemeral: boolean; + is_blank: boolean; +} + + +export type TurnAction = { type: "Pass" } | { type: "ExchangeTiles"; tiles_exchanged: number } | { type: "PlayTiles"; result: ScoreResult; locations: number[] }; + +export enum CellType { + Normal = "Normal", + DoubleWord = "DoubleWord", + DoubleLetter = "DoubleLetter", + TripleLetter = "TripleLetter", + TripleWord = "TripleWord", + Start = "Start", +} + +export type GameState = { type: "InProgress" } | { type: "Ended"; finisher: string | undefined; remaining_tiles: Map }; + +export interface APIPlayer { + name: string; + tray_tiles: number; + score: number +} + +export interface PublicInformation { + game_state: GameState; + board: Array; + cell_types: Array; + current_player: string; + players: Array; + remaining_tiles: number; + history: Array; +} + +export interface Update { + type: TurnAction, + player: string; +} + +export interface APIState { + public_information: PublicInformation; + tray: Tray; + update?: Update; +} + +export interface Result { + "Ok"?: A; + "Err"?: B; +} + +export function is_ok(result: Result): boolean { + return result["Ok"] != null; +} + +export interface API { + exchange: (selection: Array) => Promise; + pass: () => Promise; + play: (tiles: Array, commit: boolean) => Promise; + add_to_dictionary: (word: string) => Promise; + load: () => Promise; + +} \ No newline at end of file diff --git a/ui/src/index.tsx b/ui/src/index.tsx index 84b1400..167de2e 100644 --- a/ui/src/index.tsx +++ b/ui/src/index.tsx @@ -1,4 +1,4 @@ -import init from '../../pkg/word_grid.js'; +import init from 'word_grid'; import {createRoot} from "react-dom/client"; import * as React from "react"; import {Menu} from "./Menu"; diff --git a/ui/src/utils.ts b/ui/src/utils.ts index 0da07c3..7ad4c2c 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -1,14 +1,5 @@ -import {Letter as LetterData, Letter} from "../../pkg/word_grid"; import * as React from "react"; - -export enum CellType { - Normal = "Normal", - DoubleWord = "DoubleWord", - DoubleLetter = "DoubleLetter", - TripleLetter = "TripleLetter", - TripleWord = "TripleWord", - Start = "Start", -} +import {CellType, Letter as LetterData} from "./api"; export interface Settings { @@ -118,7 +109,7 @@ export function addNTimes(array: T[], toAdd: T, times: number) { } } -export function mergeTrays(existing: PlayableLetterData[], newer: (Letter | undefined)[]): PlayableLetterData[] { +export function mergeTrays(existing: PlayableLetterData[], newer: (LetterData | undefined)[]): PlayableLetterData[] { let trayLength = Math.max(existing.length, newer.length); diff --git a/ui/src/wasm.ts b/ui/src/wasm.ts new file mode 100644 index 0000000..12d8917 --- /dev/null +++ b/ui/src/wasm.ts @@ -0,0 +1,66 @@ +import {API, APIState, Difficulty, PlayedTile, Result, is_ok} from "./api"; +import {WasmAPI} from 'word_grid'; + +export class GameWasm implements API{ + wasm: WasmAPI; + + constructor(seed: bigint, dictionary_text: string, difficulty: Difficulty) { + this.wasm = new WasmAPI(seed, dictionary_text, difficulty); + } + + add_to_dictionary(word: string): Promise { + return new Promise((resolve, _) => { + this.wasm.add_to_dictionary(word); + resolve() + }); + } + + exchange(selection: Array): Promise { + return new Promise((resolve, reject) => { + let api_state: Result = this.wasm.exchange(selection); + + if(is_ok(api_state)) { + resolve(api_state.Ok); + } else { + reject(api_state.Err); + } + }); + } + + load(): Promise { + return new Promise((resolve, reject) => { + let api_state: Result = this.wasm.load(); + + if(is_ok(api_state)) { + resolve(api_state.Ok); + } else { + reject(api_state.Err); + } + }); + } + + pass(): Promise { + return new Promise((resolve, reject) => { + let api_state: Result = this.wasm.pass(); + + if(is_ok(api_state)) { + resolve(api_state.Ok); + } else { + reject(api_state.Err); + } + }); + } + + play(tiles: Array, commit: boolean): Promise { + return new Promise((resolve, reject) => { + let api_state: Result = this.wasm.play(tiles, commit); + + if(is_ok(api_state)) { + resolve(api_state.Ok); + } else { + reject(api_state.Err); + } + }); + } + +} \ No newline at end of file diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock new file mode 100644 index 0000000..838ccb0 --- /dev/null +++ b/wasm/Cargo.lock @@ -0,0 +1,289 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm" +version = "0.1.0" +dependencies = [ + "serde", + "serde-wasm-bindgen", + "serde_json", + "wasm-bindgen", + "word_grid", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "word_grid" +version = "0.1.0" +dependencies = [ + "csv", + "getrandom", + "rand", + "serde", + "serde_json", +] diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml new file mode 100644 index 0000000..8905a85 --- /dev/null +++ b/wasm/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "wasm" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +serde-wasm-bindgen = "0.6.5" +wasm-bindgen = "0.2.92" +word_grid = { version = "0.1.0", path = "../wordgrid" } +serde_json = "1.0" +serde = { version = "1.0.202", features = ["derive"] } \ No newline at end of file diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs new file mode 100644 index 0000000..bfdc766 --- /dev/null +++ b/wasm/src/lib.rs @@ -0,0 +1,60 @@ +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::JsValue; +use word_grid::api::APIGame; +use word_grid::game::{Game, PlayedTile}; +use word_grid::player_interaction::ai::Difficulty; + +#[wasm_bindgen] +pub struct WasmAPI(APIGame); + +#[wasm_bindgen] +impl WasmAPI { + #[wasm_bindgen(constructor)] + pub fn new(seed: u64, dictionary_text: &str, ai_difficulty: JsValue) -> Self { + let difficulty: Difficulty = serde_wasm_bindgen::from_value(ai_difficulty).unwrap(); + + let game = Game::new( + seed, + dictionary_text, + vec!["Player".to_string()], + vec![difficulty], + ); + + WasmAPI(APIGame::new(game)) + } + + pub fn exchange(&mut self, selection: JsValue) -> JsValue { + let selection: Vec = serde_wasm_bindgen::from_value(selection).unwrap(); + + let result = self.0.exchange("Player".to_string(), selection); + + serde_wasm_bindgen::to_value(&result).unwrap() + } + + pub fn pass(&mut self) -> JsValue { + let result = self.0.pass("Player".to_string()); + + serde_wasm_bindgen::to_value(&result).unwrap() + } + + pub fn load(&mut self) -> JsValue { + let result = self.0.load("Player".to_string()); + serde_wasm_bindgen::to_value(&result).unwrap() + } + + pub fn play(&mut self, tray_tile_locations: JsValue, commit_move: bool) -> JsValue { + let tray_tile_locations: Vec> = + serde_wasm_bindgen::from_value(tray_tile_locations).unwrap(); + + let result = self + .0 + .play("Player".to_string(), tray_tile_locations, commit_move); + serde_wasm_bindgen::to_value(&result).unwrap() + } + + pub fn add_to_dictionary(&mut self, word: String) -> JsValue { + let result = self.0.add_to_dictionary(word); + + serde_wasm_bindgen::to_value(&result).unwrap() + } +} diff --git a/wordgrid/Cargo.lock b/wordgrid/Cargo.lock new file mode 100644 index 0000000..ed07672 --- /dev/null +++ b/wordgrid/Cargo.lock @@ -0,0 +1,267 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.202" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.202" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "2.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "word_grid" +version = "0.1.0" +dependencies = [ + "csv", + "getrandom", + "rand", + "serde", + "serde_json", +] diff --git a/Cargo.toml b/wordgrid/Cargo.toml similarity index 59% rename from Cargo.toml rename to wordgrid/Cargo.toml index 7920278..924b9e8 100644 --- a/Cargo.toml +++ b/wordgrid/Cargo.toml @@ -7,16 +7,9 @@ repository = "https://git.joeltherrien.ca/joel/WordGrid" license = "AGPL-3" description = "A (WIP) package for playing 'WordGrid'." -[lib] -crate-type = ["cdylib"] - [dependencies] -csv = "1.2.2" +csv = "1.3.0" rand = {version = "0.8.5", features = ["small_rng"]} getrandom = {version = "0.2", features = ["js"]} -wasm-bindgen = { version = "0.2.87", features = ["serde-serialize"] } serde_json = "1.0" -serde = { version = "=1.0.171", features = ["derive"] } -serde-wasm-bindgen = "0.4.5" -tsify = { version = "0.4.5", features = ["js"] } - +serde = { version = "1.0.202", features = ["derive"] } diff --git a/wordgrid/src/api.rs b/wordgrid/src/api.rs new file mode 100644 index 0000000..e992817 --- /dev/null +++ b/wordgrid/src/api.rs @@ -0,0 +1,217 @@ +use crate::board::{CellType, Letter}; +use crate::game::{ + Error, Game, GameState, PlayedTile, Player, PlayerState, TurnAction, TurnAdvanceResult, +}; +use crate::player_interaction::Tray; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ApiPlayer { + name: String, + tray_tiles: usize, + score: u32, +} + +impl ApiPlayer { + fn from(player_state: &PlayerState) -> ApiPlayer { + ApiPlayer { + name: player_state.player.get_name().to_string(), + tray_tiles: player_state.tray.count(), + score: player_state.score, + } + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Update { + r#type: TurnAction, + player: String, +} + +pub type ApiBoard = Vec>; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PublicInformation { + game_state: GameState, + board: ApiBoard, + cell_types: Vec, + current_player: String, + players: Vec, + remaining_tiles: usize, + history: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ApiState { + public_information: PublicInformation, + tray: Tray, + update: Option, +} + +pub struct APIGame(pub Game, Vec); + +impl APIGame { + pub fn new(game: Game) -> APIGame { + APIGame(game, vec![]) + } + + fn is_players_turn(&self, player: &str) -> bool { + self.0.current_player_name().eq(player) + } + + fn player_exists(&self, player: &str) -> bool { + self.0.player_states.get_player_state(player).is_some() + } + + fn player_exists_and_turn(&self, player: &str) -> Result<(), Error> { + if !self.player_exists(&player) { + Err(Error::InvalidPlayer(player.to_string())) + } else if !self.is_players_turn(&player) { + Err(Error::WrongTurn(player.to_string())) + } else { + Ok(()) + } + } + + fn build_result( + &self, + tray: Tray, + game_state: Option, + update: Option, + ) -> ApiState { + ApiState { + public_information: self.build_public_information(game_state, &self.1), + tray, + update, + } + } + + fn build_public_information( + &self, + game_state: Option, + history: &Vec, + ) -> PublicInformation { + let game_state = game_state.unwrap_or_else(|| self.0.get_state()); + + let cell_types = self + .0 + .get_board() + .cells + .iter() + .map(|cell| -> CellType { cell.cell_type }) + .collect::>(); + + let board: Vec> = self + .0 + .get_board() + .cells + .iter() + .map(|cell| -> Option { cell.value.clone() }) + .collect(); + + let players = self + .0 + .player_states + .0 + .iter() + .map(|p| ApiPlayer::from(p)) + .collect::>(); + + PublicInformation { + game_state, + board, + cell_types, + current_player: self.0.current_player_name(), + players, + remaining_tiles: self.0.get_remaining_tiles(), + history: history.clone(), + } + } + + pub fn exchange(&mut self, player: String, tray_tiles: Vec) -> Result { + self.player_exists_and_turn(&player)?; + + let (tray, turn_action, game_state) = self.0.exchange_tiles(tray_tiles)?; + let update = Update { + r#type: turn_action, + player, + }; + + self.1.push(update.clone()); + + Ok(self.build_result(tray, Some(game_state), Some(update))) + } + + pub fn pass(&mut self, player: String) -> Result { + self.player_exists_and_turn(&player)?; + + let game_state = self.0.pass()?; + let tray = self.0.player_states.get_tray(&player).unwrap().clone(); + let update = Update { + r#type: TurnAction::Pass, + player, + }; + self.1.push(update.clone()); + + Ok(self.build_result(tray, Some(game_state), Some(update))) + } + + pub fn load(&mut self, player: String) -> Result { + if !self.player_exists(&player) { + Err(Error::InvalidPlayer(player)) + } else { + while self.is_ai_turn() { + let (result, _) = self.0.advance_turn()?; + + if let TurnAdvanceResult::AIMove { name, action } = result { + self.1.push(Update { + r#type: action, + player: name, + }); + } else { + unreachable!("We already checked that the current player is AI"); + } + } + + let tray = self.0.player_states.get_tray(&player).unwrap().clone(); + Ok(self.build_result(tray, None, None)) + } + } + + pub fn play( + &mut self, + player: String, + tray_tile_locations: Vec>, + commit_move: bool, + ) -> Result { + self.player_exists_and_turn(&player)?; + + let (turn_action, game_state) = self.0.receive_play(tray_tile_locations, commit_move)?; + let tray = self.0.player_states.get_tray(&player).unwrap().clone(); + let update = Update { + r#type: turn_action, + player, + }; + if commit_move { + self.1.push(update.clone()) + } + + Ok(self.build_result(tray, Some(game_state), Some(update))) + } + + pub fn add_to_dictionary(&mut self, word: String) { + self.0.add_word(word); + } + + pub fn is_ai_turn(&self) -> bool { + let current_player = self.0.current_player_name(); + matches!( + self.0 + .player_states + .get_player_state(¤t_player) + .unwrap() + .player, + Player::AI { .. } + ) + } +} diff --git a/src/board.rs b/wordgrid/src/board.rs similarity index 76% rename from src/board.rs rename to wordgrid/src/board.rs index 5228f9f..4be0b7c 100644 --- a/src/board.rs +++ b/wordgrid/src/board.rs @@ -1,32 +1,31 @@ +use crate::constants::{ALL_LETTERS_BONUS, GRID_LENGTH, TRAY_LENGTH}; +use crate::dictionary::DictionaryImpl; +use crate::game::Error; +use serde::{Deserialize, Serialize}; +use std::borrow::BorrowMut; use std::collections::HashSet; use std::fmt; use std::fmt::{Formatter, Write}; -use std::borrow::BorrowMut; -use serde::{Deserialize, Serialize}; -use tsify::Tsify; -use crate::constants::{ALL_LETTERS_BONUS, GRID_LENGTH, TRAY_LENGTH}; -use crate::dictionary::DictionaryImpl; - #[derive(Clone, Copy)] pub enum Direction { - Row, Column + Row, + Column, } impl Direction { pub fn invert(&self) -> Self { match &self { - Direction::Row => {Direction::Column} - Direction::Column => {Direction::Row} + Direction::Row => Direction::Column, + Direction::Column => Direction::Row, } } } #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -pub struct Coordinates (pub u8, pub u8); +pub struct Coordinates(pub u8, pub u8); impl Coordinates { - pub fn new_from_index(index: usize) -> Self { let y = index / GRID_LENGTH as usize; let x = index % GRID_LENGTH as usize; @@ -36,32 +35,35 @@ impl Coordinates { fn add(&self, direction: Direction, i: i8) -> Option { let proposed = match direction { - Direction::Column => {(self.0 as i8, self.1 as i8+i)} - Direction::Row => {(self.0 as i8+i, self.1 as i8)} + Direction::Column => (self.0 as i8, self.1 as i8 + i), + Direction::Row => (self.0 as i8 + i, self.1 as i8), }; - if proposed.0 < 0 || proposed.0 >= GRID_LENGTH as i8 || proposed.1 < 0 || proposed.1 >= GRID_LENGTH as i8 { + if proposed.0 < 0 + || proposed.0 >= GRID_LENGTH as i8 + || proposed.1 < 0 + || proposed.1 >= GRID_LENGTH as i8 + { None - } else{ + } else { Some(Coordinates(proposed.0 as u8, proposed.1 as u8)) } } - pub fn increment(&self, direction: Direction) -> Option{ + pub fn increment(&self, direction: Direction) -> Option { self.add(direction, 1) } - pub fn decrement(&self, direction: Direction) -> Option{ + pub fn decrement(&self, direction: Direction) -> Option { self.add(direction, -1) } pub fn map_to_index(&self) -> usize { - (self.0 + GRID_LENGTH*self.1) as usize + (self.0 + GRID_LENGTH * self.1) as usize } } -#[derive(Debug, Copy, Clone, Serialize, Deserialize, Tsify, PartialEq, Eq, Hash)] -#[tsify(from_wasm_abi)] +#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] pub struct Letter { pub text: char, pub points: u32, @@ -81,32 +83,27 @@ impl Letter { pub fn new(text: Option, points: u32) -> Letter { match text { - None => { - Letter { - text: ' ', - points, - ephemeral: true, - is_blank: true, - } - } - Some(text) => { - Letter { - text, - points, - ephemeral: true, - is_blank: false, - } - } + None => Letter { + text: ' ', + points, + ephemeral: true, + is_blank: true, + }, + Some(text) => Letter { + text, + points, + ephemeral: true, + is_blank: false, + }, } } pub fn partial_match(&self, other: &Letter) -> bool { self == other || (self.is_blank && other.is_blank && self.points == other.points) } - } -#[derive(Debug, Copy, Clone, Serialize)] +#[derive(Debug, Copy, Clone, Serialize, Deserialize)] pub enum CellType { Normal, DoubleWord, @@ -141,37 +138,34 @@ impl<'a> ToString for Word<'a> { } text - } } -impl <'a> Word<'a> { - - pub fn calculate_score(&self) -> u32{ +impl<'a> Word<'a> { + pub fn calculate_score(&self) -> u32 { let mut multiplier = 1; let mut unmultiplied_score = 0; for cell in self.cells.as_slice() { let cell_value = cell.value.unwrap(); if cell_value.ephemeral { - let cell_multiplier = - match cell.cell_type { - CellType::Normal => {1} - CellType::DoubleWord => { - multiplier *= 2; - 1 - } - CellType::DoubleLetter => {2} - CellType::TripleLetter => {3} - CellType::TripleWord => { - multiplier *= 3; - 1 - } - CellType::Start => { - multiplier *= 2; - 1 - } - }; + let cell_multiplier = match cell.cell_type { + CellType::Normal => 1, + CellType::DoubleWord => { + multiplier *= 2; + 1 + } + CellType::DoubleLetter => 2, + CellType::TripleLetter => 3, + CellType::TripleWord => { + multiplier *= 3; + 1 + } + CellType::Start => { + multiplier *= 2; + 1 + } + }; unmultiplied_score += cell_value.points * cell_multiplier; } else { // no cell multiplier unfortunately @@ -187,7 +181,6 @@ impl Board { pub fn new() -> Self { let mut cells = Vec::new(); - /// Since the board is symmetrical in both directions for the purposes of our logic we can keep our coordinates in one corner /// /// # Arguments @@ -200,7 +193,7 @@ impl Board { GRID_LENGTH - x - 1 } else { x - } + }; } for i_orig in 0..GRID_LENGTH { @@ -221,12 +214,10 @@ impl Board { } // Double letters - if (i % 4 == 2) && (j % 4 == 2) && !( - i == 2 && j == 2 - ) { + if (i % 4 == 2) && (j % 4 == 2) && !(i == 2 && j == 2) { typee = CellType::DoubleLetter; } - if (i.min(j) == 0 && i.max(j) == 3) || (i.min(j)==3 && i.max(j) == 7) { + if (i.min(j) == 0 && i.max(j) == 3) || (i.min(j) == 3 && i.max(j) == 7) { typee = CellType::DoubleLetter; } @@ -245,11 +236,10 @@ impl Board { value: None, coordinates: Coordinates(j_orig, i_orig), }) - } } - Board {cells} + Board { cells } } pub fn get_cell(&self, coordinates: Coordinates) -> Result<&Cell, &str> { @@ -261,24 +251,28 @@ impl Board { } } - pub fn get_cell_mut(&mut self, coordinates: Coordinates) -> Result<&mut Cell, &str> { + pub fn get_cell_mut(&mut self, coordinates: Coordinates) -> Result<&mut Cell, Error> { if coordinates.0 >= GRID_LENGTH || coordinates.1 >= GRID_LENGTH { - Err("x & y must be within the board's coordinates") + Err(Error::Other( + "x & y must be within the board's coordinates".to_string(), + )) } else { let index = coordinates.map_to_index(); Ok(self.cells.get_mut(index).unwrap()) } } - - pub fn calculate_scores(&self, dictionary: &DictionaryImpl) -> Result<(Vec<(Word, u32)>, u32), String> { + pub fn calculate_scores( + &self, + dictionary: &DictionaryImpl, + ) -> Result<(Vec<(Word, u32)>, u32), Error> { let (words, tiles_played) = self.find_played_words()?; let mut words_and_scores = Vec::new(); let mut total_score = 0; for word in words { if !dictionary.contains_key(&word.to_string()) { - return Err(format!("{} is not a valid word", word.to_string())); + return Err(Error::InvalidWord(word.to_string())); } let score = word.calculate_score(); @@ -293,10 +287,9 @@ impl Board { Ok((words_and_scores, total_score)) } - pub fn find_played_words(&self) -> Result<(Vec, u8), &str> { + pub fn find_played_words(&self) -> Result<(Vec, u8), Error> { // We don't assume that the move is valid, so let's first establish that - // Let's first establish what rows and columns tiles were played in let mut rows_played = HashSet::with_capacity(15); let mut columns_played = HashSet::with_capacity(15); @@ -320,9 +313,9 @@ impl Board { } if rows_played.is_empty() { - return Err("Tiles need to be played") + return Err(Error::NoTilesPlayed); } else if rows_played.len() > 1 && columns_played.len() > 1 { - return Err("Tiles need to be played on one row or column") + return Err(Error::TilesNotStraight); } let direction = if rows_played.len() > 1 { @@ -335,7 +328,9 @@ impl Board { let starting_column = *columns_played.iter().min().unwrap(); let starting_coords = Coordinates(starting_row, starting_column); - let main_word = self.find_word_at_position(starting_coords, direction).unwrap(); + let main_word = self + .find_word_at_position(starting_coords, direction) + .unwrap(); let mut words = Vec::new(); let mut observed_tiles_played = 0; @@ -359,25 +354,25 @@ impl Board { // there are tiles not part of the main word if observed_tiles_played != tiles_played { - return Err("Played tiles cannot have empty gap"); + return Err(Error::TilesHaveGap); } // don't want the case of a single letter word if main_word.cells.len() > 1 { words.push(main_word); } else if words.is_empty() { - return Err("All words must be at least one letter"); + return Err(Error::OneLetterWord); } - - - // need to verify that the play is 'anchored' let mut anchored = false; 'outer: for word in words.as_slice() { for cell in word.cells.as_slice() { // either one of the letters - if !cell.value.as_ref().unwrap().ephemeral || (cell.coordinates.0 == GRID_LENGTH / 2 && cell.coordinates.1 == GRID_LENGTH / 2){ + if !cell.value.as_ref().unwrap().ephemeral + || (cell.coordinates.0 == GRID_LENGTH / 2 + && cell.coordinates.1 == GRID_LENGTH / 2) + { anchored = true; break 'outer; } @@ -387,23 +382,27 @@ impl Board { if anchored { Ok((words, tiles_played)) } else { - return Err("Played tiles must be anchored to something") + Err(Error::UnanchoredWord) } } - pub fn find_word_at_position(&self, mut start_coords: Coordinates, direction: Direction) -> Option { + pub fn find_word_at_position( + &self, + mut start_coords: Coordinates, + direction: Direction, + ) -> Option { // let's see how far we can backtrack to the start of the word let mut times_moved = 0; loop { let one_back = start_coords.add(direction, -times_moved); match one_back { - None => { break } + None => break, Some(new_coords) => { let cell = self.get_cell(new_coords).unwrap(); - if cell.value.is_some(){ + if cell.value.is_some() { times_moved += 1; } else { - break + break; } } } @@ -423,11 +422,11 @@ impl Board { loop { let position = start_coords.add(direction, cells.len() as i8); match position { - None => {break} + None => break, Some(x) => { let cell = self.get_cell(x).unwrap(); match cell.value { - None => {break} + None => break, Some(_) => { cells.push(cell); } @@ -442,16 +441,16 @@ impl Board { }) } - pub fn receive_play(&mut self, play: Vec<(Letter, Coordinates)>) -> Result<(), String> { + pub fn receive_play(&mut self, play: Vec<(Letter, Coordinates)>) -> Result<(), Error> { for (mut letter, coords) in play { { - let cell = match self.get_cell_mut(coords) { - Ok(cell) => {cell} - Err(e) => {return Err(e.to_string())} - }; + let cell = self.get_cell_mut(coords)?; if cell.value.is_some() { - return Err(format!("There's already a letter at {:?}", coords)); + return Err(Error::Other(format!( + "There's already a letter at {:?}", + coords + ))); } letter.ephemeral = true; @@ -476,7 +475,6 @@ impl Board { impl fmt::Display for Board { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let mut str = String::new(); let normal = "\x1b[48;5;174m\x1b[38;5;0m"; @@ -493,57 +491,82 @@ impl fmt::Display for Board { let cell = self.get_cell(coords).unwrap(); let color = match cell.cell_type { - CellType::Normal => {normal} - CellType::DoubleWord => {double_word} - CellType::DoubleLetter => {double_letter} - CellType::TripleLetter => {triple_letter} - CellType::TripleWord => {triple_word} - CellType::Start => {double_word} + CellType::Normal => normal, + CellType::DoubleWord => double_word, + CellType::DoubleLetter => double_letter, + CellType::TripleLetter => triple_letter, + CellType::TripleWord => triple_word, + CellType::Start => double_word, }; let content = match &cell.value { - None => {' '} - Some(letter) => {letter.text} + None => ' ', + Some(letter) => letter.text, }; - str.write_str(color).unwrap(); str.write_char(content).unwrap(); - - } str.write_str("\x1b[0m\n").unwrap(); } write!(f, "{}", str) - } } #[cfg(test)] mod tests { - use crate::dictionary::Dictionary; use super::*; + use crate::dictionary::Dictionary; #[test] fn test_cell_types() { let board = Board::new(); - assert!(matches!(board.get_cell(Coordinates(0, 0)).unwrap().cell_type, CellType::TripleWord)); - assert!(matches!(board.get_cell(Coordinates(1, 0)).unwrap().cell_type, CellType::Normal)); - assert!(matches!(board.get_cell(Coordinates(0, 1)).unwrap().cell_type, CellType::Normal)); - assert!(matches!(board.get_cell(Coordinates(1, 1)).unwrap().cell_type, CellType::DoubleWord)); + assert!(matches!( + board.get_cell(Coordinates(0, 0)).unwrap().cell_type, + CellType::TripleWord + )); + assert!(matches!( + board.get_cell(Coordinates(1, 0)).unwrap().cell_type, + CellType::Normal + )); + assert!(matches!( + board.get_cell(Coordinates(0, 1)).unwrap().cell_type, + CellType::Normal + )); + assert!(matches!( + board.get_cell(Coordinates(1, 1)).unwrap().cell_type, + CellType::DoubleWord + )); - assert!(matches!(board.get_cell(Coordinates(13, 13)).unwrap().cell_type, CellType::DoubleWord)); - assert!(matches!(board.get_cell(Coordinates(14, 14)).unwrap().cell_type, CellType::TripleWord)); - assert!(matches!(board.get_cell(Coordinates(11, 14)).unwrap().cell_type, CellType::DoubleLetter)); + assert!(matches!( + board.get_cell(Coordinates(13, 13)).unwrap().cell_type, + CellType::DoubleWord + )); + assert!(matches!( + board.get_cell(Coordinates(14, 14)).unwrap().cell_type, + CellType::TripleWord + )); + assert!(matches!( + board.get_cell(Coordinates(11, 14)).unwrap().cell_type, + CellType::DoubleLetter + )); - assert!(matches!(board.get_cell(Coordinates(7, 7)).unwrap().cell_type, CellType::Start)); - assert!(matches!(board.get_cell(Coordinates(8, 6)).unwrap().cell_type, CellType::DoubleLetter)); - assert!(matches!(board.get_cell(Coordinates(5, 9)).unwrap().cell_type, CellType::TripleLetter)); + assert!(matches!( + board.get_cell(Coordinates(7, 7)).unwrap().cell_type, + CellType::Start + )); + assert!(matches!( + board.get_cell(Coordinates(8, 6)).unwrap().cell_type, + CellType::DoubleLetter + )); + assert!(matches!( + board.get_cell(Coordinates(5, 9)).unwrap().cell_type, + CellType::TripleLetter + )); } - #[test] fn test_cell_coordinates() { let board = Board::new(); @@ -576,7 +599,6 @@ mod tests { board.get_cell_mut(Coordinates(5, 0)).unwrap().value = Some(Letter::new_fixed('O', 0)); board.get_cell_mut(Coordinates(6, 0)).unwrap().value = Some(Letter::new_fixed('L', 0)); - board.get_cell_mut(Coordinates(9, 8)).unwrap().value = Some(Letter::new_fixed('G', 0)); board.get_cell_mut(Coordinates(10, 8)).unwrap().value = Some(Letter::new_fixed('G', 0)); @@ -584,7 +606,9 @@ mod tests { println!("x is {}", x); let first_word = board.find_word_at_position(Coordinates(8, x), Direction::Column); match first_word { - None => { panic!("Expected to find word JOEL") } + None => { + panic!("Expected to find word JOEL") + } Some(x) => { assert_eq!(x.coords.0, 8); assert_eq!(x.coords.1, 6); @@ -596,7 +620,9 @@ mod tests { let single_letter_word = board.find_word_at_position(Coordinates(8, 9), Direction::Row); match single_letter_word { - None => { panic!("Expected to find letter L") } + None => { + panic!("Expected to find letter L") + } Some(x) => { assert_eq!(x.coords.0, 8); assert_eq!(x.coords.1, 9); @@ -609,7 +635,9 @@ mod tests { println!("x is {}", x); let word = board.find_word_at_position(Coordinates(x, 0), Direction::Row); match word { - None => { panic!("Expected to find word IS") } + None => { + panic!("Expected to find word IS") + } Some(x) => { assert_eq!(x.coords.0, 0); assert_eq!(x.coords.1, 0); @@ -623,7 +651,9 @@ mod tests { println!("x is {}", x); let word = board.find_word_at_position(Coordinates(x, 0), Direction::Row); match word { - None => { panic!("Expected to find word COOL") } + None => { + panic!("Expected to find word COOL") + } Some(x) => { assert_eq!(x.coords.0, 3); assert_eq!(x.coords.1, 0); @@ -638,7 +668,9 @@ mod tests { let word = board.find_word_at_position(Coordinates(10, 8), Direction::Row); match word { - None => { panic!("Expected to find word EGG") } + None => { + panic!("Expected to find word EGG") + } Some(x) => { assert_eq!(x.coords.0, 8); assert_eq!(x.coords.1, 8); @@ -659,10 +691,10 @@ mod tests { is_blank: false, }); - match board.find_played_words() { - Ok(_) => {panic!("Expected error")} - Err(e) => {assert_eq!(e, "All words must be at least one letter");} - } + assert!(matches!( + board.find_played_words(), + Err(Error::OneLetterWord) + )); board.get_cell_mut(Coordinates(7, 7)).unwrap().value = Some(Letter { text: 'I', @@ -726,10 +758,7 @@ mod tests { board.get_cell_mut(Coordinates(8, 9)).unwrap().value = Some(make_letter('L', true)); let words = board.find_played_words(); - match words { - Ok(_) => {panic!("Expected the not-anchored error")} - Err(x) => {assert_eq!(x, "Played tiles must be anchored to something")} - } + assert!(matches!(words, Err(Error::UnanchoredWord))); // Adding anchor board.get_cell_mut(Coordinates(7, 6)).unwrap().value = Some(make_letter('I', false)); @@ -746,7 +775,6 @@ mod tests { assert!(board.find_played_words().is_ok()); } - #[test] fn test_word_finding_with_break() { // Verify that if I play my tiles on one row or column but with a break in-between I get an error @@ -765,22 +793,15 @@ mod tests { board.get_cell_mut(Coordinates(8, 6)).unwrap().value = Some(Letter::new_fixed('J', 0)); board.get_cell_mut(Coordinates(8, 7)).unwrap().value = Some(make_letter('O', true)); board.get_cell_mut(Coordinates(8, 8)).unwrap().value = Some(make_letter('E', true)); - board.get_cell_mut(Coordinates(8, 9)).unwrap().value = Some(Letter::new_fixed( 'L', 0)); + board.get_cell_mut(Coordinates(8, 9)).unwrap().value = Some(Letter::new_fixed('L', 0)); board.get_cell_mut(Coordinates(8, 11)).unwrap().value = Some(make_letter('I', true)); board.get_cell_mut(Coordinates(8, 12)).unwrap().value = Some(Letter::new_fixed('S', 0)); let words = board.find_played_words(); - match words { - Ok(_) => {panic!("Expected to find an error!")} - Err(x) => { - assert_eq!(x, "Played tiles cannot have empty gap") - } - } - + assert!(matches!(words, Err(Error::TilesHaveGap))); } - #[test] fn test_word_finding_whole_board() { let mut board = Board::new(); @@ -795,15 +816,12 @@ mod tests { } let words = board.find_played_words(); - match words { - Ok(_) => {panic!("Expected to find no words")} - Err(x) => {assert_eq!(x, "Tiles need to be played")} - } + assert!(matches!(words, Err(Error::NoTilesPlayed))); board.get_cell_mut(Coordinates(8, 6)).unwrap().value = Some(Letter::new_fixed('J', 8)); board.get_cell_mut(Coordinates(8, 7)).unwrap().value = Some(make_letter('O', true, 1)); board.get_cell_mut(Coordinates(8, 8)).unwrap().value = Some(make_letter('E', true, 1)); - board.get_cell_mut(Coordinates(8, 9)).unwrap().value = Some(Letter::new_fixed( 'L', 1)); + board.get_cell_mut(Coordinates(8, 9)).unwrap().value = Some(Letter::new_fixed('L', 1)); board.get_cell_mut(Coordinates(0, 0)).unwrap().value = Some(Letter::new_fixed('I', 1)); board.get_cell_mut(Coordinates(1, 0)).unwrap().value = Some(Letter::new_fixed('S', 1)); @@ -814,7 +832,7 @@ mod tests { board.get_cell_mut(Coordinates(6, 0)).unwrap().value = Some(Letter::new_fixed('L', 1)); fn check_board(board: &mut Board, inverted: bool) { - let dictionary = DictionaryImpl::create_from_path("resources/dictionary.csv"); + let dictionary = DictionaryImpl::create_from_path("../resources/dictionary.csv"); println!("{}", board); let words = board.find_played_words(); match words { @@ -827,7 +845,9 @@ mod tests { assert_eq!(word.calculate_score(), 8 + 1 + 2 + 1); } - Err(e) => { panic!("Expected to find a word to play; found error {}", e) } + Err(e) => { + panic!("Expected to find a word to play; found error {}", e) + } } let maybe_invert = |coords: Coordinates| { @@ -844,12 +864,21 @@ mod tests { return direction; }; - board.get_cell_mut(maybe_invert(Coordinates(9, 8))).unwrap().value = Some(Letter::new_fixed('G', 2)); - board.get_cell_mut(maybe_invert(Coordinates(10, 8))).unwrap().value = Some(Letter::new_fixed('G', 2)); + board + .get_cell_mut(maybe_invert(Coordinates(9, 8))) + .unwrap() + .value = Some(Letter::new_fixed('G', 2)); + board + .get_cell_mut(maybe_invert(Coordinates(10, 8))) + .unwrap() + .value = Some(Letter::new_fixed('G', 2)); - let word = board.find_word_at_position(Coordinates(8, 8), maybe_invert_direction(Direction::Row)); + let word = board + .find_word_at_position(Coordinates(8, 8), maybe_invert_direction(Direction::Row)); match word { - None => {panic!("Expected to find word EGG")} + None => { + panic!("Expected to find word EGG") + } Some(x) => { assert_eq!(x.coords.0, 8); assert_eq!(x.coords.1, 8); @@ -857,7 +886,6 @@ mod tests { assert_eq!(x.to_string(), "EGG"); assert_eq!(x.calculate_score(), 2 + 2 + 2); assert!(dictionary.is_word_valid(&x)); - } } @@ -876,20 +904,29 @@ mod tests { assert_eq!(word.calculate_score(), 8 + 1 + 2 + 1); assert!(!dictionary.is_word_valid(word)); } - Err(e) => { panic!("Expected to find a word to play; found error {}", e) } + Err(e) => { + panic!("Expected to find a word to play; found error {}", e) + } } let scores = board.calculate_scores(&dictionary); match scores { - Ok(_) => {panic!("Expected an error")} - Err(e) => {assert_eq!(e, "JOEL is not a valid word")} + Ok(_) => { + panic!("Expected an error") + } + Err(e) => { + if let Error::InvalidWord(w) = e { + assert_eq!(w, "JOEL"); + } else { + panic!("Expected an InvalidPlay error") + } + } } let mut alt_dictionary = DictionaryImpl::new(); alt_dictionary.insert("JOEL".to_string(), 0.5); alt_dictionary.insert("EGG".to_string(), 0.5); - let scores = board.calculate_scores(&alt_dictionary); match scores { Ok((words, total_score)) => { @@ -906,18 +943,19 @@ mod tests { assert_eq!(total_score, 18); } - Err(e) => {panic!("Wasn't expecting to encounter error {e}")} + Err(e) => { + panic!("Wasn't expecting to encounter error {e}") + } } - // replace one of the 'G' in EGG with an ephemeral to trigger an error - board.get_cell_mut(maybe_invert(Coordinates(9, 8))).unwrap().value = Some(make_letter('G', true, 2)); + board + .get_cell_mut(maybe_invert(Coordinates(9, 8))) + .unwrap() + .value = Some(make_letter('G', true, 2)); let words = board.find_played_words(); - match words { - Ok(_) => { panic!("Expected error as we played tiles in multiple rows and columns") } - Err(e) => { assert_eq!(e, "Tiles need to be played on one row or column") } - } + assert!(matches!(words, Err(Error::TilesNotStraight))); } // make a copy of the board now with x and y swapped @@ -934,7 +972,6 @@ mod tests { cell_new.value = Some(*x); } } - } } @@ -943,8 +980,5 @@ mod tests { println!("Checking inverted board"); check_board(&mut inverted_board, true); - - } - -} \ No newline at end of file +} diff --git a/src/constants.rs b/wordgrid/src/constants.rs similarity index 99% rename from src/constants.rs rename to wordgrid/src/constants.rs index 08d5b77..b53a89f 100644 --- a/src/constants.rs +++ b/wordgrid/src/constants.rs @@ -1,6 +1,6 @@ -use rand::prelude::SliceRandom; -use rand::{Rng}; use crate::board::Letter; +use rand::prelude::SliceRandom; +use rand::Rng; pub const GRID_LENGTH: u8 = 15; pub const TRAY_LENGTH: u8 = 7; @@ -49,5 +49,4 @@ pub fn standard_tile_pool(rng: Option<&mut R>) -> Vec { } letters - -} \ No newline at end of file +} diff --git a/src/dictionary.rs b/wordgrid/src/dictionary.rs similarity index 95% rename from src/dictionary.rs rename to wordgrid/src/dictionary.rs index 82708df..a21af5c 100644 --- a/src/dictionary.rs +++ b/wordgrid/src/dictionary.rs @@ -1,10 +1,9 @@ +use crate::board::Word; +use csv::Reader; use std::collections::{HashMap, HashSet}; use std::str::FromStr; -use csv::Reader; -use crate::board::Word; pub trait Dictionary { - fn create_from_reader(reader: Reader) -> Self; fn create_from_path(path: &str) -> Self; fn create_from_str(data: &str) -> Self; @@ -14,8 +13,7 @@ pub trait Dictionary { } pub type DictionaryImpl = HashMap; -impl Dictionary for DictionaryImpl{ - +impl Dictionary for DictionaryImpl { fn create_from_reader(mut reader: Reader) -> Self { let mut map = HashMap::new(); @@ -27,7 +25,6 @@ impl Dictionary for DictionaryImpl{ let score = f64::from_str(score).unwrap(); map.insert(word, score); - } map @@ -57,7 +54,6 @@ impl Dictionary for DictionaryImpl{ } map - } fn substring_set(&self) -> HashSet<&str> { @@ -65,11 +61,10 @@ impl Dictionary for DictionaryImpl{ for (word, _score) in self.iter() { for j in 0..word.len() { - for k in (j+1)..(word.len()+1) { + for k in (j + 1)..(word.len() + 1) { set.insert(&word[j..k]); } } - } set @@ -85,10 +80,9 @@ impl Dictionary for DictionaryImpl{ mod tests { use super::*; - #[test] fn test_dictionary() { - let dictionary = HashMap::create_from_path("resources/dictionary.csv"); + let dictionary = HashMap::create_from_path("../resources/dictionary.csv"); assert_eq!(dictionary.len(), 279429); @@ -96,7 +90,6 @@ mod tests { assert!(dictionary.contains_key("AARDVARK")); assert!((dictionary.get("AARDVARK").unwrap() - 0.5798372).abs() < 0.0001) - } #[test] @@ -131,11 +124,8 @@ mod tests { assert!(set.contains("JOH")); assert!(set.contains("OHN")); - assert!(!set.contains("XY")); assert!(!set.contains("JH")); assert!(!set.contains("JE")); - } - -} \ No newline at end of file +} diff --git a/src/game.rs b/wordgrid/src/game.rs similarity index 62% rename from src/game.rs rename to wordgrid/src/game.rs index 2f7ae87..b29784e 100644 --- a/src/game.rs +++ b/wordgrid/src/game.rs @@ -1,31 +1,90 @@ use std::collections::HashMap; +use std::fmt::{Display, Formatter}; -use rand::prelude::SliceRandom; -use rand::rngs::SmallRng; -use rand::SeedableRng; -use serde::{Deserialize, Serialize}; -use tsify::Tsify; use crate::board::{Board, Coordinates, Letter}; use crate::constants::{standard_tile_pool, TRAY_LENGTH}; use crate::dictionary::{Dictionary, DictionaryImpl}; -use crate::player_interaction::ai::{AI, CompleteMove, Difficulty}; +use crate::player_interaction::ai::{Difficulty, AI}; use crate::player_interaction::Tray; +use rand::prelude::SliceRandom; +use rand::rngs::SmallRng; +use rand::SeedableRng; +use serde::{Deserialize, Serialize, Serializer}; pub enum Player { Human(String), - AI{ + AI { name: String, difficulty: Difficulty, object: AI, + }, +} + +#[derive(Debug)] +pub enum Error { + InvalidPlayer(String), + WrongTurn(String), + Other(String), + InvalidWord(String), + GameFinished, + NoTilesPlayed, + TilesNotStraight, + TilesHaveGap, + OneLetterWord, + UnanchoredWord, +} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match &self { + Error::InvalidPlayer(player) => { + write!(f, "{player} doesn't exist") + } + Error::WrongTurn(player) => { + write!(f, "It's not {player}'s turn") + } + Error::Other(msg) => { + write!(f, "Other error: {msg}") + } + Error::InvalidWord(word) => { + write!(f, "{word} is not a valid word") + } + Error::GameFinished => { + write!(f, "Moves cannot be made after a game has finished") + } + Error::NoTilesPlayed => { + write!(f, "Tiles need to be played") + } + Error::TilesNotStraight => { + write!(f, "Tiles need to be played on one row or column") + } + Error::TilesHaveGap => { + write!(f, "Played tiles cannot have empty gap") + } + Error::OneLetterWord => { + write!(f, "All words must be at least two letters") + } + Error::UnanchoredWord => { + write!(f, "Played tiles must be anchored to something") + } + } + } +} + +impl Serialize for Error { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self.to_string()) } } impl Player { - pub fn get_name(&self) -> &str { match &self { - Player::Human(name) => {name} - Player::AI { name, .. } => {name} + Player::Human(name) => name, + Player::AI { name, .. } => name, } } } @@ -33,18 +92,20 @@ impl Player { pub struct PlayerState { pub player: Player, pub score: u32, - pub tray: Tray + pub tray: Tray, } -#[derive(Deserialize, Tsify, Copy, Clone, Debug)] -#[tsify(from_wasm_abi)] +#[derive(Deserialize, Copy, Clone, Debug)] pub struct PlayedTile { pub index: usize, pub character: Option, // we only set this if PlayedTile is a blank } impl PlayedTile { - pub fn convert_tray(tray_tile_locations: &Vec>, tray: &Tray) -> Vec<(Letter, Coordinates)> { + pub fn convert_tray( + tray_tile_locations: &Vec>, + tray: &Tray, + ) -> Vec<(Letter, Coordinates)> { let mut played_letters: Vec<(Letter, Coordinates)> = Vec::new(); for (i, played_tile) in tray_tile_locations.iter().enumerate() { if played_tile.is_some() { @@ -55,7 +116,9 @@ impl PlayedTile { if letter.is_blank { match played_tile.character { None => { - panic!("You can't play a blank character without providing a letter value") + panic!( + "You can't play a blank character without providing a letter value" + ) } Some(x) => { // TODO - check that x is a valid alphabet letter @@ -64,7 +127,6 @@ impl PlayedTile { } } played_letters.push((letter, coord)); - } } @@ -72,15 +134,13 @@ impl PlayedTile { } } -#[derive(Debug, Serialize, Deserialize, Tsify)] -#[tsify(from_wasm_abi)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct WordResult { word: String, score: u32, } -#[derive(Debug, Serialize, Deserialize, Tsify)] -#[tsify(from_wasm_abi)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct ScoreResult { words: Vec, total: u32, @@ -88,7 +148,6 @@ pub struct ScoreResult { pub struct PlayerStates(pub Vec); impl PlayerStates { - fn get_player_name_by_turn_id(&self, id: usize) -> &str { let id_mod = id % self.0.len(); let state = self.0.get(id_mod).unwrap(); @@ -97,37 +156,33 @@ impl PlayerStates { } pub fn get_player_state(&self, name: &str) -> Option<&PlayerState> { - self.0.iter() + self.0 + .iter() .filter(|state| state.player.get_name().eq(name)) .nth(0) - } pub fn get_player_state_mut(&mut self, name: &str) -> Option<&mut PlayerState> { - self.0.iter_mut() + self.0 + .iter_mut() .filter(|state| state.player.get_name().eq(name)) .nth(0) - } pub fn get_tray(&self, name: &str) -> Option<&Tray> { let player = self.get_player_state(name)?; Some(&player.tray) - } pub fn get_tray_mut(&mut self, name: &str) -> Option<&mut Tray> { let player = self.get_player_state_mut(name)?; Some(&mut player.tray) - } } - -#[derive(Deserialize, Serialize, Tsify, Debug, Clone)] -#[tsify(from_wasm_abi)] +#[derive(Deserialize, Serialize, Debug, Clone)] #[serde(tag = "type")] pub enum GameState { InProgress, @@ -137,7 +192,7 @@ pub enum GameState { }, } -pub struct Game{ +pub struct Game { pub tile_pool: Vec, rng: SmallRng, board: Board, @@ -148,15 +203,20 @@ pub struct Game{ state: GameState, } - impl Game { - pub fn new(seed: u64, dictionary_text: &str, player_names: Vec, ai_difficulties: Vec) -> Self { + pub fn new( + seed: u64, + dictionary_text: &str, + player_names: Vec, + ai_difficulties: Vec, + ) -> Self { let mut rng = SmallRng::seed_from_u64(seed); let mut letters = standard_tile_pool(Some(&mut rng)); let dictionary = DictionaryImpl::create_from_str(dictionary_text); - let mut player_states: Vec = player_names.iter() + let mut player_states: Vec = player_names + .iter() .map(|name| { let mut tray = Tray::new(TRAY_LENGTH); tray.fill(&mut letters); @@ -174,7 +234,7 @@ impl Game { let mut tray = Tray::new(TRAY_LENGTH); tray.fill(&mut letters); let ai_player_name = if ai_length > 1 { - format!("AI {}", i+1) + format!("AI {}", i + 1) } else { "AI".to_string() }; @@ -204,15 +264,15 @@ impl Game { } } - - - pub fn get_board(&self) -> &Board {&self.board} + pub fn get_board(&self) -> &Board { + &self.board + } pub fn set_board(&mut self, new_board: Board) { self.board = new_board; } - fn fill_trays(&mut self){ + fn fill_trays(&mut self) { for state in self.player_states.0.iter_mut() { let tray = &mut state.tray; tray.fill(&mut self.tile_pool); @@ -223,14 +283,18 @@ impl Game { &self.dictionary } - fn verify_game_in_progress(&self) -> Result<(), String> { + fn verify_game_in_progress(&self) -> Result<(), Error> { if !matches!(self.state, GameState::InProgress) { - return Err("Moves cannot be made after a game has finished".to_string()); + return Err(Error::GameFinished); } Ok(()) } - pub fn receive_play(&mut self, tray_tile_locations: Vec>, commit_move: bool) -> Result<(TurnAction, GameState), String> { + pub fn receive_play( + &mut self, + tray_tile_locations: Vec>, + commit_move: bool, + ) -> Result<(TurnAction, GameState), Error> { self.verify_game_in_progress()?; let player = self.current_player_name(); @@ -238,7 +302,8 @@ impl Game { let mut board_instance = self.get_board().clone(); let mut tray = self.player_states.get_tray(&player).unwrap().clone(); - let played_letters: Vec<(Letter, Coordinates)> = PlayedTile::convert_tray(&tray_tile_locations, &tray); + let played_letters: Vec<(Letter, Coordinates)> = + PlayedTile::convert_tray(&tray_tile_locations, &tray); for (i, played_tile) in tray_tile_locations.iter().enumerate() { if played_tile.is_some() { *tray.letters.get_mut(i).unwrap() = None; @@ -247,19 +312,16 @@ impl Game { board_instance.receive_play(played_letters)?; - let x = board_instance.calculate_scores(self.get_dictionary())?; let total_score = x.1; - let words: Vec = x.0.iter() - .map(|(word, score)| { - WordResult { + let words: Vec = + x.0.iter() + .map(|(word, score)| WordResult { word: word.to_string(), - score: *score - } - - }) - .collect(); + score: *score, + }) + .collect(); if commit_move { let player_state = self.player_states.get_player_state_mut(&player).unwrap(); @@ -276,28 +338,42 @@ impl Game { // game is over self.end_game(Some(player)); } - } - Ok((TurnAction::PlayTiles { - result: ScoreResult { - words, - total: total_score, + let locations = tray_tile_locations + .iter() + .filter_map(|x| x.as_ref()) + .map(|x| x.index) + .collect::>(); + + Ok(( + TurnAction::PlayTiles { + result: ScoreResult { + words, + total: total_score, + }, + locations, }, - }, self.state.clone())) + self.get_state(), + )) } - pub fn exchange_tiles(&mut self, tray_tile_locations: Vec) -> Result<(Tray, TurnAction, GameState), String> { + pub fn exchange_tiles( + &mut self, + tray_tile_locations: Vec, + ) -> Result<(Tray, TurnAction, GameState), Error> { self.verify_game_in_progress()?; let player = self.current_player_name(); let tray = match self.player_states.get_tray_mut(&player) { - None => {return Err(format!("Player {} not found", player))} - Some(x) => {x} + None => return Err(Error::InvalidPlayer(player)), + Some(x) => x, }; if tray.letters.len() != tray_tile_locations.len() { - return Err("Incoming tray and existing tray have different lengths".to_string()); + return Err(Error::Other( + "Incoming tray and existing tray have different lengths".to_string(), + )); } let tile_pool = &mut self.tile_pool; @@ -321,8 +397,11 @@ impl Game { let state = self.increment_turn(false); - Ok((tray, TurnAction::ExchangeTiles { tiles_exchanged }, state.clone())) - + Ok(( + tray, + TurnAction::ExchangeTiles { tiles_exchanged }, + state.clone(), + )) } pub fn add_word(&mut self, word: String) { @@ -331,21 +410,20 @@ impl Game { self.dictionary.insert(word, -1.0); } - pub fn pass(&mut self) -> Result { + pub fn pass(&mut self) -> Result { self.verify_game_in_progress()?; Ok(self.increment_turn(false).clone()) } - fn increment_turn(&mut self, played: bool) -> &GameState{ + fn increment_turn(&mut self, played: bool) -> &GameState { self.turn_order += 1; if !played { self.turns_not_played += 1; // check if game has ended due to passing - if self.turns_not_played >= 2*self.player_states.0.len() { + if self.turns_not_played >= 2 * self.player_states.0.len() { self.end_game(None); } - } else { self.turns_not_played = 0; } @@ -354,7 +432,6 @@ impl Game { } fn end_game(&mut self, finisher: Option) { - let mut finished_letters_map = HashMap::new(); let mut points_forfeit = 0; @@ -376,25 +453,30 @@ impl Game { } if let Some(finisher) = &finisher { - let mut state = self.player_states.get_player_state_mut(finisher).unwrap(); + let state = self.player_states.get_player_state_mut(finisher).unwrap(); state.score += points_forfeit; } self.state = GameState::Ended { finisher, - remaining_tiles: finished_letters_map + remaining_tiles: finished_letters_map, }; } pub fn current_player_name(&self) -> String { - self.player_states.get_player_name_by_turn_id(self.turn_order).to_string() + self.player_states + .get_player_name_by_turn_id(self.turn_order) + .to_string() } - pub fn advance_turn(&mut self) -> Result<(TurnAdvanceResult, GameState), String> { + pub fn advance_turn(&mut self) -> Result<(TurnAdvanceResult, GameState), Error> { let current_player = self.current_player_name(); - let state = self.player_states.get_player_state_mut(¤t_player).ok_or("There should be a player available")?; + let state = self + .player_states + .get_player_state_mut(¤t_player) + .ok_or(Error::InvalidPlayer(current_player.clone()))?; - if let Player::AI {object, .. } = &mut state.player { + if let Player::AI { object, .. } = &mut state.player { let tray = &mut state.tray; let best_move = object.find_best_move(tray, &self.board, &mut self.rng); @@ -407,43 +489,53 @@ impl Game { match tile_spot { None => { to_exchange.push(false); - }, + } Some(_) => { to_exchange.push(true); } } } - if self.tile_pool.is_empty(){ + if self.tile_pool.is_empty() { let game_state = self.increment_turn(false); - Ok((TurnAdvanceResult::AIMove { - name: current_player, - action: TurnAction::Pass, - }, game_state.clone())) + Ok(( + TurnAdvanceResult::AIMove { + name: current_player, + action: TurnAction::Pass, + }, + game_state.clone(), + )) } else { let (_, action, game_state) = self.exchange_tiles(to_exchange)?; - Ok((TurnAdvanceResult::AIMove { - name: current_player, - action, - }, game_state)) + Ok(( + TurnAdvanceResult::AIMove { + name: current_player, + action, + }, + game_state, + )) } - - } Some(best_move) => { let play = best_move.convert_to_play(tray); let (action, game_state) = self.receive_play(play, true)?; - Ok((TurnAdvanceResult::AIMove { - name: current_player, - action, - }, game_state)) + Ok(( + TurnAdvanceResult::AIMove { + name: current_player, + action, + }, + game_state, + )) } } } else { - Ok((TurnAdvanceResult::HumanInputRequired{name: self.current_player_name()}, self.state.clone())) + Ok(( + TurnAdvanceResult::HumanInputRequired { + name: self.current_player_name(), + }, + self.get_state(), + )) } - - } pub fn get_remaining_tiles(&self) -> usize { @@ -452,60 +544,61 @@ impl Game { pub fn get_player_tile_count(&self, player: &str) -> Result { let tray = match self.player_states.get_tray(&player) { - None => {return Err(format!("Player {} not found", player))} - Some(x) => {x} + None => return Err(format!("Player {} not found", player)), + Some(x) => x, }; - Ok( - tray.count() - ) + Ok(tray.count()) } - - + pub fn get_state(&self) -> GameState { + self.state.clone() + } } -#[derive(Serialize, Deserialize, Tsify, Debug)] -#[tsify(from_wasm_abi)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type")] pub enum TurnAction { Pass, - ExchangeTiles{ - tiles_exchanged: usize + ExchangeTiles { + tiles_exchanged: usize, }, - PlayTiles{ - result: ScoreResult + PlayTiles { + result: ScoreResult, + locations: Vec, }, } -#[derive(Serialize, Deserialize, Tsify, Debug)] -#[tsify(from_wasm_abi)] +#[derive(Serialize, Deserialize, Debug)] #[serde(tag = "type")] pub enum TurnAdvanceResult { - HumanInputRequired{ - name: String - }, - AIMove{ - name: String, - action: TurnAction, - } + HumanInputRequired { name: String }, + AIMove { name: String, action: TurnAction }, } #[cfg(test)] mod tests { - use std::fs; use crate::game::Game; use crate::player_interaction::ai::Difficulty; + use std::fs; #[test] fn test_game() { let seed = 124; - let dictionary_path = "resources/dictionary.csv"; + let dictionary_path = "../resources/dictionary.csv"; let dictionary_string = fs::read_to_string(dictionary_path).unwrap(); - let mut game = Game::new(seed, &dictionary_string, vec!["Player".to_string()], vec![Difficulty{proportion: 0.5, randomness: 0.0}]); + let mut game = Game::new( + seed, + &dictionary_string, + vec!["Player".to_string()], + vec![Difficulty { + proportion: 0.5, + randomness: 0.0, + }], + ); let current_player = game.current_player_name(); println!("Current player is {current_player}"); @@ -522,7 +615,5 @@ mod tests { assert_eq!(game.current_player_name(), "Player"); assert_eq!(0, game.turns_not_played); - } - -} \ No newline at end of file +} diff --git a/wordgrid/src/lib.rs b/wordgrid/src/lib.rs new file mode 100644 index 0000000..a7c027c --- /dev/null +++ b/wordgrid/src/lib.rs @@ -0,0 +1,6 @@ +pub mod api; +pub mod board; +pub mod constants; +pub mod dictionary; +pub mod game; +pub mod player_interaction; diff --git a/src/player_interaction.rs b/wordgrid/src/player_interaction.rs similarity index 86% rename from src/player_interaction.rs rename to wordgrid/src/player_interaction.rs index 0e32b17..d25f4e5 100644 --- a/src/player_interaction.rs +++ b/wordgrid/src/player_interaction.rs @@ -1,14 +1,11 @@ -use serde::{Deserialize, Serialize}; -use tsify::Tsify; use crate::board::Letter; - +use serde::{Deserialize, Serialize}; pub mod ai; -#[derive(Debug, Serialize, Deserialize, Tsify, Clone)] -#[tsify(from_wasm_abi)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct Tray { - pub letters: Vec> + pub letters: Vec>, } impl Tray { @@ -17,9 +14,7 @@ impl Tray { for _ in 0..tray_length { letters.push(None); } - Tray { - letters - } + Tray { letters } } pub fn fill(&mut self, standard_tile_pool: &mut Vec) { @@ -37,25 +32,20 @@ impl Tray { } pub fn count(&self) -> usize { - self.letters.iter() - .filter(|l| l.is_some()) - .count() + self.letters.iter().filter(|l| l.is_some()).count() } - - } #[cfg(test)] mod tests { use super::*; - #[test] fn test_tray() { let mut letters = vec![ Letter::new(Some('E'), 3), Letter::new(Some('O'), 2), - Letter::new(Some('J'), 1) + Letter::new(Some('J'), 1), ]; let mut tray = Tray::new(5); @@ -89,8 +79,5 @@ mod tests { assert_eq!(tray.letters.get(2).unwrap().unwrap().text, 'E'); assert!(tray.letters.get(3).unwrap().is_none()); assert!(tray.letters.get(4).unwrap().is_none()); - - } - -} \ No newline at end of file +} diff --git a/src/player_interaction/ai.rs b/wordgrid/src/player_interaction/ai.rs similarity index 82% rename from src/player_interaction/ai.rs rename to wordgrid/src/player_interaction/ai.rs index 78f6de2..4cd4f26 100644 --- a/src/player_interaction/ai.rs +++ b/wordgrid/src/player_interaction/ai.rs @@ -1,14 +1,16 @@ -use std::collections::{HashMap, HashSet}; -use rand::Rng; -use serde::{Deserialize, Serialize}; -use tsify::Tsify; use crate::board::{Board, CellType, Coordinates, Direction, Letter}; use crate::constants::GRID_LENGTH; use crate::dictionary::DictionaryImpl; use crate::game::PlayedTile; use crate::player_interaction::Tray; +use rand::Rng; +use serde::{Deserialize, Serialize}; +use std::collections::{HashMap, HashSet}; -const ALPHABET: [char; 26] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; +const ALPHABET: [char; 26] = [ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', +]; struct CoordinateLineMapper { direction: Direction, @@ -18,18 +20,13 @@ struct CoordinateLineMapper { impl CoordinateLineMapper { fn line_to_coord(&self, variable: u8) -> Coordinates { match self.direction { - Direction::Row => { - Coordinates(variable, self.fixed) - } - Direction::Column => { - Coordinates(self.fixed, variable) - } + Direction::Row => Coordinates(variable, self.fixed), + Direction::Column => Coordinates(self.fixed, variable), } } } -#[derive(Copy, Clone, Serialize, Deserialize, Tsify)] -#[tsify(from_wasm_abi)] +#[derive(Copy, Clone, Serialize, Deserialize)] pub struct Difficulty { pub proportion: f64, pub randomness: f64, @@ -48,7 +45,6 @@ pub struct AI { type MoveMap = HashMap; type CrossTiles = Vec>; - #[derive(Debug, Eq, PartialEq, Hash)] pub struct CompleteMove { moves: Vec, @@ -56,10 +52,11 @@ pub struct CompleteMove { } impl CompleteMove { - pub fn convert_to_play(&self, tray: &Tray) -> Vec> { let mut played_tiles = Vec::with_capacity(tray.letters.len()); - let mut moves = self.moves.iter() + let mut moves = self + .moves + .iter() .map(|m| Some(m.clone())) .collect::>>(); @@ -88,7 +85,7 @@ impl CompleteMove { found_match = true; break; } - }, + } None => {} } } @@ -127,29 +124,28 @@ struct MoveComponent { } impl AI { - - pub fn new(difficulty: Difficulty, dictionary: &DictionaryImpl) -> Self{ + pub fn new(difficulty: Difficulty, dictionary: &DictionaryImpl) -> Self { let mut ai_dictionary = HashSet::new(); let mut substrings = HashSet::new(); for (word, score) in dictionary.iter() { - if *score >= difficulty.proportion { // TODO - may need to reverse + if *score >= difficulty.proportion { + // TODO - may need to reverse ai_dictionary.insert(word.clone()); substrings.insert(word.clone()); for i in 0..word.len() { - for j in i+1..word.len() { + for j in i + 1..word.len() { substrings.insert(word[i..j].to_string()); } } - - } } let board_view = Board::new(); - let mut column_cross_tiles = CrossTiles::with_capacity((GRID_LENGTH * GRID_LENGTH) as usize); + let mut column_cross_tiles = + CrossTiles::with_capacity((GRID_LENGTH * GRID_LENGTH) as usize); let mut row_cross_tiles = CrossTiles::with_capacity((GRID_LENGTH * GRID_LENGTH) as usize); board_view.cells.iter().for_each(|_| { @@ -168,15 +164,20 @@ impl AI { } } - pub fn find_best_move(&mut self, tray: &Tray, grid: &Board, rng: &mut R) -> Option{ + pub fn find_best_move( + &mut self, + tray: &Tray, + grid: &Board, + rng: &mut R, + ) -> Option { let move_set = self.find_all_moves(tray, grid); let mut best_move: Option<(CompleteMove, f64)> = None; for possible_move in move_set { - let move_score = - if self.difficulty.randomness > 0.0 { - (1.0 - self.difficulty.randomness) * (possible_move.score as f64) + self.difficulty.randomness * rng.gen_range(0.0..1.0) + let move_score = if self.difficulty.randomness > 0.0 { + (1.0 - self.difficulty.randomness) * (possible_move.score as f64) + + self.difficulty.randomness * rng.gen_range(0.0..1.0) } else { possible_move.score as f64 }; @@ -194,10 +195,9 @@ impl AI { } return match best_move { - None => {None} - Some((best_move, _)) => {Some(best_move)} + None => None, + Some((best_move, _)) => Some(best_move), }; - } fn find_all_moves(&mut self, tray: &Tray, grid: &Board) -> HashSet { @@ -215,15 +215,17 @@ impl AI { &self, tray: &Tray, direction: Direction, - all_moves: &mut HashSet) { - + all_moves: &mut HashSet, + ) { // If you're building a word in one direction, you need to form valid words in the cross-direction let cross_tiles = match direction { - Direction::Column => {&self.row_cross_tiles} - Direction::Row => {&self.column_cross_tiles} + Direction::Column => &self.row_cross_tiles, + Direction::Row => &self.column_cross_tiles, }; - let tray_letters = tray.letters.iter() + let tray_letters = tray + .letters + .iter() .filter(|letter| letter.is_some()) .map(|letter| letter.unwrap()) .collect::>(); @@ -234,7 +236,7 @@ impl AI { let coord_mapper = CoordinateLineMapper { direction, - fixed: k + fixed: k, }; for p in 0..GRID_LENGTH { @@ -246,13 +248,12 @@ impl AI { for l in 0..GRID_LENGTH { let coords = coord_mapper.line_to_coord(l); - let is_anchored = check_if_anchored(&self.board_view, coords, Direction::Row) || - check_if_anchored(&self.board_view, coords, Direction::Column); + let is_anchored = check_if_anchored(&self.board_view, coords, Direction::Row) + || check_if_anchored(&self.board_view, coords, Direction::Column); - if is_anchored && - line_letters.get(l as usize).unwrap().is_none() // it's duplicate work to check here when we'll already check at either free side + if is_anchored && line_letters.get(l as usize).unwrap().is_none() + // it's duplicate work to check here when we'll already check at either free side { - self.evaluate_spot_heading_left( &line_letters, &line_cross_letters, @@ -262,17 +263,11 @@ impl AI { &Vec::new(), 1, &MoveScoring::new(), - - all_moves - - ); - + all_moves, + ); } - - } } - } fn evaluate_spot_heading_left( @@ -287,10 +282,8 @@ impl AI { min_length: usize, current_points: &MoveScoring, - all_moves: &mut HashSet - + all_moves: &mut HashSet, ) { - if line_index < 0 || line_index >= GRID_LENGTH as i8 { return; } @@ -300,10 +293,13 @@ impl AI { Some(_) => { // there's a letter here; need to take a step left if we can - if !(line_index >= 1 && - line_letters.get((line_index-1) as usize).unwrap().is_some() && - min_length == 1 - ) { + if !(line_index >= 1 + && line_letters + .get((line_index - 1) as usize) + .unwrap() + .is_some() + && min_length == 1) + { // if-statement is basically saying that if we're at the start of the process (min_length==1) and there's a word still to our left, // just stop. Other versions of the for-loops that call this function will have picked up that case. self.evaluate_spot_heading_left( @@ -315,9 +311,8 @@ impl AI { current_play, min_length, current_points, - all_moves + all_moves, ); - } } None => { @@ -331,10 +326,9 @@ impl AI { min_length, current_points, coord_mapper, - &available_letters, letter.clone(), - all_moves + all_moves, ); } @@ -348,12 +342,10 @@ impl AI { current_play, min_length + 1, current_points, - all_moves + all_moves, ); } } - - } fn evaluate_letter_at_spot( @@ -366,13 +358,10 @@ impl AI { current_points: &MoveScoring, coord_mapper: &CoordinateLineMapper, - available_letters: &Vec, letter: Letter, - all_moves: &mut HashSet - + all_moves: &mut HashSet, ) { - if letter.is_blank { // need to loop through alphabet for alpha in ALPHABET { @@ -389,8 +378,7 @@ impl AI { coord_mapper, available_letters, letter, - all_moves - + all_moves, ); } } else { @@ -404,10 +392,9 @@ impl AI { coord_mapper, available_letters, letter.clone(), - all_moves + all_moves, ); } - } fn evaluate_non_blank_letter_at_spot( @@ -419,15 +406,12 @@ impl AI { min_length: usize, current_points: &MoveScoring, - coord_mapper: &CoordinateLineMapper, available_letters: &Vec, letter: Letter, all_moves: &mut HashSet, - ) { - // let's now assign the letter to this spot let mut line_letters = line_letters.clone(); *line_letters.get_mut(line_index as usize).unwrap() = Some(letter); @@ -458,7 +442,11 @@ impl AI { // making copy let mut current_points = current_points.clone(); - let cell_type = self.board_view.get_cell(coord_mapper.line_to_coord(line_index as u8)).unwrap().cell_type; + let cell_type = self + .board_view + .get_cell(coord_mapper.line_to_coord(line_index as u8)) + .unwrap() + .cell_type; // first we score cross letters if let Some(map) = cross_letters { @@ -508,7 +496,8 @@ impl AI { current_points.main_scoring += letter.points * 2; } CellType::TripleLetter => { - current_points.main_scoring += letter.points * 3;} + current_points.main_scoring += letter.points * 3; + } }; // finally, while we know that we're in a valid substring we should check if this is a valid word or not @@ -516,7 +505,8 @@ impl AI { if word.len() >= min_length && self.dictionary.contains(&word) { let new_move = CompleteMove { moves: current_play.clone(), - score: current_points.cross_scoring + current_points.main_scoring*current_points.multiplier, + score: current_points.cross_scoring + + current_points.main_scoring * current_points.multiplier, }; all_moves.insert(new_move); } @@ -525,29 +515,26 @@ impl AI { let mut new_available_letters = Vec::with_capacity(available_letters.len() - 1); let mut skipped_one = false; - available_letters.iter() - .for_each(|in_tray| { - if skipped_one || !in_tray.partial_match(&letter) { - new_available_letters.push(*in_tray); - } else { - skipped_one = true; - } - }); + available_letters.iter().for_each(|in_tray| { + if skipped_one || !in_tray.partial_match(&letter) { + new_available_letters.push(*in_tray); + } else { + skipped_one = true; + } + }); assert!(skipped_one); // at least one should have been removed self.evaluate_spot_heading_right( &line_letters, line_cross_letters, - line_index+1, + line_index + 1, current_play, min_length, ¤t_points, - coord_mapper, &new_available_letters, - - all_moves + all_moves, ); } @@ -560,13 +547,11 @@ impl AI { min_length: usize, current_points: &MoveScoring, - coord_mapper: &CoordinateLineMapper, available_letters: &Vec, all_moves: &mut HashSet, ) { - // out-of-bounds check if line_index < 0 || line_index >= GRID_LENGTH as i8 { return; @@ -586,11 +571,11 @@ impl AI { ¤t_points, coord_mapper, available_letters, - all_moves + all_moves, ); } None => { - // there's a blank spot, so let's loop through every available letter and evaluate at this spot + // there's a blank spot, so let's loop through every available letter and evaluate at this spot for letter in available_letters { self.evaluate_letter_at_spot( line_letters, @@ -601,10 +586,8 @@ impl AI { current_points, coord_mapper, available_letters, - letter.clone(), - all_moves - + all_moves, ) } } @@ -625,25 +608,29 @@ impl AI { } let mut check_for_valid_moves = |coords: Coordinates| { - let cell = new.get_cell(coords).unwrap(); if cell.value.is_none() { let valid_row_moves = self.get_letters_that_make_words(new, Direction::Row, coords); - let valid_column_moves = self.get_letters_that_make_words(new, Direction::Column, coords); + let valid_column_moves = + self.get_letters_that_make_words(new, Direction::Column, coords); - let existing_row_moves = self.row_cross_tiles.get_mut(coords.map_to_index()).unwrap(); + let existing_row_moves = + self.row_cross_tiles.get_mut(coords.map_to_index()).unwrap(); *existing_row_moves = valid_row_moves; - let existing_column_moves = self.column_cross_tiles.get_mut(coords.map_to_index()).unwrap(); + let existing_column_moves = self + .column_cross_tiles + .get_mut(coords.map_to_index()) + .unwrap(); *existing_column_moves = valid_column_moves; } }; updated_rows.iter().for_each(|&j| { - for i in 0..GRID_LENGTH { - let coords = Coordinates(i, j); - check_for_valid_moves(coords); - } + for i in 0..GRID_LENGTH { + let coords = Coordinates(i, j); + check_for_valid_moves(coords); + } }); updated_columns.iter().for_each(|&i| { @@ -652,10 +639,14 @@ impl AI { check_for_valid_moves(coords); } }); - } - fn get_letters_that_make_words(&self, new: &Board, direction: Direction, coords: Coordinates) -> Option { + fn get_letters_that_make_words( + &self, + new: &Board, + direction: Direction, + coords: Coordinates, + ) -> Option { let is_anchored = check_if_anchored(new, coords, direction); if !is_anchored { return None; @@ -668,7 +659,7 @@ impl AI { let cell = copy_grid.get_cell_mut(coords).unwrap(); cell.value = Some(Letter { text: letter, - points: 0, // points are accounted for later + points: 0, // points are accounted for later ephemeral: false, // so that tile bonuses are ignored is_blank: false, }); @@ -687,11 +678,9 @@ impl AI { Some(new_map) } - } -fn check_if_anchored(grid: &Board, coords: Coordinates, direction: Direction) -> bool{ - +fn check_if_anchored(grid: &Board, coords: Coordinates, direction: Direction) -> bool { // Middle tile is always considered anchored if coords.0 == GRID_LENGTH / 2 && coords.1 == GRID_LENGTH / 2 { return true; @@ -699,7 +688,7 @@ fn check_if_anchored(grid: &Board, coords: Coordinates, direction: Direction) -> let has_letter = |alt_coord: Option| -> bool { match alt_coord { - None => {false} + None => false, Some(alt_coord) => { let cell = grid.get_cell(alt_coord).unwrap(); cell.value.is_some() @@ -719,7 +708,11 @@ fn find_word_on_line(line_letters: &Vec>, line_index: i8) -> Stri if start_word < 1 { break; } - if line_letters.get((start_word - 1) as usize).unwrap().is_none() { + if line_letters + .get((start_word - 1) as usize) + .unwrap() + .is_none() + { break; } start_word -= 1; @@ -738,19 +731,20 @@ fn find_word_on_line(line_letters: &Vec>, line_index: i8) -> Stri let mut str = String::new(); line_letters[(start_word as usize)..((end_word + 1) as usize)] - .iter().for_each(|letter| { - str.push(letter.unwrap().text); - }); + .iter() + .for_each(|letter| { + str.push(letter.unwrap().text); + }); str } #[cfg(test)] mod tests { + use super::*; + use crate::dictionary::Dictionary; use rand::rngs::SmallRng; use rand::SeedableRng; - use crate::dictionary::Dictionary; - use super::*; fn set_cell(board: &mut Board, x: u8, y: u8, letter: char, points: u32) { let cell = board.get_cell_mut(Coordinates(x, y)).unwrap(); @@ -793,31 +787,31 @@ mod tests { dictionary.insert("APPLE".to_string(), 0.9); let mut tray = Tray::new(7); - tray.letters[0] = Some(Letter{ + tray.letters[0] = Some(Letter { text: 'A', points: 5, ephemeral: false, is_blank: false, }); - tray.letters[1] = Some(Letter{ + tray.letters[1] = Some(Letter { text: 'P', points: 4, ephemeral: false, is_blank: false, }); - tray.letters[2] = Some(Letter{ + tray.letters[2] = Some(Letter { text: 'P', points: 4, ephemeral: false, is_blank: false, }); - tray.letters[3] = Some(Letter{ + tray.letters[3] = Some(Letter { text: 'L', points: 3, ephemeral: false, is_blank: false, }); - tray.letters[4] = Some(Letter{ + tray.letters[4] = Some(Letter { text: 'E', points: 4, ephemeral: false, @@ -832,14 +826,12 @@ mod tests { assert_eq!(moves.len(), 10); - tray.letters[4] = Some( - Letter { - text: ' ', - points: 0, - ephemeral: false, - is_blank: true, - } - ); + tray.letters[4] = Some(Letter { + text: ' ', + points: 0, + ephemeral: false, + is_blank: true, + }); let moves = ai.find_all_moves(&tray, &board); @@ -857,8 +849,6 @@ mod tests { set_cell(&mut board, 7, 9, 'A', 1); set_cell(&mut board, 7, 10, 'T', 1); - - let difficulty = Difficulty { proportion: 0.0, // restrict yourself to words with this proportion OR HIGHER randomness: 0.0, @@ -869,25 +859,25 @@ mod tests { dictionary.insert("SLAM".to_string(), 0.9); let mut tray = Tray::new(7); - tray.letters[0] = Some(Letter{ + tray.letters[0] = Some(Letter { text: 'S', points: 1, ephemeral: false, is_blank: false, }); - tray.letters[1] = Some(Letter{ + tray.letters[1] = Some(Letter { text: 'L', points: 1, ephemeral: false, is_blank: false, }); - tray.letters[6] = Some(Letter{ + tray.letters[6] = Some(Letter { text: 'A', points: 1, ephemeral: false, is_blank: false, }); - tray.letters[3] = Some(Letter{ + tray.letters[3] = Some(Letter { text: 'M', points: 3, ephemeral: false, @@ -898,7 +888,10 @@ mod tests { ai.update_state(&board); - let end_of_boat = ai.column_cross_tiles.get(Coordinates(7, 11).map_to_index()).unwrap(); + let end_of_boat = ai + .column_cross_tiles + .get(Coordinates(7, 11).map_to_index()) + .unwrap(); assert!(end_of_boat.is_some()); assert_eq!(end_of_boat.as_ref().unwrap().len(), 1); @@ -906,7 +899,6 @@ mod tests { println!("Moves are {:?}", moves); - // 3 possible moves - // 1. put 'S' at the end of 'BOAT' and form words 'SLAM' and 'BOATS' // 2. Put 'S' at end of 'BOAT' @@ -920,7 +912,6 @@ mod tests { let play = best_move.convert_to_play(&tray); println!("Play is {:?}", play); - } #[test] @@ -943,25 +934,30 @@ mod tests { let above_cell_coords = Coordinates(7, 6); let left_cell_cords = Coordinates(6, 7); - let row_cross_tiles = ai.row_cross_tiles.get(left_cell_cords.map_to_index()).unwrap(); - let column_cross_tiles = ai.column_cross_tiles.get(above_cell_coords.map_to_index()).unwrap(); + let row_cross_tiles = ai + .row_cross_tiles + .get(left_cell_cords.map_to_index()) + .unwrap(); + let column_cross_tiles = ai + .column_cross_tiles + .get(above_cell_coords.map_to_index()) + .unwrap(); assert_eq!(row_cross_tiles.as_ref().unwrap().len(), 1); assert_eq!(column_cross_tiles.as_ref().unwrap().len(), 1); let far_off_tiles = ai.row_cross_tiles.get(0).unwrap(); assert!(far_off_tiles.is_none()); - } #[test] fn test_valid_moves() { let mut board = Board::new(); - set_cell(&mut board, 7-3, 7+3, 'Z', 1); - set_cell(&mut board, 6-3, 8+3, 'A', 1); - set_cell(&mut board, 7-3, 8+3, 'A', 1); - set_cell(&mut board, 7-3, 9+3, 'Z', 1); + set_cell(&mut board, 7 - 3, 7 + 3, 'Z', 1); + set_cell(&mut board, 6 - 3, 8 + 3, 'A', 1); + set_cell(&mut board, 7 - 3, 8 + 3, 'A', 1); + set_cell(&mut board, 7 - 3, 9 + 3, 'Z', 1); let difficulty = Difficulty { proportion: 0.0, // restrict yourself to words with this proportion OR HIGHER @@ -972,7 +968,7 @@ mod tests { dictionary.insert("AA".to_string(), 0.5); let mut tray = Tray::new(7); - tray.letters[0] = Some(Letter{ + tray.letters[0] = Some(Letter { text: 'A', points: 1, ephemeral: false, @@ -992,50 +988,52 @@ mod tests { fn test_starting_move() { let mut board = Board::new(); - let difficulty = Difficulty{proportion: 0.1, randomness: 0.0}; + let difficulty = Difficulty { + proportion: 0.1, + randomness: 0.0, + }; let mut dictionary = DictionaryImpl::new(); dictionary.insert("TWEETED".to_string(), 0.2); - let mut tray = Tray::new(7); - tray.letters[0] = Some(Letter{ + tray.letters[0] = Some(Letter { text: 'I', points: 1, ephemeral: false, is_blank: false, }); - tray.letters[1] = Some(Letter{ + tray.letters[1] = Some(Letter { text: 'R', points: 1, ephemeral: false, is_blank: false, }); - tray.letters[2] = Some(Letter{ + tray.letters[2] = Some(Letter { text: 'W', points: 1, ephemeral: false, is_blank: false, }); - tray.letters[3] = Some(Letter{ + tray.letters[3] = Some(Letter { text: 'I', points: 1, ephemeral: false, is_blank: false, }); - tray.letters[4] = Some(Letter{ + tray.letters[4] = Some(Letter { text: 'T', points: 1, ephemeral: false, is_blank: false, }); - tray.letters[5] = Some(Letter{ + tray.letters[5] = Some(Letter { text: 'E', points: 1, ephemeral: false, is_blank: false, }); - tray.letters[6] = Some(Letter{ + tray.letters[6] = Some(Letter { text: 'D', points: 1, ephemeral: false, @@ -1048,7 +1046,5 @@ mod tests { println!("Available moves are {:?}", all_moves); assert!(all_moves.is_empty()); - } - -} \ No newline at end of file +}