diff --git a/compiler-core/src/expo/mod.rs b/compiler-core/src/expo/mod.rs index 08d9a008..148cb770 100644 --- a/compiler-core/src/expo/mod.rs +++ b/compiler-core/src/expo/mod.rs @@ -1,31 +1,76 @@ +//! # Export (expo) phase +//! +//! This phase collects export metadata from the plugins. The export metadata +//! is used to display export options to the user. +//! +//! # Input +//! The input is a [`ExecContext`]. +//! +//! # Output +//! The output is a [`ExpoContext`]. +use serde_json::Value; + use crate::exec::ExecContext; +use crate::macros::derive_wasm; + +/// Output of the export phase +#[derive_wasm] +pub struct ExpoContext<'p> { + #[serde(flatten)] + pub exec_ctx: ExecContext<'p>, + /// The export metadata + pub export_metadata: Vec, +} /// Data to define a plugin's export capability +#[derive(Debug, Clone)] +#[derive_wasm] pub struct ExportMetadata { - /// The id of the plugin. This is the same string in the `use` of the plugin + /// The id of the export plugin to run. This is the same string in the `use` of the plugin pub plugin_id: String, - /// The target of the exporter - pub target: ExportTarget, - /// Name of the export. For example "LiveSplit" + /// Name of the export. For example "LiveSplit". This is shown in the menu pub name: String, - /// File extension of the export. For example "lss" - pub extension: Option, /// Long description. This shows as a tooltip pub description: String, - // todo: icon + + /// (Optional) Icon to show next to the name + #[serde(default)] + pub icon: ExportIcon, + + /// (Optional) File extension of the export. For example "lss" + pub extension: Option, + + /// Extra properties to pass to the exporter when running + /// + /// This can be used to distinguish multiple exports from the same exporter. + /// This is not part of the config and cannot be changed by the user + pub properties: Value, + + /// (Optional) Example YAML configuration for the exporter to show to the user + pub example_config: Option, } -pub enum ExportTarget { - /// The exporter only runs for the CompDoc - CompDoc, - /// The exporter only runs for the ExecDoc - ExecDoc, - /// The exporter should run for both phases, - /// and produce the output in the ExecDoc phase - Both, +/// Icon for the export. +/// +/// This is only for visual. It does not restrict what the export can/cannot contain. +#[derive(Debug, Clone, Default)] +#[derive_wasm] +pub enum ExportIcon { + Archive, + Binary, + Cat, + Code, + Data, + #[default] + File, + Image, + Text, + Video, } /// The exported document type +#[derive(Debug, Clone)] +#[derive_wasm] pub struct ExpoDoc { /// The file name pub file_name: String, @@ -34,14 +79,16 @@ pub struct ExpoDoc { } impl<'p> ExecContext<'p> { - pub fn prepare_exports(&mut self) -> Vec { + pub fn prepare_exports(mut self) -> ExpoContext<'p> { let mut result = Vec::new(); for plugin in &mut self.plugin_runtimes { - // TODO #33: error handling if let Ok(Some(meta)) = plugin.on_prepare_export() { - result.push(meta); + result.extend(meta); } } - result + ExpoContext { + exec_ctx: self, + export_metadata: result, + } } } diff --git a/compiler-core/src/lib.rs b/compiler-core/src/lib.rs index 833c4874..b6db81f0 100644 --- a/compiler-core/src/lib.rs +++ b/compiler-core/src/lib.rs @@ -18,6 +18,7 @@ pub mod prep; // public API re-exports pub use comp::CompDoc; pub use exec::{ExecContext, ExecDoc}; +pub use expo::{ExpoContext, ExpoDoc}; pub use pack::{CompileContext, Compiler}; pub use prep::{ContextBuilder, PreparedContext}; diff --git a/compiler-core/src/plugin/builtin/livesplit.rs b/compiler-core/src/plugin/builtin/livesplit.rs new file mode 100644 index 00000000..acc61041 --- /dev/null +++ b/compiler-core/src/plugin/builtin/livesplit.rs @@ -0,0 +1,30 @@ +//! Exporter plugin for LiveSplit split files + +use std::borrow::Cow; + +use serde_json::json; + +use crate::expo::{ExportIcon, ExportMetadata}; + +use crate::plugin::{PluginResult, PluginRuntime}; + +pub struct ExportLiveSplitPlugin; + +impl PluginRuntime for ExportLiveSplitPlugin { + fn get_id(&self) -> Cow<'static, str> { + Cow::Owned(super::BuiltInPlugin::ExportLiveSplit.id()) + } + + fn on_prepare_export(&mut self) -> PluginResult>> { + let metadata = ExportMetadata { + plugin_id: self.get_id().into_owned(), + name: "LiveSplit".to_string(), + description: "Export to a LiveSplit split file".to_string(), + icon: ExportIcon::Data, + extension: Some("lss".to_string()), + properties: json!(null), + example_config: Some(include_str!("./livesplit.yaml").to_string()), + }; + Ok(Some(vec![metadata])) + } +} diff --git a/compiler-core/src/plugin/builtin/livesplit.yaml b/compiler-core/src/plugin/builtin/livesplit.yaml new file mode 100644 index 00000000..74af5f80 --- /dev/null +++ b/compiler-core/src/plugin/builtin/livesplit.yaml @@ -0,0 +1,13 @@ +# Do you want subsplits? +# -------- +# Subsplits are divided by sections in the route document +# Change below to `true` to enable subsplits +subsplits: false + +# Do you want icons? +# -------- +# Change below to `false` to disable icons +icons: true + +# Keep this as-is to use the splits configured in the settings +split-types: null diff --git a/compiler-core/src/plugin/builtin/mod.rs b/compiler-core/src/plugin/builtin/mod.rs index d6a38e57..4a1b312f 100644 --- a/compiler-core/src/plugin/builtin/mod.rs +++ b/compiler-core/src/plugin/builtin/mod.rs @@ -11,16 +11,19 @@ use super::{PluginResult, PluginRuntime}; mod botw_unstable; mod link; +mod livesplit; mod metrics; mod variables; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum BuiltInPlugin { - Metrics, + BotwAbilityUnstable, + #[serde(rename = "export-livesplit")] + ExportLiveSplit, Link, + Metrics, Variables, - BotwAbilityUnstable, } impl BuiltInPlugin { @@ -30,15 +33,16 @@ impl BuiltInPlugin { props: &Value, ) -> PluginResult> { match &self { + BuiltInPlugin::BotwAbilityUnstable => Ok(Box::new( + botw_unstable::BotwAbilityUnstablePlugin::from_props(props), + )), + BuiltInPlugin::ExportLiveSplit => Ok(Box::new(livesplit::ExportLiveSplitPlugin)), BuiltInPlugin::Link => Ok(Box::new(link::LinkPlugin)), BuiltInPlugin::Metrics => Ok(Box::new(metrics::MetricsPlugin::from_props( props, &ctx.start_time, ))), BuiltInPlugin::Variables => Ok(Box::new(variables::VariablesPlugin::from_props(props))), - BuiltInPlugin::BotwAbilityUnstable => Ok(Box::new( - botw_unstable::BotwAbilityUnstablePlugin::from_props(props), - )), } } diff --git a/compiler-core/src/plugin/error.rs b/compiler-core/src/plugin/error.rs index a4b2fe8b..601a8d29 100644 --- a/compiler-core/src/plugin/error.rs +++ b/compiler-core/src/plugin/error.rs @@ -7,8 +7,12 @@ use crate::lang::BaseError; pub enum PluginError { #[error("An exception occured while executing script: {0}")] ScriptException(String), + #[error("Extra plugin at `{0}` from plugin options is invalid: {1}")] InvalidAddPlugin(usize, String), + + #[error("The plugin `{0}` does not implement the required `{1}` method!")] + NotImplemented(String, String), } pub type PluginResult = Result; diff --git a/compiler-core/src/plugin/mod.rs b/compiler-core/src/plugin/mod.rs index 6953f2e6..7bb08fb0 100644 --- a/compiler-core/src/plugin/mod.rs +++ b/compiler-core/src/plugin/mod.rs @@ -56,24 +56,49 @@ pub trait PluginRuntime { fn on_before_compile(&mut self, _ctx: &mut CompileContext) -> PluginResult<()> { Ok(()) } + /// Called after the route is compiled, to transform the route fn on_after_compile(&mut self, _doc: &mut CompDoc) -> PluginResult<()> { Ok(()) } + /// Called after the route is turned into ExecDoc fn on_after_execute(&mut self, _doc: &mut ExecDoc) -> PluginResult<()> { Ok(()) } - fn on_prepare_export(&mut self) -> PluginResult> { + /// Called at the end of compilation to check what exports are available + fn on_prepare_export(&mut self) -> PluginResult>> { Ok(None) } - fn on_export_comp_doc(&mut self, _doc: &CompDoc) -> PluginResult> { + /// Called only in export workflow, to let the exporter access the CompDoc + /// + /// If the exporter needs to access the ExecDoc as well, it should return `None`. + /// Otherwise, the returned export data will be used and the exporter will not be called + /// with the ExecDoc + fn on_export_comp_doc( + &mut self, + _properties: &Value, + _payload: &Value, + _doc: &CompDoc, + ) -> PluginResult> { Ok(None) } - fn on_export_exec_doc(&mut self, _doc: &ExecDoc) -> PluginResult> { - Ok(None) + + /// Called only in export workflow, to let the exporter access the ExecDoc + /// + /// The exporter must return the export data or throw an error + fn on_export_exec_doc( + &mut self, + _properties: Value, + _payload: Value, + _doc: &ExecDoc, + ) -> PluginResult { + Err(PluginError::NotImplemented( + self.get_display_name().into_owned(), + "on_export_exec_doc".into(), + )) } } diff --git a/compiler-wasm/build/src/prelude.ts b/compiler-wasm/build/src/prelude.ts index 97bc513c..5a91b89c 100644 --- a/compiler-wasm/build/src/prelude.ts +++ b/compiler-wasm/build/src/prelude.ts @@ -2,4 +2,4 @@ import { callWorker } from "low/utils"; // serde_json::Value -export type Value = null | boolean | number | string | Value[] | { [key: string]: Value }; +export type Value = unknown; diff --git a/compiler-wasm/src/compile.rs b/compiler-wasm/src/compile.rs index 920bc1a3..1bdfb5d0 100644 --- a/compiler-wasm/src/compile.rs +++ b/compiler-wasm/src/compile.rs @@ -10,7 +10,7 @@ use celerc::{ CompDoc, CompileContext, Compiler, ContextBuilder, ExecContext, PluginOptions, PreparedContext, }; -use crate::interop::OpaqueExecContext; +use crate::interop::OpaqueExpoContext; use crate::loader::{self, LoadFileOutput, LoaderInWasm}; use crate::plugin; @@ -23,7 +23,7 @@ thread_local! { pub async fn compile_document( entry_path: Option, use_cache: bool, -) -> Result { +) -> Result { let plugin_options = match plugin::get_plugin_options() { Ok(x) => x, Err(message) => { @@ -31,7 +31,7 @@ pub async fn compile_document( error!("{message}"); let diagnostic = DocDiagnostic::error(&message, "web-editor"); let exec_ctx = ExecContext::from_diagnostic(diagnostic); - return OpaqueExecContext::try_from(exec_ctx); + return OpaqueExpoContext::try_from(exec_ctx.prepare_exports()); } }; @@ -58,8 +58,7 @@ pub async fn compile_document( Err(e) => { let comp_doc = CompDoc::from_prep_error(e, start_time); let exec_context = comp_doc.execute().await; - // TODO #33: exports - return OpaqueExecContext::try_from(exec_context); + return OpaqueExpoContext::try_from(exec_context.prepare_exports()); } }; @@ -100,7 +99,7 @@ async fn compile_in_context( prep_ctx: &PreparedContext, start_time: Option, plugin_options: Option, -) -> Result { +) -> Result { let mut comp_ctx = prep_ctx.new_compilation(start_time).await; match comp_ctx.configure_plugins(plugin_options).await { Err(e) => compile_with_pack_error(comp_ctx, e).await, @@ -114,16 +113,16 @@ async fn compile_in_context( async fn compile_with_pack_error( context: CompileContext<'_>, error: PackError, -) -> Result { +) -> Result { let comp_doc = CompDoc::from_diagnostic(error, context); let exec_ctx = comp_doc.execute().await; - OpaqueExecContext::try_from(exec_ctx) + OpaqueExpoContext::try_from(exec_ctx.prepare_exports()) } -async fn compile_with_compiler(compiler: Compiler<'_>) -> Result { +async fn compile_with_compiler(compiler: Compiler<'_>) -> Result { let comp_doc = compiler.compile().await; let exec_ctx = comp_doc.execute().await; - OpaqueExecContext::try_from(exec_ctx) + OpaqueExpoContext::try_from(exec_ctx.prepare_exports()) } /// Create a context builder that corresponds to the root project.yaml diff --git a/compiler-wasm/src/interop/opaque.rs b/compiler-wasm/src/interop/opaque.rs index 6df52aae..38e4e068 100644 --- a/compiler-wasm/src/interop/opaque.rs +++ b/compiler-wasm/src/interop/opaque.rs @@ -3,7 +3,7 @@ use wasm_bindgen::prelude::*; use celerc::macros::derive_opaque; -use celerc::ExecContext; +use celerc::ExpoContext; -#[derive_opaque(ExecContext)] -pub struct OpaqueExecContext<'p>; +#[derive_opaque(ExpoContext)] +pub struct OpaqueExpoContext<'p>; diff --git a/compiler-wasm/src/lib.rs b/compiler-wasm/src/lib.rs index 6f2e61db..dfec595a 100644 --- a/compiler-wasm/src/lib.rs +++ b/compiler-wasm/src/lib.rs @@ -8,7 +8,7 @@ use celerc::prep::EntryPointsSorted; use celerc::res::{ResPath, Resource}; mod interop; -use interop::OpaqueExecContext; +use interop::OpaqueExpoContext; mod compile; mod loader; use loader::LoaderInWasm; @@ -53,7 +53,7 @@ pub async fn get_entry_points() -> Result { pub async fn compile_document( entry_path: Option, use_cache: bool, -) -> Result { +) -> Result { compile::compile_document(entry_path, use_cache).await } diff --git a/docs/src/plugin/settings.md b/docs/src/plugin/settings.md index 3922212a..32b38709 100644 --- a/docs/src/plugin/settings.md +++ b/docs/src/plugin/settings.md @@ -23,7 +23,8 @@ First follow these steps to get to the user plugin settings: 1. Open the document you want to tweak. 2. Click on `Settings` on the toolbar. 3. Select the `Plugins` category. -4. You should see a text area under `User Plugins`. +4. Under `User Plugins`, click the `Edit Config` button. +5. You should see a dialog with a text area popped up. The syntax to configure user plugins is: ```yaml @@ -40,7 +41,7 @@ Replace: - `"Document Title"` with the exact title of the document you want to add the plugin to, surrounded by quotes. There is a little hint above the text area that tells you what the title of the current document is. You can also use the wildcard`"*"` to add the plugin to all documents. -- `my/plugin/file.js` with the path of the plugin. The plugin should be a file on GitHub, +- `my/extra/plugin1.js` with the path of the plugin. The plugin should be a file on GitHub, and you can reference it by `//path/to/file.js`. See [here](../route/file-structure.md) for more about the `use` property. However note that you cannot use a path to file on your computer. diff --git a/docs/src/toolbar.md b/docs/src/toolbar.md index a984a5d4..25449f47 100644 --- a/docs/src/toolbar.md +++ b/docs/src/toolbar.md @@ -14,6 +14,7 @@ These options are disabled until a document is loaded - `Jump to section`: Scroll the document to a particular section. - `View diagnostics`: Quickly jump to a line where there is an error, warning, or info message. +- `Export`: Export data from the document, such as split files. What's available depends on the export [plugin settings](./plugin/getting-started.md). ## Map Options :::tip diff --git a/web-client/.eslintrc.cjs b/web-client/.eslintrc.cjs index deb2fb03..b7f3f2b9 100644 --- a/web-client/.eslintrc.cjs +++ b/web-client/.eslintrc.cjs @@ -23,7 +23,8 @@ module.exports = { }, ignorePatterns: ["*.d.ts"], rules: { - "react-refresh/only-export-components": "warn", + // TODO #182: will address this later + "react-refresh/only-export-components": "off", "@typescript-eslint/no-unused-vars": [ "warn", { diff --git a/web-client/package-lock.json b/web-client/package-lock.json index 5ee91063..2953fc9f 100644 --- a/web-client/package-lock.json +++ b/web-client/package-lock.json @@ -21,10 +21,12 @@ "leaflet-rastercoords": "^1.0.5", "lru-cache": "^10.0.1", "monaco-editor": "^0.41.0", + "prismjs": "^1.29.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-grid-layout": "^1.3.4", "react-redux": "^8.1.0", + "react-simple-code-editor": "^0.13.1", "redux-watch": "^1.2.0" }, "devDependencies": { @@ -37,23 +39,24 @@ "@types/js-yaml": "^4.0.9", "@types/leaflet": "^1.9.3", "@types/leaflet-rastercoords": "^1.0.2", + "@types/prismjs": "^1.26.3", "@types/react": "^18.0.37", "@types/react-dom": "^18.0.11", "@types/react-grid-layout": "^1.3.2", "@types/redux-watch": "^1.1.0", - "@typescript-eslint/eslint-plugin": "^5.59.0", - "@typescript-eslint/parser": "^5.59.0", + "@typescript-eslint/eslint-plugin": "^6.20.0", + "@typescript-eslint/parser": "^6.20.0", "@vitejs/plugin-react": "^4.0.0", - "eslint": "^8.45.0", - "eslint-import-resolver-typescript": "^3.5.5", - "eslint-plugin-import": "^2.27.5", + "eslint": "^8.56.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.3.4", + "eslint-plugin-react-refresh": "^0.4.5", "identity-obj-proxy": "^3.0.0", "jest": "^29.6.1", "jest-environment-jsdom": "^29.6.1", "prettier": "^3.0.0", - "typescript": "5.0.4", + "typescript": "5.3.3", "vite": "^4.5.2", "vite-plugin-top-level-await": "^1.3.1", "vite-plugin-wasm": "^3.2.2", @@ -2364,18 +2367,18 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", - "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -2396,9 +2399,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2411,9 +2414,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", - "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3725,13 +3728,13 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -3752,9 +3755,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { @@ -4686,32 +4689,6 @@ "node": ">= 8" } }, - "node_modules/@pkgr/utils": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", - "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "fast-glob": "^3.3.0", - "is-glob": "^4.0.3", - "open": "^9.1.0", - "picocolors": "^1.0.0", - "tslib": "^2.6.0" - }, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@pkgr/utils/node_modules/tslib": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", - "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", - "dev": true - }, "node_modules/@reduxjs/toolkit": { "version": "1.9.5", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.5.tgz", @@ -5331,9 +5308,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/json5": { @@ -5372,6 +5349,12 @@ "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", "dev": true }, + "node_modules/@types/prismjs": { + "version": "1.26.3", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.3.tgz", + "integrity": "sha512-A0D0aTXvjlqJ5ZILMz3rNfDBOx9hHxLZYv2by47Sm/pqW35zzjusrZTryatjN/Rf8Us2gZrJD+KeHbUSTux1Cw==", + "dev": true + }, "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", @@ -5416,9 +5399,9 @@ "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" }, "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, "node_modules/@types/stack-utils": { @@ -5463,32 +5446,33 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.59.11", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.11.tgz", - "integrity": "sha512-XxuOfTkCUiOSyBWIvHlUraLw/JT/6Io1365RO6ZuI88STKMavJZPNMU0lFcUTeQXEhHiv64CbxYxBNoDVSmghg==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.20.0.tgz", + "integrity": "sha512-fTwGQUnjhoYHeSF6m5pWNkzmDDdsKELYrOBxhjMrofPqCkoC2k3B2wvGHFxa1CTIqkEn88nlW1HVMztjo2K8Hg==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.11", - "@typescript-eslint/type-utils": "5.59.11", - "@typescript-eslint/utils": "5.59.11", + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.20.0", + "@typescript-eslint/type-utils": "6.20.0", + "@typescript-eslint/utils": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0", "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -5497,25 +5481,26 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.59.11", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.11.tgz", - "integrity": "sha512-s9ZF3M+Nym6CAZEkJJeO2TFHHDsKAM3ecNkLuH4i4s8/RCPnF5JRip2GyviYkeEAcwGMJxkqG9h2dAsnA1nZpA==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.20.0.tgz", + "integrity": "sha512-bYerPDF/H5v6V76MdMYhjwmwgMA+jlPVqjSDq2cRqMi8bP5sR3Z+RLOiOMad3nsnmDVmn2gAFCyNgh/dIrfP/w==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.59.11", - "@typescript-eslint/types": "5.59.11", - "@typescript-eslint/typescript-estree": "5.59.11", + "@typescript-eslint/scope-manager": "6.20.0", + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/typescript-estree": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0", "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -5524,16 +5509,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.59.11", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.11.tgz", - "integrity": "sha512-dHFOsxoLFtrIcSj5h0QoBT/89hxQONwmn3FOQ0GOQcLOOXm+MIrS8zEAhs4tWl5MraxCY3ZJpaXQQdFMc2Tu+Q==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.20.0.tgz", + "integrity": "sha512-p4rvHQRDTI1tGGMDFQm+GtxP1ZHyAh64WANVoyEcNMpaTFn3ox/3CcgtIlELnRfKzSs/DwYlDccJEtr3O6qBvA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.11", - "@typescript-eslint/visitor-keys": "5.59.11" + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -5541,25 +5526,25 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.59.11", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.11.tgz", - "integrity": "sha512-LZqVY8hMiVRF2a7/swmkStMYSoXMFlzL6sXV6U/2gL5cwnLWQgLEG8tjWPpaE4rMIdZ6VKWwcffPlo1jPfk43g==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.20.0.tgz", + "integrity": "sha512-qnSobiJQb1F5JjN0YDRPHruQTrX7ICsmltXhkV536mp4idGAYrIyr47zF/JmkJtEcAVnIz4gUYJ7gOZa6SmN4g==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.59.11", - "@typescript-eslint/utils": "5.59.11", + "@typescript-eslint/typescript-estree": "6.20.0", + "@typescript-eslint/utils": "6.20.0", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -5568,12 +5553,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.59.11", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.11.tgz", - "integrity": "sha512-epoN6R6tkvBYSc+cllrz+c2sOFWkbisJZWkOE+y3xHtvYaOE6Wk6B8e114McRJwFRjGvYdJwLXQH5c9osME/AA==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.20.0.tgz", + "integrity": "sha512-MM9mfZMAhiN4cOEcUOEx+0HmuaW3WBfukBZPCfwSqFnQy0grXYtngKCqpQN339X3RrwtzspWJrpbrupKYUSBXQ==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -5581,21 +5566,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.59.11", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.11.tgz", - "integrity": "sha512-YupOpot5hJO0maupJXixi6l5ETdrITxeo5eBOeuV7RSKgYdU3G5cxO49/9WRnJq9EMrB7AuTSLH/bqOsXi7wPA==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.20.0.tgz", + "integrity": "sha512-RnRya9q5m6YYSpBN7IzKu9FmLcYtErkDkc8/dKv81I9QiLLtVBHrjz+Ev/crAqgMNW2FCsoZF4g2QUylMnJz+g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.11", - "@typescript-eslint/visitor-keys": "5.59.11", + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -5607,49 +5593,78 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/utils": { - "version": "5.59.11", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.11.tgz", - "integrity": "sha512-didu2rHSOMUdJThLk4aZ1Or8IcO3HzCw/ZvEjTTIfjIrcdd5cvSIwwDy2AOlE7htSNp7QIZ10fLMyRCveesMLg==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.20.0.tgz", + "integrity": "sha512-/EKuw+kRu2vAqCoDwDCBtDRU6CTKbUmwwI7SH7AashZ+W+7o8eiyy6V2cdOqN49KsTcASWsC5QeghYuRDTyOOg==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.11", - "@typescript-eslint/types": "5.59.11", - "@typescript-eslint/typescript-estree": "5.59.11", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.20.0", + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/typescript-estree": "6.20.0", + "semver": "^7.5.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.59.11", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.11.tgz", - "integrity": "sha512-KGYniTGG3AMTuKF9QBD7EIrvufkB6O6uX3knP73xbKLMpH+QRPcgnCxjWXSHjMRuOxFLovljqQgQpR0c7GvjoA==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.20.0.tgz", + "integrity": "sha512-E8Cp98kRe4gKHjJD4NExXKz/zOJ1A2hhZc+IMVD6i7w4yjIvh6VyuRI0gRtxAsXtoC35uGMaQ9rjI2zJaXDEAw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.11", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "6.20.0", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/@vitejs/plugin-react": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.0.tgz", @@ -5830,15 +5845,15 @@ } }, "node_modules/array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", "is-string": "^1.0.7" }, "engines": { @@ -5857,15 +5872,34 @@ "node": ">=8" } }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -5876,14 +5910,14 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -5893,6 +5927,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -5900,9 +5954,9 @@ "dev": true }, "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz", + "integrity": "sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==", "engines": { "node": ">= 0.4" }, @@ -6116,27 +6170,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "node_modules/big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/bplist-parser": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", - "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", - "dev": true, - "dependencies": { - "big-integer": "^1.6.44" - }, - "engines": { - "node": ">= 5.10.0" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -6206,28 +6239,14 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/bundle-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", - "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", - "dev": true, - "dependencies": { - "run-applescript": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6549,160 +6568,17 @@ "node": ">=0.10.0" } }, - "node_modules/default-browser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", - "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", - "dev": true, - "dependencies": { - "bundle-name": "^3.0.0", - "default-browser-id": "^3.0.0", - "execa": "^7.1.1", - "titleize": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", - "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", - "dev": true, - "dependencies": { - "bplist-parser": "^0.2.0", - "untildify": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/execa": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", - "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/default-browser/node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", - "dev": true, - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/default-browser/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "engines": { - "node": ">=12" + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.4" } }, "node_modules/define-properties": { @@ -6865,24 +6741,25 @@ } }, "node_modules/es-abstract": { - "version": "1.21.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.3.tgz", - "integrity": "sha512-ZU4miiY1j3sGPFLJ34VJXEqhpmL+HGByCinGHv4HC+Fxl2fI2Z4yR6tl0mORnDr6PA8eihWo4LmSWDbvhALckg==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", "dependencies": { "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.5", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", - "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", + "hasown": "^2.0.0", "internal-slot": "^1.0.5", "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", @@ -6890,20 +6767,23 @@ "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", + "is-typed-array": "^1.1.12", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", "typed-array-byte-offset": "^1.0.0", "typed-array-length": "^1.0.4", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.10" + "which-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -6912,6 +6792,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-errors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.0.0.tgz", + "integrity": "sha512-yHV74THqMJUyFKkHyN7hyENcEZM3Dj2a2IrdClY+IT4BFQHkIVwlh8s6uZfjsFydMdNHv0F5mWgAA3ajFbsvVQ==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-get-iterator": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", @@ -6945,12 +6833,12 @@ } }, "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" } }, "node_modules/es-to-primitive": { @@ -7045,37 +6933,29 @@ "source-map": "~0.6.1" } }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/eslint": { - "version": "8.45.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz", - "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.1.0", - "@eslint/js": "8.44.0", - "@humanwhocodes/config-array": "^0.11.10", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.6.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -7109,14 +6989,14 @@ } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", - "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, "dependencies": { "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -7129,19 +7009,18 @@ } }, "node_modules/eslint-import-resolver-typescript": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.5.tgz", - "integrity": "sha512-TdJqPHs2lW5J9Zpe17DZNQuDnox4xo2o+0tE7Pggain9Rbc19ik8kFtXdxZ250FVx2kF4vlt2RSf4qlUpG7bhw==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", "dev": true, "dependencies": { "debug": "^4.3.4", "enhanced-resolve": "^5.12.0", "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", "get-tsconfig": "^4.5.0", - "globby": "^13.1.3", "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "synckit": "^0.8.5" + "is-glob": "^4.0.3" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -7154,37 +7033,6 @@ "eslint-plugin-import": "*" } }, - "node_modules/eslint-import-resolver-typescript/node_modules/globby": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", - "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", - "dev": true, - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.3.0", - "ignore": "^5.2.4", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-import-resolver-typescript/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint-module-utils": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", @@ -7212,26 +7060,28 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.27.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", - "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", "dev": true, "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", - "has": "^1.0.3", - "is-core-module": "^2.11.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" @@ -7283,31 +7133,34 @@ } }, "node_modules/eslint-plugin-react-refresh": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.3.5.tgz", - "integrity": "sha512-61qNIsc7fo9Pp/mju0J83kzvLm0Bsayu7OQSLEoJxLDCBjIIyb87bkzufoOvdDxLkSlMfkF7UxomC4+eztUBSA==", + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.5.tgz", + "integrity": "sha512-D53FYKJa+fDmZMtriODxvhwrO+IOqrxoEo21gMA0sjHdU6dPVH4OhyFip9ypl8HOF5RV5KdTo+rBQLvnY2cO8w==", "dev": true, "peerDependencies": { "eslint": ">=7" } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -7377,31 +7230,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/eslint/node_modules/globals": { "version": "13.20.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", @@ -7480,15 +7308,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -7501,7 +7320,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -7510,15 +7329,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -7584,9 +7394,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -7743,19 +7553,22 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" }, "engines": { "node": ">= 0.4" @@ -7791,14 +7604,18 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.3.tgz", + "integrity": "sha512-JIcZczvcMVE7AUOP+X72bh8HqHBRxFdz5PDHYtNG/lE3yk9b3KZBJlwFcTyPYjg3L4RLLmZJzvjxhaZVapxFrQ==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "es-errors": "^1.0.0", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7950,12 +7767,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -7997,11 +7808,11 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", "dependencies": { - "get-intrinsic": "^1.1.1" + "get-intrinsic": "^1.2.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8030,17 +7841,28 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", "dependencies": { - "has-symbols": "^1.0.2" + "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/hoist-non-react-statics": { @@ -8326,12 +8148,12 @@ } }, "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8351,21 +8173,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-equal": { "version": "1.6.4", "resolved": "https://registry.npmjs.org/is-equal/-/is-equal-1.6.4.tgz", @@ -8464,24 +8271,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", @@ -8614,15 +8403,11 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "which-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -8662,33 +8447,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-wsl/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -10196,18 +9954,6 @@ "node": ">=8" } }, - "node_modules/jest-snapshot/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/jest-snapshot/node_modules/pretty-format": { "version": "29.6.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.1.tgz", @@ -10240,21 +9986,6 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, - "node_modules/jest-snapshot/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==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/jest-snapshot/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -10267,12 +9998,6 @@ "node": ">=8" } }, - "node_modules/jest-snapshot/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/jest-util": { "version": "29.6.1", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.1.tgz", @@ -11016,12 +10741,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -11070,9 +10789,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -11139,6 +10858,23 @@ "node": ">= 0.4" } }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object.getprototypeof": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/object.getprototypeof/-/object.getprototypeof-1.0.4.tgz", @@ -11156,15 +10892,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object.groupby": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1" + } + }, "node_modules/object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" @@ -11197,24 +10945,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/open": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", - "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", - "dev": true, - "dependencies": { - "default-browser": "^4.0.0", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -11530,6 +11260,14 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -11743,6 +11481,15 @@ "react": ">= 16.3" } }, + "node_modules/react-simple-code-editor": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/react-simple-code-editor/-/react-simple-code-editor-0.13.1.tgz", + "integrity": "sha512-XYeVwRZwgyKtjNIYcAEgg2FaQcCZwhbarnkJIV20U2wkCU9q/CPFBo8nRXrK4GXUz3AvbqZFsZRrpUTkqqEYyQ==", + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -11847,13 +11594,13 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" + "set-function-name": "^2.0.0" }, "engines": { "node": ">= 0.4" @@ -11921,12 +11668,12 @@ "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" }, "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -12034,21 +11781,6 @@ "@babel/runtime": "^7.1.2" } }, - "node_modules/run-applescript": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", - "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -12072,6 +11804,23 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-array-concat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", + "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "dependencies": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-regex-test": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", @@ -12114,9 +11863,9 @@ } }, "node_modules/semver": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", - "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -12146,6 +11895,34 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/set-function-length": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", + "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "dependencies": { + "define-data-property": "^1.1.1", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.2", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -12295,13 +12072,13 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" @@ -12311,26 +12088,26 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12425,28 +12202,6 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "node_modules/synckit": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", - "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", - "dev": true, - "dependencies": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/synckit/node_modules/tslib": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", - "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", - "dev": true - }, "node_modules/tabster": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/tabster/-/tabster-5.3.0.tgz", @@ -12522,18 +12277,6 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/titleize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", - "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -12588,6 +12331,18 @@ "node": ">=12" } }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/tsconfck": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-2.1.1.tgz", @@ -12609,9 +12364,9 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", @@ -12641,27 +12396,6 @@ "node": ">=4" } }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -12695,6 +12429,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typed-array-byte-offset": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", @@ -12727,16 +12491,16 @@ } }, "node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=12.20" + "node": ">=14.17" } }, "node_modules/unbox-primitive": { @@ -12802,15 +12566,6 @@ "node": ">= 4.0.0" } }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/update-browserslist-db": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", @@ -13167,16 +12922,15 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.10.tgz", - "integrity": "sha512-uxoA5vLUfRPdjCuJ1h5LlYdmTLbYfums398v3WLkM+i/Wltl2/XyZpQWKbN++ck5L64SR/grOHqtXCUKmlZPNA==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", + "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.6", + "call-bind": "^1.0.5", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" + "has-tostringtag": "^1.0.1" }, "engines": { "node": ">= 0.4" diff --git a/web-client/package.json b/web-client/package.json index 6bfcae6a..771e85ac 100644 --- a/web-client/package.json +++ b/web-client/package.json @@ -17,10 +17,12 @@ "leaflet-rastercoords": "^1.0.5", "lru-cache": "^10.0.1", "monaco-editor": "^0.41.0", + "prismjs": "^1.29.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-grid-layout": "^1.3.4", "react-redux": "^8.1.0", + "react-simple-code-editor": "^0.13.1", "redux-watch": "^1.2.0" }, "devDependencies": { @@ -33,23 +35,24 @@ "@types/js-yaml": "^4.0.9", "@types/leaflet": "^1.9.3", "@types/leaflet-rastercoords": "^1.0.2", + "@types/prismjs": "^1.26.3", "@types/react": "^18.0.37", "@types/react-dom": "^18.0.11", "@types/react-grid-layout": "^1.3.2", "@types/redux-watch": "^1.1.0", - "@typescript-eslint/eslint-plugin": "^5.59.0", - "@typescript-eslint/parser": "^5.59.0", + "@typescript-eslint/eslint-plugin": "^6.20.0", + "@typescript-eslint/parser": "^6.20.0", "@vitejs/plugin-react": "^4.0.0", - "eslint": "^8.45.0", - "eslint-import-resolver-typescript": "^3.5.5", - "eslint-plugin-import": "^2.27.5", + "eslint": "^8.56.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.3.4", + "eslint-plugin-react-refresh": "^0.4.5", "identity-obj-proxy": "^3.0.0", "jest": "^29.6.1", "jest-environment-jsdom": "^29.6.1", "prettier": "^3.0.0", - "typescript": "5.0.4", + "typescript": "5.3.3", "vite": "^4.5.2", "vite-plugin-top-level-await": "^1.3.1", "vite-plugin-wasm": "^3.2.2", diff --git a/web-client/src/core/doc/docReducers.ts b/web-client/src/core/doc/docReducers.ts index 6bf397af..70cf58ec 100644 --- a/web-client/src/core/doc/docReducers.ts +++ b/web-client/src/core/doc/docReducers.ts @@ -1,15 +1,15 @@ //! Reducers for the document state -import { ExecContext } from "low/celerc"; +import { ExpoContext } from "low/celerc"; import { withPayload } from "low/store"; import { DocumentState } from "./state"; -/// Set the document +/// Set the document from compiler output /// /// Also automatically increment the serial number so that /// the application re-renders the document and does necessary updates -export const setDocument = withPayload( +export const setDocument = withPayload( (state, value) => { if (value) { state.serial += 1; @@ -18,5 +18,6 @@ export const setDocument = withPayload( } state.document = value?.execDoc; state.pluginMetadata = value?.pluginMetadata; + state.exportMetadata = value?.exportMetadata; }, ); diff --git a/web-client/src/core/doc/state.ts b/web-client/src/core/doc/state.ts index b03f3050..d1a87a96 100644 --- a/web-client/src/core/doc/state.ts +++ b/web-client/src/core/doc/state.ts @@ -1,6 +1,6 @@ //! Document view, setting, and route document state -import { ExecDoc, PluginMetadata } from "low/celerc"; +import { ExecDoc, ExportMetadata, PluginMetadata } from "low/celerc"; /// View state for the document export type DocViewState = { @@ -97,6 +97,8 @@ export type DocumentState = { document: ExecDoc | undefined; /// The current document's plugin metadata pluginMetadata: PluginMetadata[] | undefined; + /// The current document's export options + exportMetadata: ExportMetadata[] | undefined; }; /// The initial document state @@ -104,4 +106,5 @@ export const initialDocumentState: DocumentState = { serial: 0, document: undefined, pluginMetadata: undefined, + exportMetadata: undefined, }; diff --git a/web-client/src/core/doc/utils.ts b/web-client/src/core/doc/utils.ts index a8034c10..a610b276 100644 --- a/web-client/src/core/doc/utils.ts +++ b/web-client/src/core/doc/utils.ts @@ -230,15 +230,7 @@ export const getRawPluginOptions = ( : []; const add = []; if (enabledAppPlugins["export-split"]) { - // TODO #33: export splits - // add.push({ use: "export-livesplit" }); - // add.push({ - // use: "export-livesplit", - // "allow-duplicate": true, - // with: { - // subsplits: true, - // } - // }); + add.push({ use: "export-livesplit" }); } if (enableUserPlugins) { const [result] = parseUserConfigOptions(userPluginConfig, document); diff --git a/web-client/src/core/kernel/AlertMgr.ts b/web-client/src/core/kernel/AlertMgr.ts new file mode 100644 index 00000000..648e1151 --- /dev/null +++ b/web-client/src/core/kernel/AlertMgr.ts @@ -0,0 +1,145 @@ +//! Manager for modal alerts + +import { AlertExtraAction, ModifyAlertActionPayload } from "core/stage"; +import { AppDispatcher, viewActions } from "core/store"; + +/// Options for showing a simple alert +export type AlertOptions = { + /// Title of the alert + title: string; + /// Message body of the alert + message: string; + /// Text for the ok button. Default is "Ok" + okButton?: string; + /// Text for the cancel button. Default is no cancel button. + cancelButton?: string; + /// Show a learn more link after the message + learnMoreLink?: string; + /// Extra actions besides ok and cancel + extraActions?: TExtra; +}; + +/// Options for showing a rich (react) alert +export type RichAlertOptions = { + /// Title of the alert + title: string; + /// Body component of the alert + component: React.ComponentType; + /// Text for the ok button. Default is "Ok" + okButton?: string; + /// Text for the cancel button. Default is "Cancel" + cancelButton?: string; + /// Extra actions besides ok and cancel + extraActions?: TExtra; +}; + +type IdsOf = T[number]["id"]; +type AlertCallback = (ok: boolean | string) => void; + +/// Timeout needed to clear the previous alert +const ALERT_TIMEOUT = 100; + +export class AlertMgr { + private store: AppDispatcher; + private previousFocusedElement: Element | undefined = undefined; + private alertCallback: AlertCallback | undefined = undefined; + private RichAlertComponent: React.ComponentType | undefined = undefined; + + constructor(store: AppDispatcher) { + this.store = store; + } + + /// Show an alert dialog + /// + /// Returns a promise that resolves to true if the user + /// clicked ok and false if the user clicked cancel. + /// + /// If there are extra options, it may resolve to the id of the extra action + public show({ + title, + message, + okButton, + cancelButton, + learnMoreLink, + extraActions, + }: AlertOptions): Promise> { + return new Promise((resolve) => { + this.initAlert(resolve, undefined); + this.store.dispatch( + viewActions.setAlert({ + title, + text: message, + okButton: okButton ?? "Ok", + cancelButton: cancelButton ?? "Cancel", + learnMore: learnMoreLink ?? "", + extraActions: extraActions ?? [], + }), + ); + }); + } + + /// Like `show`, but with a custom react component for the body + public showRich({ + title, + component, + okButton, + cancelButton, + extraActions, + }: RichAlertOptions): Promise> { + return new Promise((resolve) => { + this.initAlert(resolve, component); + this.store.dispatch( + viewActions.setAlert({ + title, + text: "", + okButton: okButton ?? "Ok", + cancelButton: cancelButton ?? "", + learnMore: "", + extraActions: extraActions ?? [], + }), + ); + }); + } + + /// Modify the current alert's actions + /// + /// Only effective if a dialog is showing + public modifyActions(payload: ModifyAlertActionPayload) { + if (this.alertCallback) { + this.store.dispatch(viewActions.setAlertActions(payload)); + } + } + + private initAlert( + resolve: AlertCallback, + component: React.ComponentType | undefined, + ) { + this.previousFocusedElement = document.activeElement ?? undefined; + this.alertCallback = (response) => { + this.store.dispatch(viewActions.clearAlert()); + this.alertCallback = undefined; + this.RichAlertComponent = undefined; + setTimeout(() => { + const element = this.previousFocusedElement; + if ( + element && + "focus" in element && + typeof element.focus === "function" + ) { + element.focus(); + } + resolve(response); + }, ALERT_TIMEOUT); + }; + this.RichAlertComponent = component; + } + + /// Called from the alert dialog to notify the user action + public onAction(response: boolean | string) { + this.alertCallback?.(response); + } + + public getRichComponent() { + return this.RichAlertComponent; + } +} diff --git a/web-client/src/core/kernel/Kernel.ts b/web-client/src/core/kernel/Kernel.ts index 3f9b3c66..b4cfc1b3 100644 --- a/web-client/src/core/kernel/Kernel.ts +++ b/web-client/src/core/kernel/Kernel.ts @@ -20,6 +20,7 @@ import type { CompilerKernel } from "./compiler"; import type { EditorKernel } from "./editor"; import { KeyMgr } from "./KeyMgr"; import { WindowMgr } from "./WindowMgr"; +import { AlertMgr } from "./AlertMgr"; type InitUiFunction = ( kernel: Kernel, @@ -48,7 +49,7 @@ export class Kernel { private cleanupUi: (() => void) | null = null; // Alert API - private alertCallback: ((ok: boolean) => void) | undefined = undefined; + private alertMgr: AlertMgr; // Editor API // The editor is owned by the kernel because the toolbar needs access @@ -62,6 +63,7 @@ export class Kernel { this.initReact = initReact; this.log.info("starting application"); this.store = this.initStore(); + this.alertMgr = new AlertMgr(this.store); } /// Initialize the store @@ -179,48 +181,8 @@ export class Kernel { this.themeLinkTag.href = `/themes/${theme}.min.css`; } - /// Show an alert dialog - /// - /// Returns a promise that resolves to true if the user - /// clicked ok and false if the user clicked cancel. - public showAlert( - title: string, - message: string, - okButton: string, - cancelButton: string, - learnMore?: string, - ): Promise { - return new Promise((resolve) => { - // Run new alert asynchronously so that the previous alert has time to disappear first - setTimeout(() => { - this.alertCallback = (ok) => { - this.store?.dispatch(viewActions.clearAlert()); - resolve(ok); - this.alertCallback = undefined; - }; - const store = this.store; - if (!store) { - console.error("store not initialized"); - resolve(false); - return; - } - store.dispatch( - viewActions.setAlert({ - title, - text: message, - learnMore: learnMore || "", - okButton, - cancelButton, - }), - ); - }, 50); - }); - } - - public onAlertAction(ok: boolean) { - if (this.alertCallback) { - this.alertCallback(ok); - } + public getAlertMgr(): AlertMgr { + return this.alertMgr; } public getEditor(): EditorKernel | null { @@ -255,27 +217,25 @@ export class Kernel { return; } if (code === FsResultCodes.NotSupported) { - await this.showAlert( - "Not Supported", - "Your browser does not support this feature.", - "Close", - "", - "/docs/route/editor/web#browser-os-support", - ); + await this.getAlertMgr().show({ + title: "Not Supported", + message: "Your browser does not support this feature.", + okButton: "Close", + learnMoreLink: "/docs/route/editor/web#browser-os-support", + }); } else if (code === FsResultCodes.IsFile) { - await this.showAlert( - "Error", - "You dropped a file. Make sure you are dropping the project folder and not individual files.", - "Close", - "", - ); + await this.getAlertMgr().show({ + title: "Error", + message: + "You dropped a file. Make sure you are dropping the project folder and not individual files.", + okButton: "Close", + }); } else { - await this.showAlert( - "Error", - `Cannot open the project. Make sure you have access to the folder or contact support. (Error code ${code}}`, - "Close", - "", - ); + await this.getAlertMgr().show({ + title: "Error", + message: `Cannot open the project. Make sure you have access to the folder or contact support. (Error code ${code}}`, + okButton: "Close", + }); } return; } @@ -286,19 +246,20 @@ export class Kernel { let retry = false; const code = result.inner(); if (code === FsResultCodes.PermissionDenied) { - retry = await this.showAlert( - "Permission Denied", - "You must given file system access permission to the app to use this feature. Please try again and grant the permission when prompted.", - "Grant Permission", - "Cancel", - ); + retry = await this.getAlertMgr().show({ + title: "Permission Denied", + message: + "You must given file system access permission to the app to use this feature. Please try again and grant the permission when prompted.", + okButton: "Grant Permission", + cancelButton: "Cancel", + }); } else { - retry = await this.showAlert( - "Error", - `Failed to initialize the project. Please try again. (Error code ${code})`, - "Retry", - "Cancel", - ); + retry = await this.getAlertMgr().show({ + title: "Error", + message: `Failed to initialize the project. Please try again. (Error code ${code})`, + okButton: "Retry", + cancelButton: "Cancel", + }); } if (!retry) { return; @@ -310,13 +271,14 @@ export class Kernel { if (editorMode === "web") { // must be able to save to use web editor if (!fileSys.isWritable()) { - const yes = await this.showAlert( - "Save not supported", - "The web editor cannot be used because your browser does not support saving changes to the file system. If you wish to edit the project, you can use the External Editor workflow and have Celer load changes directly from your file system.", - "Use external editor", - "Cancel", - "/docs/route/editor/web#browser-os-support", - ); + const yes = await this.getAlertMgr().show({ + title: "Save not supported", + message: + "The web editor cannot be used because your browser does not support saving changes to the file system. If you wish to edit the project, you can use the External Editor workflow and have Celer load changes directly from your file system.", + okButton: "Use external editor", + cancelButton: "Cancel", + learnMoreLink: "/docs/route/editor/web#browser-os-support", + }); if (!yes) { return; } @@ -326,13 +288,14 @@ export class Kernel { } if (fileSys.isStale()) { - const yes = await this.showAlert( - "Heads up!", - "Your browser has limited support for file system access when opening a project from a dialog. Certain operations may not work! Please see the learn more link below for more information.", - "Continue anyway", - "Cancel", - "/docs/route/editor/external#open-a-project", - ); + const yes = await this.getAlertMgr().show({ + title: "Heads up!", + message: + "Your browser has limited support for file system access when opening a project from a dialog. Certain operations may not work! Please see the learn more link below for more information.", + okButton: "Continue anyway", + cancelButton: "Cancel", + learnMoreLink: "/docs/route/editor/external#open-a-project", + }); if (!yes) { return; } diff --git a/web-client/src/core/kernel/compiler/CompilerKernelImpl.ts b/web-client/src/core/kernel/compiler/CompilerKernelImpl.ts index 204c52ef..54292d32 100644 --- a/web-client/src/core/kernel/compiler/CompilerKernelImpl.ts +++ b/web-client/src/core/kernel/compiler/CompilerKernelImpl.ts @@ -144,6 +144,10 @@ export class CompilerKernelImpl implements CompilerKernel { public async compile() { // setting the needCompile flag to ensure this request is handled eventually this.needCompile = true; + if (!this.fileAccess) { + CompilerLog.warn("file access not available, skipping compile"); + return; + } if (!(await this.ensureReady())) { CompilerLog.warn( diff --git a/web-client/src/core/kernel/index.ts b/web-client/src/core/kernel/index.ts index 1ff1b240..dc34bc3a 100644 --- a/web-client/src/core/kernel/index.ts +++ b/web-client/src/core/kernel/index.ts @@ -4,5 +4,6 @@ //! the react ui, redux store, file system, and others export * from "./Kernel"; +export * from "./AlertMgr"; export * from "./context"; export type { EditorKernel } from "./editor"; diff --git a/web-client/src/core/stage/state.ts b/web-client/src/core/stage/state.ts index 43826c4e..22d69754 100644 --- a/web-client/src/core/stage/state.ts +++ b/web-client/src/core/stage/state.ts @@ -8,9 +8,19 @@ export type StageViewState = { alertLearnMoreLink: string; alertOkButton: string; alertCancelButton: string; + alertExtraActions: AlertExtraAction[]; settingsTab: SettingsTab; isResizingWindow: boolean; }; +export type AlertExtraAction = { + id: string; + text: string; +}; +export type ModifyAlertActionPayload = { + okButton?: string; + cancelButton?: string; + extraActions?: AlertExtraAction[]; +}; export type StageMode = "view" | "edit"; @@ -23,6 +33,7 @@ export const initialStageViewState: StageViewState = { alertLearnMoreLink: "", alertOkButton: "", alertCancelButton: "", + alertExtraActions: [], settingsTab: "doc", isResizingWindow: false, }; diff --git a/web-client/src/core/stage/viewReducers.ts b/web-client/src/core/stage/viewReducers.ts index 3591bada..38cab86a 100644 --- a/web-client/src/core/stage/viewReducers.ts +++ b/web-client/src/core/stage/viewReducers.ts @@ -2,7 +2,13 @@ import { ReducerDecl, withPayload } from "low/store"; -import { SettingsTab, StageMode, StageViewState } from "./state"; +import { + AlertExtraAction, + ModifyAlertActionPayload, + SettingsTab, + StageMode, + StageViewState, +} from "./state"; export const setStageMode = withPayload( (state, mode) => { @@ -22,18 +28,38 @@ export type AlertPayload = { learnMore: string; okButton: string; cancelButton: string; + extraActions: AlertExtraAction[]; }; export const setAlert = withPayload( - (state, { title, text, learnMore: link, okButton, cancelButton }) => { + ( + state, + { title, text, learnMore: link, okButton, cancelButton, extraActions }, + ) => { state.alertTitle = title; state.alertText = text; state.alertLearnMoreLink = link; state.alertOkButton = okButton; state.alertCancelButton = cancelButton; + state.alertExtraActions = extraActions; }, ); +export const setAlertActions = withPayload< + StageViewState, + ModifyAlertActionPayload +>((state, { okButton, cancelButton, extraActions }) => { + if (okButton !== undefined) { + state.alertOkButton = okButton; + } + if (cancelButton !== undefined) { + state.alertCancelButton = cancelButton; + } + if (extraActions !== undefined) { + state.alertExtraActions = extraActions; + } +}); + export const clearAlert: ReducerDecl = (state) => { state.alertText = ""; state.alertOkButton = ""; diff --git a/web-client/src/low/fs/FileSystemAccessApiFileSys.ts b/web-client/src/low/fs/FileSystemAccessApiFileSys.ts index 12febe89..c6b6b08c 100644 --- a/web-client/src/low/fs/FileSystemAccessApiFileSys.ts +++ b/web-client/src/low/fs/FileSystemAccessApiFileSys.ts @@ -25,7 +25,6 @@ export const isFileSystemAccessApiSupported = (): boolean => { return false; } - // @ts-expect-error FileSystemFileHandle should have a createWritable() method if (!window.FileSystemFileHandle.prototype.createWritable) { return false; } @@ -162,10 +161,7 @@ export class FileSystemAccessApiFileSys implements FileSys { return result; } try { - // @ts-expect-error FileSystemWritableFileStream is not in tslib - const file: FileSystemWritableFileStream = - // @ts-expect-error FileSystemFileHandle should have a createWritable() method - await result.inner().createWritable(); + const file = await result.inner().createWritable(); await file.write(content); await file.close(); return result.makeOk(undefined); diff --git a/web-client/src/low/utils/Debouncer.ts b/web-client/src/low/utils/Debouncer.ts index 1c1736c0..e665414d 100644 --- a/web-client/src/low/utils/Debouncer.ts +++ b/web-client/src/low/utils/Debouncer.ts @@ -78,7 +78,7 @@ export const useDebouncer = (delay: number) => { } handle.current = window.setTimeout(fn, delay); }, - [delay, handle], + [delay], ); return dispatch; diff --git a/web-client/src/low/utils/html.ts b/web-client/src/low/utils/html.ts index 876bdc8d..60a8cfa9 100644 --- a/web-client/src/low/utils/html.ts +++ b/web-client/src/low/utils/html.ts @@ -1,5 +1,7 @@ //! Basic utilities for working in browser environments. +import clsx from "clsx"; + export const isInDarkMode = () => !!( window.matchMedia && @@ -20,7 +22,8 @@ export class DOMId { } public get(): E | undefined { - return document.getElementById(this.id) as E | undefined; + const element = document.getElementById(this.id) || undefined; + return element as E | undefined; } public style(style: Record) { @@ -82,13 +85,19 @@ function addCssObjectToMap( } /// Accessor for DOM Class -export class DOMClass { - readonly className: string; - constructor(className: string) { +export class DOMClass { + readonly className: N; + constructor(className: N) { this.className = className; } - public style(style: Record) { + /// Get the combined class name from the given Griffel style map + public styledClassName(style: Record) { + return clsx(this.className, style[this.className]); + } + + /// Inject a raw css map into the head that targets this class + public injectStyle(style: Record) { const map = {}; addCssObjectToMap(`.${this.className}`, style, map); const css = Object.entries(map) @@ -99,11 +108,14 @@ export class DOMClass { new DOMStyleInject(`${this.className}-styles`).setStyle(css); } - public query(selector?: string) { - return document.querySelector(`.${this.className}${selector || ""}`); + public query(selector?: string): E | undefined { + const element = + document.querySelector(`.${this.className}${selector || ""}`) || + undefined; + return element as E | undefined; } - public queryAll(selector?: string) { + public queryAll(selector?: string): NodeListOf { return document.querySelectorAll(`.${this.className}${selector || ""}`); } } diff --git a/web-client/src/ui/app/AppAlert.css b/web-client/src/ui/app/AppAlert.css deleted file mode 100644 index 030947fa..00000000 --- a/web-client/src/ui/app/AppAlert.css +++ /dev/null @@ -1,3 +0,0 @@ -div.alert-link { - margin-top: 10px; -} diff --git a/web-client/src/ui/app/AppAlert.tsx b/web-client/src/ui/app/AppAlert.tsx index 6e4c0077..ea20d3f2 100644 --- a/web-client/src/ui/app/AppAlert.tsx +++ b/web-client/src/ui/app/AppAlert.tsx @@ -1,5 +1,4 @@ //! Global alert component -import "./AppAlert.css"; import { useRef } from "react"; import { useSelector } from "react-redux"; import { @@ -17,6 +16,7 @@ import { import { useKernel } from "core/kernel"; import { viewSelector } from "core/store"; +import { sleep } from "low/utils"; export const AppAlert: React.FC = () => { const { @@ -25,10 +25,12 @@ export const AppAlert: React.FC = () => { alertLearnMoreLink, alertOkButton, alertCancelButton, + alertExtraActions, } = useSelector(viewSelector); - const kernel = useKernel(); - const okRef = useRef(null); - if (!alertText) { + const alertMgr = useKernel().getAlertMgr(); + const responseRef = useRef(false); + const RichAlertComponent = alertMgr.getRichComponent(); + if (!alertText && !RichAlertComponent) { return null; } @@ -36,10 +38,11 @@ export const AppAlert: React.FC = () => { { + onOpenChange={async (_, data) => { if (!data.open) { - const ok = ev.target === okRef.current; - kernel.onAlertAction(ok); + // doing this async just in case + await sleep(0); + alertMgr.onAction(responseRef.current); } }} > @@ -47,28 +50,59 @@ export const AppAlert: React.FC = () => { {alertTitle} - {alertText} - {alertLearnMoreLink && ( -
- - Learn more - -
+ {RichAlertComponent ? ( + + ) : ( + <> + {alertText} + {alertLearnMoreLink && ( +
+ + Learn more + +
+ )} + )}
- + 0}> - {alertCancelButton && ( - )} + {alertExtraActions.map((action, i) => ( + + + + ))}
diff --git a/web-client/src/ui/doc/DocDiagnosticBlock.tsx b/web-client/src/ui/doc/DocDiagnosticBlock.tsx index 41d46b70..9608fea5 100644 --- a/web-client/src/ui/doc/DocDiagnosticBlock.tsx +++ b/web-client/src/ui/doc/DocDiagnosticBlock.tsx @@ -1,7 +1,7 @@ //! The diagnostic text block import clsx from "clsx"; -import { Text } from "@fluentui/react-components"; +import { Text, makeStyles, shorthands } from "@fluentui/react-components"; import { DocDiagnostic } from "low/celerc"; import { DOMClass } from "low/utils"; @@ -18,13 +18,15 @@ export type DocDiagnosticBlockProps = { const PREFIX = "docline-diagnostic"; const DocDiagnosticHeadClass = new DOMClass(`${PREFIX}-head`); -DocDiagnosticHeadClass.style({ - padding: "4px 4px 0 4px", -}); const DocDiagnosticBodyClass = new DOMClass(`${PREFIX}-body`); -DocDiagnosticBodyClass.style({ - padding: "4px 0 4px 4px", - "word-break": "break-word", +const useStyles = makeStyles({ + [DocDiagnosticHeadClass.className]: { + ...shorthands.padding("4px 4px 0 4px"), + }, + [DocDiagnosticBodyClass.className]: { + ...shorthands.padding("4px 0 4px 4px"), + wordBreak: "break-word", + }, }); export const DocDiagnosticBlock: React.FC = ({ @@ -32,11 +34,12 @@ export const DocDiagnosticBlock: React.FC = ({ showCaret, }) => { const { msg, source, type } = diagnostic; + const styles = useStyles(); return (
@@ -47,7 +50,7 @@ export const DocDiagnosticBlock: React.FC = ({
diff --git a/web-client/src/ui/doc/DocSection.tsx b/web-client/src/ui/doc/DocSection.tsx index 62b1288c..2483540a 100644 --- a/web-client/src/ui/doc/DocSection.tsx +++ b/web-client/src/ui/doc/DocSection.tsx @@ -4,6 +4,7 @@ import { Text } from "@fluentui/react-components"; import { SectionBannerWidthClass } from "./updateBannerWidths"; import { DocSectionHead } from "./utils"; +import { useDocStyles } from "./styles"; /// Component for one section in the document type DocSectionProps = { @@ -18,11 +19,12 @@ export const DocSection: React.FC> = ({ index, children, }) => { + const styles = useDocStyles(); return (
diff --git a/web-client/src/ui/doc/styles.ts b/web-client/src/ui/doc/styles.ts new file mode 100644 index 00000000..8eabde62 --- /dev/null +++ b/web-client/src/ui/doc/styles.ts @@ -0,0 +1,12 @@ +import { makeStyles, shorthands } from "@fluentui/react-components"; +import { DocSectionHead } from "./utils"; + +export const useDocStyles = makeStyles({ + [DocSectionHead.className]: { + boxSizing: "border-box", + ...shorthands.padding("16px 0px 16px 64px"), + "& span": { + wordWrap: "break-word", + }, + }, +}); diff --git a/web-client/src/ui/doc/updateBannerWidths.ts b/web-client/src/ui/doc/updateBannerWidths.ts index 1b38ef71..8bf6fd86 100644 --- a/web-client/src/ui/doc/updateBannerWidths.ts +++ b/web-client/src/ui/doc/updateBannerWidths.ts @@ -1,6 +1,7 @@ //! Logic for updating the width of banners upon updates -import { DocContainer, DocLog, getInjectedStyleTag } from "./utils"; +import { DOMStyleInject } from "low/utils"; +import { DocContainer, DocLog } from "./utils"; export const SectionBannerWidthClass = "section-banner-width-injected"; export const BannerWidthClass = "banner-width-injected"; @@ -8,6 +9,8 @@ export const BannerTextWidthClass = "banner-text-width-injected"; export const BannerTextWithIconWidthClass = "banner-text-width-with-icon-injected"; +const BannerWidthStyles = new DOMStyleInject("banner-width"); + export const updateBannerWidths = (): void => { const container = DocContainer.get(); if (!container) { @@ -17,13 +20,12 @@ export const updateBannerWidths = (): void => { const bannerWidth = containerWidth - 64; // subtract the header const textWidth = bannerWidth - 4; // subtract the padding - const styleTag = getInjectedStyleTag("banner-width"); let style = `.${SectionBannerWidthClass}{width:${containerWidth}px !important;}`; style += `.${BannerWidthClass}{width:${bannerWidth}px !important;}`; style += `.${BannerTextWidthClass}{width:${textWidth}px !important;}`; style += `.${BannerTextWithIconWidthClass}{width:${ textWidth - 50 }px !important;}`; - styleTag.innerHTML = style; + BannerWidthStyles.setStyle(style); DocLog.info("banner width css updated."); }; diff --git a/web-client/src/ui/doc/utils.ts b/web-client/src/ui/doc/utils.ts index bdede84c..821ec388 100644 --- a/web-client/src/ui/doc/utils.ts +++ b/web-client/src/ui/doc/utils.ts @@ -1,7 +1,7 @@ //! Utilities import { DocTagColor, DocTag } from "low/celerc"; -import { DOMClass, DOMId, Logger } from "low/utils"; +import { DOMClass, DOMId, DOMStyleInject, Logger } from "low/utils"; export const DocLog = new Logger("doc"); @@ -22,13 +22,6 @@ export const DocLineContainerClass = "docline-container"; /// Class for the section heads (title) in the document export const DocSectionHead = new DOMClass("docsection-head"); -DocSectionHead.style({ - "box-sizing": "border-box", - padding: "16px 0px 16px 64px", - " span": { - "word-wrap": "break-word", - }, -}); /// Scroll view type export type ScrollView = { @@ -126,10 +119,11 @@ export const getLineScrollView = ( export const RichTextClassName = "rich-text"; +const RichTextStyles = new DOMStyleInject("rich-text"); + /// Update the styles/classes for rich tags export const updateDocTagsStyle = (tags: Readonly>) => { - const styleTag = getInjectedStyleTag("rich-text"); - styleTag.innerText = Object.entries(tags) + const css = Object.entries(tags) .map(([tag, data]) => { let css = `.${getTagClassName(tag)}{`; if (data.bold) { @@ -157,26 +151,10 @@ export const updateDocTagsStyle = (tags: Readonly>) => { return css + "}"; }) .join(""); + RichTextStyles.setStyle(css); DocLog.info("rich text css updated."); }; -/// Get or inject a style tag with the id. The id sets the "data-inject" attribute -export const getInjectedStyleTag = (id: string): HTMLStyleElement => { - let styleTag = document.querySelector(`style[data-inject="${id}"`); - if (!styleTag) { - DocLog.info(`creating injected ${id} tag...`); - styleTag = document.createElement("style"); - styleTag.setAttribute("data-inject", id); - const head = document.querySelector("head"); - if (!head) { - DocLog.error("cannot find `head`"); - } else { - head.appendChild(styleTag); - } - } - return styleTag as HTMLStyleElement; -}; - const createCssStringForColor = (color: DocTagColor, type: "fg" | "bg") => { if (typeof color === "string") { return `--rich-text-${type}-light:${color};--rich-text-${type}-dark:${color};`; diff --git a/web-client/src/ui/editor/EditorDropZone.tsx b/web-client/src/ui/editor/EditorDropZone.tsx index d7f3c8d9..e2184ebe 100644 --- a/web-client/src/ui/editor/EditorDropZone.tsx +++ b/web-client/src/ui/editor/EditorDropZone.tsx @@ -38,12 +38,12 @@ export const EditorDropZone: React.FC = () => { const item = e.dataTransfer?.items[0]; if (!item) { - kernel.showAlert( - "Error", - "Cannot open the project. Make sure you are dropping the correct folder and try again.", - "Close", - "", - ); + await kernel.getAlertMgr().show({ + title: "Error", + message: + "Cannot open the project. Make sure you are dropping the correct folder and try again.", + okButton: "Close", + }); return; } const fileSysResult = await createFsFromDataTransferItem(item); diff --git a/web-client/src/ui/shared/ErrorBar.tsx b/web-client/src/ui/shared/ErrorBar.tsx index e1b0b3a2..1fef9195 100644 --- a/web-client/src/ui/shared/ErrorBar.tsx +++ b/web-client/src/ui/shared/ErrorBar.tsx @@ -5,13 +5,14 @@ import { MessageBar, MessageBarBody, MessageBarTitle, + makeStyles, } from "@fluentui/react-components"; -import { DOMClass } from "low/utils"; -const ErrorBarClass = new DOMClass("error-bar"); -ErrorBarClass.style({ - "font-family": "monospace", - "white-space": "pre-wrap", +const useErrorBarStyles = makeStyles({ + root: { + fontFamily: "monospace", + whiteSpace: "pre-wrap", + }, }); type ErrorBarProps = { @@ -36,19 +37,20 @@ export const ErrorBar: React.FC> = ({ }; export const FormattedError: React.FC<{ error: unknown }> = ({ error }) => { + const styles = useErrorBarStyles(); if (typeof error !== "string" || !error) { return null; } const lines = error.split("\n").map((line, i) => { if (!line) { return ( -
+
 
); } return ( -
+
{line || ""}
); diff --git a/web-client/src/ui/shared/PrismEditor/PrismEditorCore.tsx b/web-client/src/ui/shared/PrismEditor/PrismEditorCore.tsx new file mode 100644 index 00000000..491c06ec --- /dev/null +++ b/web-client/src/ui/shared/PrismEditor/PrismEditorCore.tsx @@ -0,0 +1,83 @@ +import { makeStyles, shorthands } from "@fluentui/react-components"; +import ReactSimpleCodeEditor from "react-simple-code-editor"; +import { highlight, languages } from "prismjs"; + +// load languages +/* eslint-disable import/no-internal-modules */ +import "prismjs/components/prism-yaml"; +/* eslint-enable import/no-internal-modules */ + +import { console, isInDarkMode } from "low/utils"; + +import { PrismEditorProps } from "./types"; + +console.info("loading prism editor"); + +function initStyles() { + const dark = isInDarkMode(); + if (dark) { + // eslint-disable-next-line import/no-internal-modules + import("prismjs/themes/prism-okaidia.css"); + } else { + // eslint-disable-next-line import/no-internal-modules + import("prismjs/themes/prism.css"); + } + return makeStyles({ + inner: { + maxHeight: "300px", + minHeight: "100px", + overflowY: "auto", + "& *": { + minHeight: "100px", + fontFamily: "monospace", + fontSize: "12px", + }, + "& textarea": { + ...shorthands.outline("initial", "none"), + }, + }, + outer: { + ...shorthands.margin("10px", "0"), + ...shorthands.border("1px", "solid", "#888"), + ...shorthands.borderRadius("4px"), + ...shorthands.padding("4px"), + ":focus-within": { + ...shorthands.outline("1px", "solid", dark ? "white" : "black"), + }, + backgroundColor: dark ? "#111" : "#eee", + }, + }); +} +const useStyles = initStyles(); + +const PrismEditorCore: React.FC = ({ + language, + value, + setValue, +}) => { + const styles = useStyles(); + return ( +
+
+ setValue(code)} + highlight={(code) => + highlight(code, languages[language], language) + } + padding={4} + onKeyDown={(e) => { + // prevent dialog from closing if the editor is + // inside a dialog + if (e.key === "Escape") { + e.preventDefault(); + e.currentTarget.blur(); + } + }} + /> +
+
+ ); +}; + +export default PrismEditorCore; diff --git a/web-client/src/ui/shared/PrismEditor/index.tsx b/web-client/src/ui/shared/PrismEditor/index.tsx new file mode 100644 index 00000000..ad14ee7c --- /dev/null +++ b/web-client/src/ui/shared/PrismEditor/index.tsx @@ -0,0 +1,15 @@ +//! An editor that uses PrismJS for syntax highlighting +import React, { Suspense } from "react"; +import { Spinner } from "@fluentui/react-components"; + +import { PrismEditorProps } from "./types"; + +const PrismEditorCore = React.lazy(() => import("./PrismEditorCore")); + +export const PrismEditor: React.FC = (props) => { + return ( + }> + + + ); +}; diff --git a/web-client/src/ui/shared/PrismEditor/types.ts b/web-client/src/ui/shared/PrismEditor/types.ts new file mode 100644 index 00000000..81abc999 --- /dev/null +++ b/web-client/src/ui/shared/PrismEditor/types.ts @@ -0,0 +1,15 @@ +/// Props for the PrismEditor +/// +/// This is defined separately because the editor is lazy-loaded +export type PrismEditorProps = { + language: PrismEditorLanguage; + value: string; + setValue: (value: string) => void; +}; + +export type PrismEditorLanguage = + | "markup" + | "css" + | "clike" + | "javascript" + | "yaml"; diff --git a/web-client/src/ui/shared/index.ts b/web-client/src/ui/shared/index.ts index a0952e89..6c7c9360 100644 --- a/web-client/src/ui/shared/index.ts +++ b/web-client/src/ui/shared/index.ts @@ -7,4 +7,5 @@ export * from "./ErrorScreen"; export * from "./ErrorBoundary"; export * from "./HintScreen"; export * from "./LoadScreen"; +export * from "./PrismEditor"; export * from "./useWindowSize"; diff --git a/web-client/src/ui/toolbar/Export.tsx b/web-client/src/ui/toolbar/Export.tsx new file mode 100644 index 00000000..3d7e25bc --- /dev/null +++ b/web-client/src/ui/toolbar/Export.tsx @@ -0,0 +1,159 @@ +//! Control for selecting export options + +import { forwardRef } from "react"; +import { useSelector } from "react-redux"; +import { + Menu, + MenuItem, + MenuList, + MenuPopover, + MenuTrigger, + ToolbarButton, + Tooltip, +} from "@fluentui/react-components"; +import { + AnimalCat20Regular, + ArrowDownload20Regular, + Box20Regular, + Code20Regular, + Document20Regular, + DocumentChevronDouble20Regular, + FolderZip20Regular, + Image20Regular, + Video20Regular, +} from "@fluentui/react-icons"; + +import { documentSelector } from "core/store"; +import { ExecDoc, ExportIcon, ExportMetadata } from "low/celerc"; + +import { ControlComponentProps, ToolbarControl } from "./util"; + +export const Export: ToolbarControl = { + ToolbarButton: forwardRef((_, ref) => { + const { enabled, tooltip, exportMetadata } = useExportControl(); + return ( + + + } + disabled={!enabled} + /> + + + ); + }), + MenuItem: () => { + const { enabled, exportMetadata } = useExportControl(); + return ( + + } disabled={!enabled}> + Export + + + ); + }, +}; + +const useExportControl = () => { + const { document, exportMetadata } = useSelector(documentSelector); + const enabled = + document !== undefined && + exportMetadata !== undefined && + exportMetadata.length > 0; + return { + enabled, + exportMetadata, + tooltip: getTooltip(document, exportMetadata), + }; +}; + +const getTooltip = ( + document: ExecDoc | undefined, + exportMetadata: ExportMetadata[] | undefined, +) => { + if (!document) { + return "No document loaded to export"; + } + if (!exportMetadata || !exportMetadata.length) { + return "This document has no export options"; + } + return "Export this document"; +}; + +type ExportInternalProps = ControlComponentProps & { + exportMetadata: ExportMetadata[] | undefined; +}; + +const ExportInternal: React.FC = ({ + children, + exportMetadata, +}) => { + return ( + + {children} + + + {exportMetadata?.map((metadata, i) => ( + + ))} + + + + ); +}; + +const ExportButton: React.FC<{ metadata: ExportMetadata }> = ({ metadata }) => { + const text = metadata.extension + ? `${metadata.name} (*.${metadata.extension})` + : metadata.name; + return ( + + }> + {text} + + + ); +}; + +const ExportIconComponent: React.FC<{ name: ExportIcon | undefined }> = ({ + name, +}) => { + switch (name) { + case "archive": + return ; + case "binary": + return ; + case "cat": + return ; + case "code": + return ; + case "data": + return ; + case "file": + return ; + case "image": + return ; + case "video": + return ; + default: + return ; + } +}; + +// type ExportDialogProps = { +// /// All available export options +// exportMetadata: ExportMetadata[]; +// /// Currently selected export option +// selectedMetadata: ExportMetadata; +// setSelectedMetadata: (metadata: ExportMetadata) => void; +// } +// const ExportDialog: React.FC<{metadata: ExportMetadata}> = ({metadata}) => { +// return ( +// <> +// ); +// } diff --git a/web-client/src/ui/toolbar/OpenCloseProject.tsx b/web-client/src/ui/toolbar/OpenCloseProject.tsx index e03716ff..5554c84c 100644 --- a/web-client/src/ui/toolbar/OpenCloseProject.tsx +++ b/web-client/src/ui/toolbar/OpenCloseProject.tsx @@ -46,12 +46,13 @@ const useOpenCloseProjectControl = () => { } if (await editor.hasUnsavedChanges()) { - const yes = await kernel.showAlert( - "Unsaved changes", - "There are unsaved changes in the editor. Continue closing will discard all changes. Are you sure you want to continue?", - "Discard changes", - "Cancel", - ); + const yes = await kernel.getAlertMgr().show({ + title: "Unsaved changes", + message: + "There are unsaved changes in the editor. Continue closing will discard all changes. Are you sure you want to continue?", + okButton: "Discard changes", + cancelButton: "Cancel", + }); if (!yes) { return; } diff --git a/web-client/src/ui/toolbar/SaveProject.tsx b/web-client/src/ui/toolbar/SaveProject.tsx index 0163656a..4d6d2081 100644 --- a/web-client/src/ui/toolbar/SaveProject.tsx +++ b/web-client/src/ui/toolbar/SaveProject.tsx @@ -83,12 +83,12 @@ const useSaveProjectControl = () => { editor.notifyActivity(); const result = await editor.saveChangesToFs(); if (result.isErr()) { - await kernel.showAlert( - "Error", - "Fail to save changes to file system. Please try again.", - "Close", - "", - ); + await kernel.getAlertMgr().show({ + title: "Error", + message: + "Fail to save changes to file system. Please try again.", + okButton: "Close", + }); } }, [kernel]); diff --git a/web-client/src/ui/toolbar/SyncProject.tsx b/web-client/src/ui/toolbar/SyncProject.tsx index 868716bf..8662d503 100644 --- a/web-client/src/ui/toolbar/SyncProject.tsx +++ b/web-client/src/ui/toolbar/SyncProject.tsx @@ -70,12 +70,12 @@ const useSyncProjectControl = () => { // failure could be due to project structure change. try again const result2 = await editor.loadChangesFromFs(); if (result2.isErr()) { - await kernel.showAlert( - "Error", - "Fail to load changes from file system. Please try again.", - "Close", - "", - ); + await kernel.getAlertMgr().show({ + title: "Error", + message: + "Fail to load changes from file system. Please try again.", + okButton: "Close", + }); } } incFileSysSerial(); diff --git a/web-client/src/ui/toolbar/getHeaderControls.ts b/web-client/src/ui/toolbar/getHeaderControls.ts index 0431f496..d670414e 100644 --- a/web-client/src/ui/toolbar/getHeaderControls.ts +++ b/web-client/src/ui/toolbar/getHeaderControls.ts @@ -14,6 +14,7 @@ import { SyncProject } from "./SyncProject"; import { SaveProject } from "./SaveProject"; import { CompileProject } from "./CompileProject"; import { OpenDocs } from "./OpenDocs"; +import { Export } from "./Export"; /// Header controls. /// @@ -32,7 +33,7 @@ export const getHeaderControls = ( // Doc Controls { priority: 40, - controls: [SelectSection, ViewDiagnostics], + controls: [SelectSection, ViewDiagnostics, Export], }, // Map Controls { diff --git a/web-client/src/ui/toolbar/settings/PluginSettings.tsx b/web-client/src/ui/toolbar/settings/PluginSettings.tsx index 9a4d596f..bab282ff 100644 --- a/web-client/src/ui/toolbar/settings/PluginSettings.tsx +++ b/web-client/src/ui/toolbar/settings/PluginSettings.tsx @@ -1,6 +1,6 @@ //! Plugin tab of the settings dialog -import { useEffect, useState, useTransition } from "react"; +import { useState } from "react"; import { useSelector } from "react-redux"; import { Body1, @@ -9,11 +9,12 @@ import { CheckboxProps, Field, Link, + MessageBar, + MessageBarBody, Switch, - Textarea, } from "@fluentui/react-components"; -import { ErrorBar } from "ui/shared"; +import { ErrorBar, PrismEditor } from "ui/shared"; import { documentSelector, settingsActions, @@ -24,30 +25,15 @@ import { parseUserConfigOptions, useDocDisabledPlugins, } from "core/doc"; +import { Kernel, useKernel } from "core/kernel"; import { useActions } from "low/store"; -import { PluginMetadata } from "low/celerc"; -import { DOMId, useDebouncer } from "low/utils"; +import { ExecDoc, PluginMetadata } from "low/celerc"; +import { console } from "low/utils"; import { SettingsSection } from "./SettingsSection"; -const UserPluginConfigTextarea = new DOMId("user-plugin-config-textarea"); -UserPluginConfigTextarea.style({ - "font-family": "monospace", - "font-size": "12px", -}); -const adjustUserPluginConfigTextareaHeight = () => { - const element = UserPluginConfigTextarea.get(); - if (!element) { - return; - } - // shrink it - element.style.height = "32px"; - const height = Math.max(32, Math.min(element.scrollHeight, 300)); - element.style.height = `${height}px`; -}; - export const PluginSettings: React.FC = () => { - const { pluginMetadata, document, serial } = useSelector(documentSelector); + const { pluginMetadata, document } = useSelector(documentSelector); // cache the plugin metadata once the dialog shows up // so the UI doesn't jump around when the plugin metadata changes const [cachedPluginMetadata, setCachedPluginMetadata] = @@ -58,22 +44,8 @@ export const PluginSettings: React.FC = () => { useActions(settingsActions); const disabledPlugins = useDocDisabledPlugins(); - const [userPluginSyntaxError, setUserPluginSyntaxError] = useState< - string | undefined - >(undefined); - const [configText, setConfigText] = useState(userPluginConfig); - const dispatchDebouncer = useDebouncer(2000); - const [_, startTransition] = useTransition(); + const kernel = useKernel(); - useEffect(adjustUserPluginConfigTextareaHeight, []); - /* eslint-disable react-hooks/exhaustive-deps*/ - useEffect(() => { - startTransition(() => { - const [_, error] = parseUserConfigOptions(configText, document); - setUserPluginSyntaxError(error); - }); - }, [configText, serial]); - /* eslint-enable react-hooks/exhaustive-deps*/ return ( <> @@ -83,8 +55,7 @@ export const PluginSettings: React.FC = () => { @@ -142,14 +113,6 @@ export const PluginSettings: React.FC = () => { ? `The current document title is "${document.project.title}"` : undefined } - validationState={ - userPluginSyntaxError ? "error" : "success" - } - validationMessage={ - userPluginSyntaxError - ? "There is a syntax error with your configuration" - : "Configuration syntax is valid" - } > { /> -