diff --git a/.config/nextest.toml b/.config/nextest.toml new file mode 100644 index 00000000..f9fd128a --- /dev/null +++ b/.config/nextest.toml @@ -0,0 +1,40 @@ +# The CodeChat Editor, a word processor for software developers.
Copyright +# (C) 2024-2026 Bryan A. Jones. +# +# This file is part of the CodeChat Editor. +# +# The CodeChat Editor is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# The CodeChat Editor is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# the CodeChat Editor. If not, see +# [http://www.gnu.org/licenses](http://www.gnu.org/licenses). +# +# `nextest.toml` -- a cargo-nextest configuration file +# ==================================================== +# +# See the [docs](https://nexte.st/docs/configuration/) for this file. nextest +# reads it only from `.config/` in the workspace root. +# +# Browser-backed tests +# -------------------- +# +# The `overall` test binary (`server/tests/overall.rs`, which gathers the +# `overall_*.rs` modules) drives a browser through WebDriver. Overlapping +# WebDriver sessions are unreliable on macOS CI, so run these tests one at a +# time. nextest runs each test in its own process; a +# [test group](https://nexte.st/docs/configuration/test-groups/) limits how many +# of those processes run at once, while other tests still run in parallel. +[test-groups] +web-driver = { max-threads = 1 } + +[[profile.default.overrides]] +filter = "binary_id(codechat-editor-server::overall)" +test-group = "web-driver" diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 8ca65126..14e15d7e 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -58,5 +58,4 @@ jobs: - name: Run tests run: | rustup update - # ./bt install && ./bt full diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7f013f1e..c4e0ccf9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -64,7 +64,7 @@ jobs: # we specify bash to get pipefail; it guards against the `curl` command # failing. otherwise `sh` won't catch that `curl` returned non-0 shell: bash - run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.33.1/cargo-dist-installer.sh | sh" + run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.34.0/cargo-dist-installer.sh | sh" - name: Cache dist uses: actions/upload-artifact@v7 with: diff --git a/AGENTS.md b/AGENTS.md index 30d0f453..22c6a28b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -61,10 +61,10 @@ project: 1. Assign a unique id for that section: `

section title

` for a level-3 section; in a code file, this must be placed in a - doc block. Any HTML element with an id can be the target of either a - hyperlink or a cross-reference. -2. Refer to it using a hyperlink or cross-reference. For example, the following - syntax links directly to this section's heading: `[Foo](#cc-sZ0Glsgjhu)` + doc block. Any HTML element with an id can be the target of a + cross-reference. +2. Refer to it using a cross-reference. For example, the following syntax links + directly to this section's heading: `Foo` (link text is "Foo") / `` (link text comes from the cross-referenced span: "Cross-references, gather elements, and fragments"); the same syntax (a bare id with no file) also links to any file @@ -73,7 +73,7 @@ project: When implementing a specification: 1. Label each doc block preceding non-contiguous section of code of more than - three lines with a fragment placed at the end of the doc block: ``. 2. Gather these fragments in a subheading following the specification: `

Cross-references

-Any HTML element with an id can be the target of either a hyperlink or a -cross-reference. If the id resides in a file within a [project](#cc-DscjSxRZHF), -then any file in that same project can refer to that id using a hyperlink or -cross-reference. For example: +Any HTML element with an id can be the target of a cross-reference. If the id +resides in a file within a [project](#cc-DscjSxRZHF), then any file in that same +project can refer to that id using a cross-reference. For example: -| Source | Rendered | -| ----------------------------------- | --------------------------------- | -| `[Style guide](#cc-nNZ6Gs2uWD)` | [Style guide](#cc-nNZ6Gs2uWD) | -| `` | | +| Source | Rendered | +| ---------------------------------------------- | --------------------------------- | +| `Style guide` | Style guide | +| `` | | In projects, each id must be unique throughout the entire project. To simplify the creation of unique ids, items assigned an `id="*"` with be replaced with a -unique id, such as `id=cc-DscjSxRZHF`. This autogenerated id isn't automatically -saved; you must make an edit to its containing file in the Client to save the -resulting id. +unique id, such as `id="cc-DscjSxRZHF"`. This autogenerated id isn't +automatically saved; you must make an edit to its containing file in the Client +to save the resulting id.

Gathering fragments

@@ -285,8 +284,7 @@ participant explicitly opts in. See the [capture token setup guide](capture-token-setup-guide.html) for more information. -Supported languages ---------------------------------------------------- +

Supported languages

* C/C++ * C# @@ -338,8 +336,7 @@ You should have received a [copy](LICENSE.html) of the GNU General Public License along with the CodeChat Editor. If not, see [https://www.gnu.org/licenses/](https://www.gnu.org/licenses/). -Notes ------------------------ +

Notes

1. The image used comes from [Monitor icons created by prettycons - Flaticon](https://www.flaticon.com/free-icons/monitor "monitor icons"). diff --git a/builder/Cargo.lock b/builder/Cargo.lock index 2a60e7a2..b560bf37 100644 --- a/builder/Cargo.lock +++ b/builder/Cargo.lock @@ -87,6 +87,7 @@ dependencies = [ "cmd_lib", "current_platform", "dunce", + "env_logger", "path-slash", "regex", ] @@ -128,7 +129,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -173,37 +174,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a74858bcfe44b22016cb49337d7b6f04618c58e5dbfdef61b06b8c434324a0bc" -[[package]] -name = "defmt" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a0795ac740cb54d7b3775c9c17345f6aaecf884c01733b39d6017738e0e3e1" -dependencies = [ - "bitflags", - "defmt-macros", -] - -[[package]] -name = "defmt-macros" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "840bb056bd99c495c9188198a258ab787c79f306d864db3e6e8451442d6d8366" -dependencies = [ - "defmt-parser", - "proc-macro2", - "quote", - "syn 3.0.9", -] - -[[package]] -name = "defmt-parser" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71958f69fb2de856c5dd51ac9377e986ca1aa5919f931bf5395a807277f889a0" -dependencies = [ - "thiserror", -] - [[package]] name = "dunce" version = "1.0.5" @@ -258,11 +228,10 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "jiff" -version = "0.2.38" +version = "0.2.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b005715dcbeb0089a3c0dab99f2ff1cc3b2525323552703d648585d342a383" +checksum = "fefca06093eeaed707a905795e68206da0edca4edef23d2a3997a3ddbee462aa" dependencies = [ - "defmt", "jiff-core", "jiff-static", "log", @@ -273,19 +242,18 @@ dependencies = [ [[package]] name = "jiff-core" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c" +checksum = "77a24020db0ee88d1c681d677681bd31f9f4ea189a455425223d52ce4f1508aa" dependencies = [ - "defmt", "log", ] [[package]] name = "jiff-static" -version = "0.2.38" +version = "0.2.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc9817253cf7c7ee4684451bd327e88d6f3658014e54a29198625590650695c" +checksum = "41d3213549742662eea1a18e6c5af9be5dfbabeb7611ab71356a54928ec398f0" dependencies = [ "jiff-core", "proc-macro2", @@ -440,7 +408,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -462,9 +430,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.9" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +checksum = "4ae9ccbea3a7b0b09443036490c8f34a8b1b760fd345e5c0dae0aac718faea79" dependencies = [ "proc-macro2", "quote", @@ -488,7 +456,7 @@ checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] diff --git a/builder/Cargo.toml b/builder/Cargo.toml index 51071137..6aa020ac 100644 --- a/builder/Cargo.toml +++ b/builder/Cargo.toml @@ -42,6 +42,7 @@ clap = { version = "4", features = ["derive"] } cmd_lib = "2.0.0" current_platform = "0.2.0" dunce = "1.0.5" +env_logger = "0.11.11" path-slash = "0.2.1" regex = "1.11.1" diff --git a/builder/src/main.rs b/builder/src/main.rs index d579fe8c..b212989b 100644 --- a/builder/src/main.rs +++ b/builder/src/main.rs @@ -144,7 +144,7 @@ static WORKSPACE_MANIFEST_PATH: &str = "../Cargo.toml"; // second, explicit pass over it. static BUILDER_PATH: &str = "../builder"; static NAPI_TARGET: &str = "NAPI_TARGET"; -static DIST_VERSION: &str = "0.33.1"; +static DIST_VERSION: &str = "0.34.0"; // Code // ---- @@ -386,9 +386,7 @@ fn run_install(cargo_dist: bool) -> io::Result<()> { patch_client_libs()?; run_script("pnpm", &["install"], VSCODE_PATH, true)?; run_cmd!( - info "cargo fetch"; cargo fetch; - info "Builder: cargo fetch"; cargo fetch --manifest-path=$BUILDER_PATH/Cargo.toml; )?; // Install the cargo binstall binary, taken from the @@ -398,9 +396,9 @@ fn run_install(cargo_dist: bool) -> io::Result<()> { pwsh -Command "Set-ExecutionPolicy Unrestricted -Scope Process; iex (iwr 'https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.ps1').Content"; }?; #[cfg(not(windows))] - // The original command had `'=https'`, but single quotes confused - // `cmd_lib` and aren't needed to quote this. Note that `//` in the URL - // is a comment in Rust, so it must be + // The original command had `'=https'`, but single quotes confused `cmd_lib` + // and aren't needed to quote this. Note that `//` in the URL is a comment + // in Rust, so it must be // [enclosed in quotes](https://github.com/rust-shell-script/rust_cmd_lib/issues/88). run_cmd! { curl -L --proto =https --tlsv1.2 -sSf "https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh" | bash; @@ -416,25 +414,14 @@ fn run_install(cargo_dist: bool) -> io::Result<()> { )?; #[cfg(not(target_os = "macos"))] run_cmd!( - info "cargo binstall cargo-dist"; cargo binstall cargo-dist@${DIST_VERSION} --no-confirm; )?; } run_cmd!( - info "cargo binstall cargo-outdated"; - cargo binstall cargo-outdated --no-confirm; - info "cargo binstall cargo-sort"; - cargo binstall cargo-sort --no-confirm; - info "cargo binstall cargo-audit"; - cargo binstall cargo-audit --no-confirm; - info "cargo binstall cargo-machete"; - cargo binstall cargo-machete --no-confirm; - info "cargo binstall cargo-llvm-cov"; - cargo binstall cargo-llvm-cov --no-confirm; + cargo binstall cargo-audit cargo-llvm-cov cargo-machete cargo-nextest cargo-outdated cargo-sort --no-confirm; // Install the required llvm-tools component used by cargo-llvm-cov // without prompting. - info "rustup component add llvm-tools-preview"; rustup component add llvm-tools-preview; ) } @@ -444,16 +431,13 @@ fn run_update() -> io::Result<()> { patch_client_libs()?; run_script("pnpm", &["update"], VSCODE_PATH, true)?; run_cmd!( - info "cargo update"; cargo update; - info "Builder: cargo update"; cargo update --manifest-path=$BUILDER_PATH/Cargo.toml; )?; // Simply display outdated dependencies, but don't consider them an error. run_script("pnpm", &["outdated"], CLIENT_PATH, false)?; run_script("pnpm", &["outdated"], VSCODE_PATH, false)?; run_cmd!( - info "cargo outdated"; cargo outdated --workspace; )?; // `cargo outdated` 0.19.0 joins a relative `--manifest-path` onto the @@ -489,21 +473,15 @@ fn run_format_and_lint(check_only: bool) -> io::Result<()> { // the workspace root cargo would discover, so from `server/` it checks only // `server/Cargo.toml`. Passing `..` aims it at the workspace root instead. run_cmd!( - info "cargo clippy and fmt"; cargo clippy --workspace --all-targets --all-features -- $clippy_check_only; cargo fmt --all $check; - info "Builder: cargo clippy and fmt"; cargo clippy --all-targets --all-features --manifest-path=$BUILDER_PATH/Cargo.toml -- $clippy_check_only; cargo fmt --all $check --manifest-path=$BUILDER_PATH/Cargo.toml; - info "cargo audit"; cargo audit --file=../Cargo.lock --ignore $h2_advisory_ignore; - info "Builder: cargo audit"; cargo audit --file=$BUILDER_PATH/Cargo.lock --no-fetch --ignore $h2_advisory_ignore; - info "cargo sort"; cargo sort --workspace $check ..; - info "Builder: cargo sort"; cargo sort $check $BUILDER_PATH; )?; // `cargo machete` recurses into subdirectories on its own, so a single @@ -517,12 +495,10 @@ fn run_format_and_lint(check_only: bool) -> io::Result<()> { // its own arguments. if check_only { run_cmd!( - info "cargo machete"; cargo-machete --with-metadata --skip-target-dir ..; )?; } else { run_cmd!( - info "cargo machete"; cargo-machete --with-metadata --skip-target-dir --fix ..; )?; } @@ -542,7 +518,6 @@ fn run_full() -> io::Result<()> { // Verify that compiling for release produces no errors. run_cmd!( cd ..; - info "dist build"; dist build; )?; run_test() @@ -554,10 +529,8 @@ fn run_test() -> io::Result<()> { // from, and its feature resolution matches the `cargo run` which started // that executable, so nothing here needs to relink the running binary. run_cmd!( - info "cargo test"; - cargo test --workspace; - info "Builder: cargo test"; - cargo test --manifest-path=$BUILDER_PATH/Cargo.toml; + cargo nextest run --workspace; + cargo nextest run --manifest-path=$BUILDER_PATH/Cargo.toml; )?; Ok(()) } @@ -576,9 +549,9 @@ fn run_until_fail() -> io::Result<()> { // Clear the screen so only the current iteration's output is visible. print!("\x1b[2J\x1b[H"); println!("--- Iteration {iteration} ---"); - // `run_cmd!` returns an error if `cargo test` exits non-zero, which + // `run_cmd!` returns an error if `cargo nextest` exits non-zero, which // breaks out of the loop -- the same behavior as the script. - run_cmd!(cargo test --test overall).map_err(|err| { + run_cmd!(cargo nextest run --test overall).map_err(|err| { io::Error::other(format!("Test failed on iteration {iteration}: {err}")) })?; } @@ -589,7 +562,6 @@ fn run_build() -> io::Result<()> { // before it began executing, and rebuilding it here would have to relink // the running executable. run_cmd!( - info "cargo build"; cargo build --workspace; )?; // Clean out all bundled files before the rebuild. @@ -609,8 +581,7 @@ fn run_client_build( ) -> io::Result<()> { // Ensure the JavaScript data structures generated from Rust are up to date. run_cmd!( - info "cargo test export_bindings"; - cargo test export_bindings; + cargo nextest run export_bindings; )?; let esbuild = PathBuf::from_slash("node_modules/.bin/esbuild"); @@ -734,8 +705,7 @@ fn run_extensions_build( // Ensure the JavaScript data structures generated from Rust are up to date. run_cmd!( - info "cargo test export_bindings"; - cargo test export_bindings; + cargo nextest run export_bindings; )?; // The main build for the extension. @@ -786,7 +756,7 @@ fn run_change_version(new_version: &String) -> io::Result<()> { )?; search_and_replace_file( format!("{CLIENT_PATH}/package.json5"), - r"(\r?\n version: ')[\d.]+(?:-[a-z\d]*)?(',\r?\n)", + r"(\r?\n version: ')[\d.]+(?:-[a-z\d]*)?(',\r?\n)", &replacement_string, )?; Ok(()) @@ -855,8 +825,7 @@ fn run_postrelease(target: &str, tag: &str) -> io::Result<()> { fn run_coverage() -> io::Result<()> { run_cmd!( - info "cargo llvm-cov --open"; - cargo llvm-cov --open; + cargo llvm-cov nextest --open; ) } @@ -901,6 +870,18 @@ fn main() -> io::Result<()> { let root_path = canonicalize(root_path).unwrap(); env::set_current_dir(root_path).unwrap(); + // Replace cmd\_lib's built-in logger, which hides `debug` messages unless + // `RUST_LOG` says otherwise, with one which shows them unless `RUST_LOG` + // says otherwise. Match its format (see + // `cmd_lib::try_init_default_logger`), which omits the timestamp and + // target. + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")) + .format_timestamp(None) + .format_target(false) + .init(); + + // Echo all commands as they're run, to make failures easy to debug. + cmd_lib::set_debug(true); let cli = Cli::parse(); cli.run()?; diff --git a/client/package.json5 b/client/package.json5 index 361c26e3..744e2e5c 100644 --- a/client/package.json5 +++ b/client/package.json5 @@ -24,86 +24,86 @@ oddly munged by `pnpm` per [this issue](https://github.com/pnpm/pnpm/issues/9838). */ { - author: 'Bryan A. Jones', - categories: [ - 'Other', - ], - description: 'The CodeChat Editor Client, part of a web-based literate programming editor (the CodeChat Editor).', - homepage: 'https://codechat-editor.onrender.com/fw/fsb/opt/render/project/src/README.md', - keywords: [ - 'literate programming', - 'CodeChat Editor', - 'Visual Studio Code extension', - ], - license: 'GPL-3.0-only', - name: 'codechat-editor-client', - repository: { - type: 'git', - url: 'https://github.com/bjones1/CodeChat_editor', - }, - type: 'module', - version: '0.3.2', - dependencies: { - '@codemirror/commands': '^6.11.1', - '@codemirror/lang-cpp': '^6.0.3', - '@codemirror/lang-css': '^6.3.1', - '@codemirror/lang-go': '^6.0.1', - '@codemirror/lang-html': '^6.4.12', - '@codemirror/lang-java': '^6.0.2', - '@codemirror/lang-javascript': '^6.2.5', - '@codemirror/lang-json': '^6.0.2', - '@codemirror/lang-python': '^6.2.1', - '@codemirror/lang-rust': '^6.0.2', - '@codemirror/lang-sql': '^6.10.0', - '@codemirror/lang-yaml': '^6.1.3', - '@codemirror/language': '^6.13.1', - '@codemirror/legacy-modes': '^6.5.5', - '@codemirror/lint': '^6.9.7', - '@codemirror/state': '^6.7.6', - '@codemirror/view': '^6.43.15', - '@hpcc-js/wasm-graphviz': '^1.30.0', - '@mathjax/mathjax-newcm-font': '^4.1.3', - codemirror: '^6.0.2', - mathjax: '^4.1.3', - mermaid: '^12.2.0', - 'pdfjs-dist': '^6.4.299', - tinymce: '^8.10.1', - 'toastify-js': '^1.12.0', - }, - devDependencies: { - '@eslint/css': '^2.0.1', - '@eslint/js': '^10.0.1', - '@types/chai': '^5.2.3', - '@types/mocha': '^10.0.10', - '@types/node': '^26.6.6', - '@types/toastify-js': '^1.12.4', - '@typescript-eslint/eslint-plugin': '^8.72.1', - '@typescript-eslint/parser': '^8.72.1', - '@typescript/native': 'npm:typescript@^7.0.2', - /* The accessibility audit engine driven by the Server's `overall_a11y` - browser tests. */ - 'axe-core': '^4.14.0', - chai: '^6.3.0', - esbuild: '^0.28.2', - eslint: '^10.14.0', - 'eslint-config-prettier': '^10.1.8', - 'eslint-plugin-import': '^2.32.0', - 'eslint-plugin-prettier': '^5.5.7', - globals: '^17.13.0', - mocha: '^12.0.3', - 'npm-check-updates': '^23.1.1', - prettier: '^3.9.10', - /* Typescript 7 support for eslint is blocked per - [this issue](https://github.com/typescript-eslint/typescript-eslint/issues/10940). - Instead, see - [Running Typescript 7.0 Side-by-Side with TypeScript 6.0](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/#running-side-by-side-with-typescript-6.0) - for a workaround. */ - typescript: 'npm:@typescript/typescript6@^6.0.2', - 'typescript-eslint': '^8.72.1', - }, - scripts: { - test: 'echo "Error: no test specified" && exit 1', - build: 'cargo run --manifest-path=../builder/Cargo.toml client-build', - dist: 'cargo run --manifest-path=../builder/Cargo.toml client-build --dist', - }, + author: 'Bryan A. Jones', + categories: [ + 'Other', + ], + description: 'The CodeChat Editor Client, part of a web-based literate programming editor (the CodeChat Editor).', + homepage: 'https://codechat-editor.onrender.com/fw/fsb/opt/render/project/src/README.md', + keywords: [ + 'literate programming', + 'CodeChat Editor', + 'Visual Studio Code extension', + ], + license: 'GPL-3.0-only', + name: 'codechat-editor-client', + repository: { + type: 'git', + url: 'https://github.com/bjones1/CodeChat_editor', + }, + type: 'module', + version: '0.3.3', + dependencies: { + '@codemirror/commands': '^6.11.1', + '@codemirror/lang-cpp': '^6.0.3', + '@codemirror/lang-css': '^6.3.1', + '@codemirror/lang-go': '^6.0.1', + '@codemirror/lang-html': '^6.4.12', + '@codemirror/lang-java': '^6.0.2', + '@codemirror/lang-javascript': '^6.2.5', + '@codemirror/lang-json': '^6.0.2', + '@codemirror/lang-python': '^6.2.1', + '@codemirror/lang-rust': '^6.0.2', + '@codemirror/lang-sql': '^6.10.0', + '@codemirror/lang-yaml': '^6.1.3', + '@codemirror/language': '^6.13.1', + '@codemirror/legacy-modes': '^6.5.5', + '@codemirror/lint': '^6.9.7', + '@codemirror/state': '^6.7.6', + '@codemirror/view': '^6.43.15', + '@hpcc-js/wasm-graphviz': '^1.30.0', + '@mathjax/mathjax-newcm-font': '^4.1.3', + codemirror: '^6.0.2', + mathjax: '^4.1.3', + mermaid: '^12.3.0', + 'pdfjs-dist': '^6.5.438', + tinymce: '^8.10.1', + 'toastify-js': '^1.12.0', + }, + devDependencies: { + '@eslint/css': '^2.0.1', + '@eslint/js': '^10.0.1', + '@types/chai': '^5.2.3', + '@types/mocha': '^10.0.10', + '@types/node': '^26.6.6', + '@types/toastify-js': '^1.12.4', + '@typescript-eslint/eslint-plugin': '^8.72.1', + '@typescript-eslint/parser': '^8.72.1', + '@typescript/native': 'npm:typescript@^7.0.2', + /* The accessibility audit engine driven by the Server's `overall_a11y` + browser tests. */ + 'axe-core': '^4.14.0', + chai: '^6.3.0', + esbuild: '^0.28.2', + eslint: '^10.14.0', + 'eslint-config-prettier': '^10.1.8', + 'eslint-plugin-import': '^2.32.0', + 'eslint-plugin-prettier': '^5.5.7', + globals: '^17.14.0', + mocha: '^12.0.3', + 'npm-check-updates': '^23.1.1', + prettier: '^3.9.10', + /* Typescript 7 support for eslint is blocked per + [this issue](https://github.com/typescript-eslint/typescript-eslint/issues/10940). + Instead, see + [Running Typescript 7.0 Side-by-Side with TypeScript 6.0](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/#running-side-by-side-with-typescript-6.0) + for a workaround. */ + typescript: 'npm:@typescript/typescript6@^6.0.2', + 'typescript-eslint': '^8.72.1', + }, + scripts: { + test: 'echo "Error: no test specified" && exit 1', + build: 'cargo run --manifest-path=../builder/Cargo.toml client-build', + dist: 'cargo run --manifest-path=../builder/Cargo.toml client-build --dist', + }, } diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml index 9623b575..15dd7fdd 100644 --- a/client/pnpm-lock.yaml +++ b/client/pnpm-lock.yaml @@ -72,11 +72,11 @@ importers: specifier: ^4.1.3 version: 4.1.3 mermaid: - specifier: ^12.2.0 - version: 12.2.0 + specifier: ^12.3.0 + version: 12.3.0 pdfjs-dist: - specifier: ^6.4.299 - version: 6.4.299 + specifier: ^6.5.438 + version: 6.5.438 tinymce: specifier: ^8.10.1 version: 8.10.1 @@ -133,8 +133,8 @@ importers: specifier: ^5.5.7 version: 5.5.7(eslint-config-prettier@10.1.8(eslint@10.14.0(supports-color@8.1.1)))(eslint@10.14.0(supports-color@8.1.1))(prettier@3.9.10) globals: - specifier: ^17.13.0 - version: 17.13.0 + specifier: ^17.14.0 + version: 17.14.0 mocha: specifier: ^12.0.3 version: 12.0.3 @@ -405,8 +405,8 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + '@eslint-community/regexpp@4.12.3': + resolution: {integrity: sha512-R76UKbvsqI68DJJVTVyqFKqU98CN4+B+acxNfEA2IFarSzP0SjtKf/3+fFiXzTyv5Fj3PxLkGHe2wnVWWMxobQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} '@eslint/config-array@0.23.5': @@ -1030,8 +1030,8 @@ packages: codemirror@6.0.2: resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} - commander@15.0.0: - resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} + commander@15.1.0: + resolution: {integrity: sha512-cgnQ88TRrWcC7pVq46RzJVRMktu3W2RcbnoidnfBsl1bmDCBwJS/udcIZpKoCrbAYYaCqsz1yZCVIgbIaU3ddQ==} engines: {node: '>=22.12.0'} commander@7.2.0: @@ -1071,140 +1071,140 @@ packages: d3-array@2.12.1: resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} - d3-array@3.2.4: - resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + d3-array@3.2.5: + resolution: {integrity: sha512-Th8qGXoBalmWsstpkuhmBuTsBQIFqYOJtjlBvNVvBfJ8E3uYusBUwUR8HU20U0qKKQkgCvKyR1YjiozWadk5QA==} engines: {node: '>=12'} - d3-axis@3.0.0: - resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + d3-axis@3.0.1: + resolution: {integrity: sha512-E5QCXfaf/uJZEHHiqoWRq+bQEm2PzoVFv2rDC7CZ3wwI0MjfMW3w83J3ubobG4IJj3lShAI5eiPJhOu/8wHofA==} engines: {node: '>=12'} - d3-brush@3.0.0: - resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + d3-brush@3.0.1: + resolution: {integrity: sha512-L5Glqa/Gb7LU3ndIOMtA5mDzlJ0aXKp5ELP2X09ctWF23jO7+faIUVDbmaIi+D6k3EemXFWn1F3lkfguExoVhA==} engines: {node: '>=12'} - d3-chord@3.0.1: - resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + d3-chord@3.0.2: + resolution: {integrity: sha512-cGmADo5M2PTi3ewJZ2lcE32eURd4JmHtQ5JwRIUcas5L1SXqufG9yPyjWp8fW0gRi7aZi9bgbZPFZO1eyZ+1CQ==} engines: {node: '>=12'} - d3-color@3.1.0: - resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + d3-color@3.1.1: + resolution: {integrity: sha512-lfab8x0Bj0UO7SNsY8dZSbNIA6ipbkE3X0NG9nqjCu6CfCHZseuDnOSJY7hidKrjpP++i1M2qT+FlAdPKYRilA==} engines: {node: '>=12'} - d3-contour@4.0.2: - resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + d3-contour@4.0.3: + resolution: {integrity: sha512-5DYURc8KwXPOhSUBblU0P9rVcArsSPxPOxsfO0Eud0s28oU0sB2e80aRHRL9AZW3usT8ikFKyIHpHHLNWLdRVA==} engines: {node: '>=12'} - d3-delaunay@6.0.4: - resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + d3-delaunay@6.0.6: + resolution: {integrity: sha512-DMQIEvSJhZCB6pwedcXaAlQ+MeKU5LlM2XakKtc73b/VM+RBiI1SRXycOEOKg2jsKj4zZ9F0KGYG6nCGwwWu/g==} engines: {node: '>=12'} - d3-dispatch@3.0.1: - resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + d3-dispatch@3.0.2: + resolution: {integrity: sha512-sAzH4Y4nsLo8eSqw5jKiZt+LU2wZmL/qS+OkxQGjhwazB/D7TY34R/QK1eshfGr7cZEKymKZ/Haem7m+lu98Sg==} engines: {node: '>=12'} - d3-drag@3.0.0: - resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + d3-drag@3.0.1: + resolution: {integrity: sha512-OWeoayCq8J69hUIjvL+Mb6Q6Oaj/fyHV5XaXByEUAG+JUjIfTGDnk3qGpcXrD3VmQ3BSV96fcbM6fqq7C0tbPA==} engines: {node: '>=12'} - d3-dsv@3.0.1: - resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + d3-dsv@3.0.2: + resolution: {integrity: sha512-FUnXhX7I4/AXyRCZzwfZTDGSq8PGZ4oR0tiCBqNGOZMsDrQ+6sIWNQnBzcCGhzJKZ6uCvCezTwflUqI209RRiQ==} engines: {node: '>=12'} hasBin: true - d3-ease@3.0.1: - resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + d3-ease@3.0.2: + resolution: {integrity: sha512-B5znKqRmKROAN4oHWQ50W/qisVjA9GXh2WMsVKdFVp4DxWmcrOsweqgUOUVsv5th96kwaZlokU6SlV4J3gak1w==} engines: {node: '>=12'} - d3-fetch@3.0.1: - resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + d3-fetch@3.0.2: + resolution: {integrity: sha512-1wGF62bgjMRbF6mqbD+6rRWBL2hwWVYQjFO2UP3Wm1nIAvJZKaQxXM5caVY7athoCa8wIq9lCf7g44lPWFk50g==} engines: {node: '>=12'} - d3-force@3.0.0: - resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + d3-force@3.0.1: + resolution: {integrity: sha512-kAaaHLFebBYwgi5cYBXAI8vKrQFMCD2MEswj2QuPKKbdU1wYLc8WXtS7O8F/b6POCIe3gJjY6hkDstHi1yMETQ==} engines: {node: '>=12'} - d3-format@3.1.2: - resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} + d3-format@3.1.3: + resolution: {integrity: sha512-+F+/49swqmGuQJmSKnVMIDH/QkEFV5li9QRj0xm/KhyAUBv099O5PrvpQFxBp24PYph17Mnvt9mjKQV0ii0nMA==} engines: {node: '>=12'} - d3-geo@3.1.1: - resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + d3-geo@3.1.2: + resolution: {integrity: sha512-5R8ZgDQorIxmauv7R6gpE/ndz+Z0qAZssigq0aXFdvPHdY41RqtW02jrRUQAL724NdPABYXo1+gQEGBBr7uKNg==} engines: {node: '>=12'} - d3-hierarchy@3.1.2: - resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + d3-hierarchy@3.1.3: + resolution: {integrity: sha512-GRajN5ZcnEwYFWqqdzhG1qJ3+fDg6WWzk47TJg7ePY7yvYAgRfD2r1mUx+wviBOWuCwamCUzjwMSdato43jbGA==} engines: {node: '>=12'} - d3-interpolate@3.0.1: - resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + d3-interpolate@3.0.2: + resolution: {integrity: sha512-IRzGU62DtxhvsnSTWMQIdnoZ6gA+BCWwBon1EJI6SjoN595799b6z/QRBzXfFhE8iupUPp3042yBNo0STPqnzQ==} engines: {node: '>=12'} d3-path@1.0.9: resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} - d3-path@3.1.0: - resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + d3-path@3.1.1: + resolution: {integrity: sha512-jsbgV8zIT38ReB9O7X7gcLndTQRONSqNNd+oGIaTBdUug4r5jFmp0N6RY9R5GWbdUDucn0qoTGyfjapT4tDhcg==} engines: {node: '>=12'} - d3-polygon@3.0.1: - resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + d3-polygon@3.0.2: + resolution: {integrity: sha512-WAUvPudGU1Dn4mDPfb6+JnnbeVEV53hG/BoT+bxts6AkZsOpTEiV1jHYX+2vtwCICNFG9Wxv8QS+eW1zE/Dwfg==} engines: {node: '>=12'} - d3-quadtree@3.0.1: - resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + d3-quadtree@3.0.2: + resolution: {integrity: sha512-9Lu9mqJKRbIk0d6mKDjpvPURaPdwHVK5CYbcdd0/4vBgz4ldz/7TIOse3kNERsByGNfld58KEco507AztJWyTQ==} engines: {node: '>=12'} - d3-random@3.0.1: - resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + d3-random@3.0.2: + resolution: {integrity: sha512-PxJi9LNV+7mulaYO77nd+oGurXGL1fhedXjHnB3pWLUcqDnQtF4VASoqnQGHgoXLByVdv5QJ/2kfwkGn5HTS8g==} engines: {node: '>=12'} d3-sankey@0.12.3: resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} - d3-scale-chromatic@3.1.0: - resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + d3-scale-chromatic@3.1.1: + resolution: {integrity: sha512-lA5gfN2yMvmChubmptnDiBfeGpHD7Yb1EbvCz0TZE0WHXhyR6W2allPuhKtzV5ILQRqeOdefF0qYtERReLUBDg==} engines: {node: '>=12'} - d3-scale@4.0.2: - resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + d3-scale@4.0.3: + resolution: {integrity: sha512-66cWobCNzcMvlfoaDHCxuIv9TBUWG1BLOWdv9kHHFuCr1JdqAWPvTmsaEYDD5NRMyWZ5+7u0GqiCDfMXMqh3hg==} engines: {node: '>=12'} - d3-selection@3.0.0: - resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + d3-selection@3.0.1: + resolution: {integrity: sha512-ODSf35vqCrlCfp7hrm0eZjvOosSXSYLjqvIlhMBV9q9VOx7EBJG6pc+uXBswEZNJgCGJ+qnKYcWutbZDIxe/Xg==} engines: {node: '>=12'} d3-shape@1.3.7: resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} - d3-shape@3.2.0: - resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + d3-shape@3.2.1: + resolution: {integrity: sha512-dm2o+lbKdzg9tY7GEag/dB9hcbodLfwkE/DkvqbELJXaMz0yKzWWhZqhbI7CKubukA7HnRyz0avdtvi7EPxPvw==} engines: {node: '>=12'} - d3-time-format@4.1.0: - resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + d3-time-format@4.1.1: + resolution: {integrity: sha512-22XaqjyCjpqgda20erhsOjGmC3vvYwTNYniKAd45W5UWLDF43moeOuV9qYpRqobIlsnK0UhnKZjUUJm3VgORUA==} engines: {node: '>=12'} - d3-time@3.1.0: - resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + d3-time@3.1.1: + resolution: {integrity: sha512-Ze7rjrhMzdeulh0/hjcfFj7XLAHOfowtEMfsoG6DU866HPynQNW7Wfen6hzXcqKTv8XzxvF6Hzr5XD6bMHr2ug==} engines: {node: '>=12'} - d3-timer@3.0.1: - resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + d3-timer@3.0.2: + resolution: {integrity: sha512-1Il1aliroVSErrv5aulRBxAY+7+DnaoLIWGd1C6SsBTWDeobWiP/V69vwb8vT6abR1kKwaNe1196pmaQ1fK90A==} engines: {node: '>=12'} - d3-transition@3.0.1: - resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + d3-transition@3.0.2: + resolution: {integrity: sha512-RcjCsdFgyFoDB+QXLC5m60ZkTN0k9zH+ovoLlTdJnDS1AbfbcuowiM4pCKSTOclNibS4f4J4cbv2m7O7y8NTOQ==} engines: {node: '>=12'} peerDependencies: d3-selection: 2 - 3 - d3-zoom@3.0.0: - resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + d3-zoom@3.0.1: + resolution: {integrity: sha512-kfjD3BDQu/FOatpZ6JdMSyIoDwTxIpI29ySTI2J5ZlDaH1WbuJGQJ2Q9oJkWTEZEW98j6idezoomSD3Cn2zwiw==} engines: {node: '>=12'} - d3@7.9.0: - resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + d3@7.9.2: + resolution: {integrity: sha512-ZKb/mONPVKzaO5UlcWcwN8bS4ezvQaYu+bsou+XgNABdGC800kwH651ADTbbTxMPHW13UlvbQafdmJQDk1w7Mg==} engines: {node: '>=12'} dagre-d3-es@7.0.14: @@ -1271,8 +1271,8 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - elkjs@0.9.3: - resolution: {integrity: sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==} + elkjs@0.12.1: + resolution: {integrity: sha512-IhMYKHE4S2vtx0QrhBP3lYOIKDeIiJXBrdq9MGYkuB8ZHqhrBnHNfSUndjXFewrX1CPK8chwq+2NA0K0hliYuw==} es-abstract-get@1.0.0: resolution: {integrity: sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==} @@ -1306,8 +1306,8 @@ packages: resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==} engines: {node: '>= 0.4'} - es-toolkit@1.53.1: - resolution: {integrity: sha512-VhMc6IXmexu8iYFfL2aaAww6IvJTdHlqBLruLoEUs33YD4IcP5DdZcLOybMsMmmLsiy1c8PsiLsrM0DdIuuRUA==} + es-toolkit@1.53.2: + resolution: {integrity: sha512-iUqZ+NlwH4jUgRmXZUxFBsV/9762TQEa1O4IXLFBmDEjVHScBytKuseX23I0+v9ShZ5MYxEx6WKNzm6IPnex8g==} esbuild@0.28.2: resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} @@ -1486,12 +1486,12 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob@13.0.6: - resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + glob@13.0.7: + resolution: {integrity: sha512-wfsFgXQ8A3SEI9XGf7Nl3Y9l7ffSrGh7SUCT7vU/2CzYPep9kjxAn1S40F9OPKxAMGCVl7HtNlJhrCJUeUq83g==} engines: {node: 18 || 20 || >=22} - globals@17.13.0: - resolution: {integrity: sha512-RwMTC61u7hrG3ZJMkZQOK4JLJrKS8QtoTii63EmWvFXHqycY9FObBJQCbsLxSO8kjKhWE5kV1GC+Vb1g3RI0Zg==} + globals@17.14.0: + resolution: {integrity: sha512-UtdkTVyAJePQv0J2M9Xe4L0ruNSDV314XiIJsADI2Zf40bcdAonE/D/OhAU8AT99oij9mhLByb+NvA3QWZYgCg==} engines: {node: '>=18'} globalthis@1.0.4: @@ -1592,8 +1592,8 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - is-core-module@2.17.0: - resolution: {integrity: sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==} + is-core-module@2.18.0: + resolution: {integrity: sha512-qyax9fgaKOEC4qK8WZn7Q4IcoZC9RC1O1fFxRcRTq/oMMkWT/uXpqpXa12kzWR409zAt1drYN9N9BO26UmBCmw==} engines: {node: '>= 0.4'} is-data-view@1.0.2: @@ -1746,8 +1746,8 @@ packages: mdn-data@2.37.2: resolution: {integrity: sha512-rz9YOBGItdSbe7HcSArUbhiAv4SB/4DKRYg96CSFS2CcIYMbUvBtZlzA1NCbk2AdgbmYwMqwNblLpR441lLeiQ==} - mermaid@12.2.0: - resolution: {integrity: sha512-w7nr/SFrLO7BaVTs3dQTvYSV6nYSBj0Yy9DjBhsIJtAcHqRzXSq4Pg32ujHZ/AdWsAMNEvvhbm5dt9E2tOiHzw==} + mermaid@12.3.0: + resolution: {integrity: sha512-4113TdXeLAsMruJ79OpFL5O8+LTFXhQqZ260rF3tgUmiNAtRm4Uume04I+65PRN6yZ69J4f8rVYWW8zRk65UYw==} engines: {node: '>=22.12.0'} minimatch@10.2.6: @@ -1849,8 +1849,8 @@ packages: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} - pdfjs-dist@6.4.299: - resolution: {integrity: sha512-AVl138zALtfaAPvADulE0PZThbYzCBS79nL4pOSL/6Sm/4AH5A21BD9VHt97OlCuzJuCpmeZtAtkinisF4Vb1g==} + pdfjs-dist@6.5.438: + resolution: {integrity: sha512-vg8Pw1x+AFKy4AMDvhuWl5cOYV8d698UoEANoFFhc79hqXDnZQqnOXoxw3HG907WHOg1JYOvLhP756boddFxpA==} engines: {node: '>=22.13.0 || >=24'} picocolors@1.1.1: @@ -1932,12 +1932,12 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + semver@6.3.2: + resolution: {integrity: sha512-GYrCADwpu6yV5OAvchkQ27Z5wwMxWAEMg5NNWjyHh/5DboFFqbdbvYNIvZouQpxXyeMPoTOh0vdPYKlf0ZswdQ==} hasBin: true - semver@7.8.5: - resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + semver@7.8.6: + resolution: {integrity: sha512-9lpSSU4Mly3mrtruwLs1eLK6+gzbzqeBFwRNjIjE+9LuDpWdYctrQlQ3ej1Ilgi7gknpsTRnPoLP8DpCHqHIJw==} engines: {node: '>=10'} hasBin: true @@ -2101,10 +2101,6 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - uuid@14.0.3: - resolution: {integrity: sha512-Sc5u1VVln93y1Xnz4R+CunOZc7R9LUcTmhj7Rc7Eg3HVcf7rVn2FOoa812fe0W8p3jD7xeoGSYbfqCGGH2B6xw==} - hasBin: true - w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} @@ -2399,7 +2395,7 @@ snapshots: eslint: 10.14.0(supports-color@8.1.1) eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.12.2': {} + '@eslint-community/regexpp@4.12.3': {} '@eslint/config-array@0.23.5(supports-color@8.1.1)': dependencies: @@ -2750,7 +2746,7 @@ snapshots: '@typescript-eslint/eslint-plugin@8.72.1(@typescript-eslint/parser@8.72.1(@typescript/typescript6@6.0.2)(eslint@10.14.0(supports-color@8.1.1))(supports-color@8.1.1))(@typescript/typescript6@6.0.2)(eslint@10.14.0(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@eslint-community/regexpp': 4.12.2 + '@eslint-community/regexpp': 4.12.3 '@typescript-eslint/parser': 8.72.1(@typescript/typescript6@6.0.2)(eslint@10.14.0(supports-color@8.1.1))(supports-color@8.1.1) '@typescript-eslint/scope-manager': 8.72.1 '@typescript-eslint/type-utils': 8.72.1(@typescript/typescript6@6.0.2)(eslint@10.14.0(supports-color@8.1.1))(supports-color@8.1.1) @@ -2816,7 +2812,7 @@ snapshots: '@typescript-eslint/visitor-keys': 8.72.1 debug: 4.4.3(supports-color@8.1.1) minimatch: 10.2.6 - semver: 7.8.5 + semver: 7.8.6 tinyglobby: 0.2.17 ts-api-utils: 2.5.0(@typescript/typescript6@6.0.2) typescript: '@typescript/typescript6@6.0.2' @@ -2905,8 +2901,8 @@ snapshots: '@upsetjs/venn.js@2.0.0': optionalDependencies: - d3-selection: 3.0.0 - d3-transition: 3.0.1(d3-selection@3.0.0) + d3-selection: 3.0.1 + d3-transition: 3.0.2(d3-selection@3.0.1) acorn-jsx@5.3.2(acorn@8.19.0): dependencies: @@ -3047,7 +3043,7 @@ snapshots: '@codemirror/state': 6.7.6 '@codemirror/view': 6.43.15 - commander@15.0.0: {} + commander@15.1.0: {} commander@7.2.0: {} @@ -3085,172 +3081,173 @@ snapshots: dependencies: internmap: 1.0.1 - d3-array@3.2.4: + d3-array@3.2.5: dependencies: internmap: 2.0.3 - d3-axis@3.0.0: {} + d3-axis@3.0.1: {} - d3-brush@3.0.0: + d3-brush@3.0.1: dependencies: - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-transition: 3.0.1(d3-selection@3.0.0) + d3-dispatch: 3.0.2 + d3-drag: 3.0.1 + d3-interpolate: 3.0.2 + d3-selection: 3.0.1 + d3-transition: 3.0.2(d3-selection@3.0.1) - d3-chord@3.0.1: + d3-chord@3.0.2: dependencies: - d3-path: 3.1.0 + d3-path: 3.1.1 - d3-color@3.1.0: {} + d3-color@3.1.1: {} - d3-contour@4.0.2: + d3-contour@4.0.3: dependencies: - d3-array: 3.2.4 + d3-array: 3.2.5 - d3-delaunay@6.0.4: + d3-delaunay@6.0.6: dependencies: delaunator: 5.1.0 - d3-dispatch@3.0.1: {} + d3-dispatch@3.0.2: {} - d3-drag@3.0.0: + d3-drag@3.0.1: dependencies: - d3-dispatch: 3.0.1 - d3-selection: 3.0.0 + d3-dispatch: 3.0.2 + d3-selection: 3.0.1 - d3-dsv@3.0.1: + d3-dsv@3.0.2: dependencies: commander: 7.2.0 iconv-lite: 0.6.3 rw: 1.3.3 - d3-ease@3.0.1: {} + d3-ease@3.0.2: {} - d3-fetch@3.0.1: + d3-fetch@3.0.2: dependencies: - d3-dsv: 3.0.1 + d3-dsv: 3.0.2 - d3-force@3.0.0: + d3-force@3.0.1: dependencies: - d3-dispatch: 3.0.1 - d3-quadtree: 3.0.1 - d3-timer: 3.0.1 + d3-dispatch: 3.0.2 + d3-quadtree: 3.0.2 + d3-timer: 3.0.2 - d3-format@3.1.2: {} + d3-format@3.1.3: {} - d3-geo@3.1.1: + d3-geo@3.1.2: dependencies: - d3-array: 3.2.4 + d3-array: 3.2.5 - d3-hierarchy@3.1.2: {} + d3-hierarchy@3.1.3: {} - d3-interpolate@3.0.1: + d3-interpolate@3.0.2: dependencies: - d3-color: 3.1.0 + d3-color: 3.1.1 d3-path@1.0.9: {} - d3-path@3.1.0: {} + d3-path@3.1.1: {} - d3-polygon@3.0.1: {} + d3-polygon@3.0.2: {} - d3-quadtree@3.0.1: {} + d3-quadtree@3.0.2: {} - d3-random@3.0.1: {} + d3-random@3.0.2: {} d3-sankey@0.12.3: dependencies: d3-array: 2.12.1 d3-shape: 1.3.7 - d3-scale-chromatic@3.1.0: + d3-scale-chromatic@3.1.1: dependencies: - d3-color: 3.1.0 - d3-interpolate: 3.0.1 + d3-color: 3.1.1 + d3-interpolate: 3.0.2 + d3-scale: 4.0.3 - d3-scale@4.0.2: + d3-scale@4.0.3: dependencies: - d3-array: 3.2.4 - d3-format: 3.1.2 - d3-interpolate: 3.0.1 - d3-time: 3.1.0 - d3-time-format: 4.1.0 + d3-array: 3.2.5 + d3-format: 3.1.3 + d3-interpolate: 3.0.2 + d3-time: 3.1.1 + d3-time-format: 4.1.1 - d3-selection@3.0.0: {} + d3-selection@3.0.1: {} d3-shape@1.3.7: dependencies: d3-path: 1.0.9 - d3-shape@3.2.0: - dependencies: - d3-path: 3.1.0 - - d3-time-format@4.1.0: - dependencies: - d3-time: 3.1.0 - - d3-time@3.1.0: - dependencies: - d3-array: 3.2.4 - - d3-timer@3.0.1: {} - - d3-transition@3.0.1(d3-selection@3.0.0): - dependencies: - d3-color: 3.1.0 - d3-dispatch: 3.0.1 - d3-ease: 3.0.1 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-timer: 3.0.1 - - d3-zoom@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-transition: 3.0.1(d3-selection@3.0.0) - - d3@7.9.0: - dependencies: - d3-array: 3.2.4 - d3-axis: 3.0.0 - d3-brush: 3.0.0 - d3-chord: 3.0.1 - d3-color: 3.1.0 - d3-contour: 4.0.2 - d3-delaunay: 6.0.4 - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-dsv: 3.0.1 - d3-ease: 3.0.1 - d3-fetch: 3.0.1 - d3-force: 3.0.0 - d3-format: 3.1.2 - d3-geo: 3.1.1 - d3-hierarchy: 3.1.2 - d3-interpolate: 3.0.1 - d3-path: 3.1.0 - d3-polygon: 3.0.1 - d3-quadtree: 3.0.1 - d3-random: 3.0.1 - d3-scale: 4.0.2 - d3-scale-chromatic: 3.1.0 - d3-selection: 3.0.0 - d3-shape: 3.2.0 - d3-time: 3.1.0 - d3-time-format: 4.1.0 - d3-timer: 3.0.1 - d3-transition: 3.0.1(d3-selection@3.0.0) - d3-zoom: 3.0.0 + d3-shape@3.2.1: + dependencies: + d3-path: 3.1.1 + + d3-time-format@4.1.1: + dependencies: + d3-time: 3.1.1 + + d3-time@3.1.1: + dependencies: + d3-array: 3.2.5 + + d3-timer@3.0.2: {} + + d3-transition@3.0.2(d3-selection@3.0.1): + dependencies: + d3-color: 3.1.1 + d3-dispatch: 3.0.2 + d3-ease: 3.0.2 + d3-interpolate: 3.0.2 + d3-selection: 3.0.1 + d3-timer: 3.0.2 + + d3-zoom@3.0.1: + dependencies: + d3-dispatch: 3.0.2 + d3-drag: 3.0.1 + d3-interpolate: 3.0.2 + d3-selection: 3.0.1 + d3-transition: 3.0.2(d3-selection@3.0.1) + + d3@7.9.2: + dependencies: + d3-array: 3.2.5 + d3-axis: 3.0.1 + d3-brush: 3.0.1 + d3-chord: 3.0.2 + d3-color: 3.1.1 + d3-contour: 4.0.3 + d3-delaunay: 6.0.6 + d3-dispatch: 3.0.2 + d3-drag: 3.0.1 + d3-dsv: 3.0.2 + d3-ease: 3.0.2 + d3-fetch: 3.0.2 + d3-force: 3.0.1 + d3-format: 3.1.3 + d3-geo: 3.1.2 + d3-hierarchy: 3.1.3 + d3-interpolate: 3.0.2 + d3-path: 3.1.1 + d3-polygon: 3.0.2 + d3-quadtree: 3.0.2 + d3-random: 3.0.2 + d3-scale: 4.0.3 + d3-scale-chromatic: 3.1.1 + d3-selection: 3.0.1 + d3-shape: 3.2.1 + d3-time: 3.1.1 + d3-time-format: 4.1.1 + d3-timer: 3.0.2 + d3-transition: 3.0.2(d3-selection@3.0.1) + d3-zoom: 3.0.1 dagre-d3-es@7.0.14: dependencies: - d3: 7.9.0 + d3: 7.9.2 lodash-es: 4.18.1 data-view-buffer@1.0.2: @@ -3319,7 +3316,7 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - elkjs@0.9.3: {} + elkjs@0.12.1: {} es-abstract-get@1.0.0: dependencies: @@ -3413,7 +3410,7 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - es-toolkit@1.53.1: {} + es-toolkit@1.53.2: {} esbuild@0.28.2: optionalDependencies: @@ -3453,7 +3450,7 @@ snapshots: eslint-import-resolver-node@0.3.10(supports-color@8.1.1): dependencies: debug: 3.2.7(supports-color@8.1.1) - is-core-module: 2.17.0 + is-core-module: 2.18.0 resolve: 2.0.0-next.7 transitivePeerDependencies: - supports-color @@ -3481,13 +3478,13 @@ snapshots: eslint-import-resolver-node: 0.3.10(supports-color@8.1.1) eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.72.1(@typescript/typescript6@6.0.2)(eslint@10.14.0(supports-color@8.1.1))(supports-color@8.1.1))(eslint-import-resolver-node@0.3.10(supports-color@8.1.1))(eslint@10.14.0(supports-color@8.1.1))(supports-color@8.1.1) hasown: 2.0.4 - is-core-module: 2.17.0 + is-core-module: 2.18.0 is-glob: 4.0.3 minimatch: 3.1.5 object.fromentries: 2.0.8 object.groupby: 1.0.3 object.values: 1.2.1 - semver: 6.3.1 + semver: 6.3.2 string.prototype.trimend: 1.0.10 tsconfig-paths: 3.15.0 optionalDependencies: @@ -3520,7 +3517,7 @@ snapshots: eslint@10.14.0(supports-color@8.1.1): dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@10.14.0(supports-color@8.1.1)) - '@eslint-community/regexpp': 4.12.2 + '@eslint-community/regexpp': 4.12.3 '@eslint/config-array': 0.23.5(supports-color@8.1.1) '@eslint/config-helpers': 0.7.0 '@eslint/core': 1.2.1 @@ -3651,13 +3648,13 @@ snapshots: dependencies: is-glob: 4.0.3 - glob@13.0.6: + glob@13.0.7: dependencies: minimatch: 10.2.6 minipass: 7.1.3 path-scurry: 2.0.2 - globals@17.13.0: {} + globals@17.14.0: {} globalthis@1.0.4: dependencies: @@ -3745,7 +3742,7 @@ snapshots: is-callable@1.2.7: {} - is-core-module@2.17.0: + is-core-module@2.18.0: dependencies: hasown: 2.0.4 @@ -3852,7 +3849,7 @@ snapshots: katex@0.18.10: dependencies: - commander: 15.0.0 + commander: 15.1.0 keyv@5.6.0: dependencies: @@ -3887,7 +3884,7 @@ snapshots: mdn-data@2.37.2: {} - mermaid@12.2.0: + mermaid@12.3.0: dependencies: '@braintree/sanitize-url': 7.1.2 '@iconify/utils': 3.1.7 @@ -3898,20 +3895,19 @@ snapshots: cytoscape: 3.34.4 cytoscape-cose-bilkent: 4.1.0(cytoscape@3.34.4) cytoscape-fcose: 2.2.0(cytoscape@3.34.4) - d3: 7.9.0 + d3: 7.9.2 d3-sankey: 0.12.3 dagre-d3-es: 7.0.14 dayjs: 1.11.23 dompurify: 3.4.17 - elkjs: 0.9.3 - es-toolkit: 1.53.1 + elkjs: 0.12.1 + es-toolkit: 1.53.2 katex: 0.18.10 khroma: 2.1.0 marked: 16.4.2 roughjs: 4.6.6 stylis: 4.4.0 ts-dedent: 2.3.0 - uuid: 14.0.3 minimatch@10.2.6: dependencies: @@ -3932,7 +3928,7 @@ snapshots: debug: 4.4.3(supports-color@8.1.1) diff: 9.0.0 find-up-simple: 1.0.1 - glob: 13.0.6 + glob: 13.0.7 is-path-inside: 4.0.0 is-unicode-supported: 0.1.0 js-yaml: 5.5.0 @@ -3953,7 +3949,7 @@ snapshots: array.prototype.flatmap: 1.3.3 es-errors: 1.3.0 object.entries: 1.1.9 - semver: 6.3.1 + semver: 6.3.2 npm-check-updates@23.1.1: {} @@ -4036,7 +4032,7 @@ snapshots: lru-cache: 11.5.3 minipass: 7.1.3 - pdfjs-dist@6.4.299: + pdfjs-dist@6.5.438: optionalDependencies: '@napi-rs/canvas': 1.1.0 @@ -4092,7 +4088,7 @@ snapshots: resolve@2.0.0-next.7: dependencies: es-errors: 1.3.0 - is-core-module: 2.17.0 + is-core-module: 2.18.0 node-exports-info: 1.6.2 object-keys: 1.1.1 path-parse: 1.0.7 @@ -4130,9 +4126,9 @@ snapshots: safer-buffer@2.1.2: {} - semver@6.3.1: {} + semver@6.3.2: {} - semver@7.8.5: {} + semver@7.8.6: {} serialize-javascript@7.1.4: {} @@ -4351,8 +4347,6 @@ snapshots: dependencies: punycode: 2.3.1 - uuid@14.0.3: {} - w3c-keyname@2.2.8: {} which-boxed-primitive@1.1.1: diff --git a/client/src/CodeChatEditor-test.mts b/client/src/CodeChatEditor-test.mts index f8d4e597..8d6830d2 100644 --- a/client/src/CodeChatEditor-test.mts +++ b/client/src/CodeChatEditor-test.mts @@ -19,7 +19,7 @@ // ================================================================= // // To run tests, run [`./bt client-build`](#cc-1s8bUScadp) from the root of the -// project to build any changes to the Client, then run `cargo test --test +// project to build any changes to the Client, then run `cargo nextest run --test // overall test_client` from the `server/` directory. Or, add a `?test` // parameter to any web page served by the CodeChat Editor Server. // diff --git a/client/src/CodeChatEditor.mts b/client/src/CodeChatEditor.mts index aa25cdf7..6acdca48 100644 --- a/client/src/CodeChatEditor.mts +++ b/client/src/CodeChatEditor.mts @@ -58,6 +58,7 @@ import { mathJaxUnTypeset, scrollToLine as codemirrorScrollToLine, setCodeMirrorPositions, + setCodeMirrorReadOnly, } from "./CodeMirror-integration.mjs"; import "./graphviz-webcomponent-setup.mjs"; // This must be imported *after* the previous setup import, so it's placed here, @@ -127,6 +128,7 @@ declare global { scrollLine?: number, ) => void; showToast: (text: string) => void; + setReadOnly: (readOnly: boolean) => void; allow_navigation: boolean; }; CodeChatEditor_test: unknown; @@ -163,13 +165,40 @@ export const setIsDirty = (value: boolean = true) => { export const getIsDirty = () => isDirty; +// True while the IDE holds text which the Server can't translate. The Client +// still shows the last text which translated, and the Server rejects edits to +// it, since they would replace the IDE's newer text (see `client_update` in +// [translation.rs](../../server/src/translation.rs)). So, the Client is +// read-only until the IDE's text translates. +let isReadOnly = false; + +export const getIsReadOnly = () => isReadOnly; + +// Make the Client read-only or editable. The read-only modes of CodeMirror and +// TinyMCE keep the cursor, so the user can still select, copy, and follow +// links. +const setReadOnly = ( + // True to make the Client read-only. + readOnly: boolean, +) => { + isReadOnly = readOnly; + setTinymceMode(); + setCodeMirrorReadOnly(readOnly); +}; + +const setTinymceMode = () => + tinymceInstance()?.mode.set(isReadOnly ? "readonly" : "design"); + // ### TinyMCE dynamic import // // TinyMCE is dynamically imported when `init` is called. export const init = async (options: RawEditorOptions) => { const tinymceConfig = await import("./tinymce-config.mjs"); tinymce = tinymceConfig.tinymce; - return await tinymceConfig.init(options); + const editors = await tinymceConfig.init(options); + // The Client may have become read-only while TinyMCE loaded. + setTinymceMode(); + return editors; }; // The imported module is stored in this variable. export let tinymce: undefined | TinyMCE = undefined; @@ -271,6 +300,12 @@ const _openLp = async ( consoleLog(`Ignoring re-translation because Client is dirty.`); return; } + // The Server sends an update which isn't a re-translation only when the + // IDE's text translates, ending the read-only state which began when the + // Framework received a `CannotTranslateSource` error. + if (!isReTranslation) { + setReadOnly(false); + } try { // Use @@ -809,6 +844,7 @@ onDomContentLoaded(async () => { sendUpdate, scrollToLine, showToast, + setReadOnly, allow_navigation: false, }; }); diff --git a/client/src/CodeChatEditorFramework.mts b/client/src/CodeChatEditorFramework.mts index 040bd09f..de0b0fae 100644 --- a/client/src/CodeChatEditorFramework.mts +++ b/client/src/CodeChatEditorFramework.mts @@ -338,6 +338,21 @@ class WebSocketComm { `Error in message ${id}: ${JSON.stringify(resultContents.Err)}.`, resultContents.Err, ); + // The Server sends this error when the IDE's text first + // fails to translate (see `ide_update` in + // [translation.rs](../../server/src/translation.rs)). + // Queue this behind any update still being applied: + // that update holds older text, so applying it would + // otherwise end the read-only state. + const err = resultContents.Err; + if ( + typeof err === "object" && + "CannotTranslateSource" in err + ) { + this.promise = this.promise.finally(() => + getClient()?.setReadOnly(true), + ); + } } break; } diff --git a/client/src/CodeMirror-integration.mts b/client/src/CodeMirror-integration.mts index 093579c4..d44628ba 100644 --- a/client/src/CodeMirror-integration.mts +++ b/client/src/CodeMirror-integration.mts @@ -63,6 +63,7 @@ import { } from "@codemirror/view"; import { ChangeDesc, + Compartment, EditorState, Extension, Prec, @@ -79,6 +80,7 @@ import type { Editor, EditorEvent, Events } from "tinymce"; // ### Local import { + getIsReadOnly, setIsDirty, startAutoUpdateTimer, saveSelection, @@ -150,6 +152,9 @@ const exceptionSink = EditorView.exceptionSink.of((exception) => { const TINYMCE_INST = "TinyMCE-inst"; const CODECHAT_DOC_HIDDEN = "CodeChat-doc-hidden"; +// Holds the `readOnly` facet, so that `setCodeMirrorReadOnly` can change it. +const readOnlyCompartment = new Compartment(); + // Doc blocks in CodeMirror // ------------------------ // @@ -163,7 +168,7 @@ const CODECHAT_DOC_HIDDEN = "CodeChat-doc-hidden"; // [StateField](https://codemirror.net/docs/ref/#state.StateField^define): the // state required to store all doc blocks. Conveniently, a // [DecorationSet](https://codemirror.net/docs/ref/#view.DecorationSet) is a -// [RangeSet](https://codemirror.net/docs/ref/#state.RangeSet)<[Decoration](https://codemirror.net/docs/ref/#view.Decoration)\>, +// [RangeSet](https://codemirror.net/docs/ref/#state.RangeSet)\<[Decoration](https://codemirror.net/docs/ref/#view.Decoration)\>, // each element of which contains the required range and the needed HTML in the // Decoration -- all the required state. Making it a DecorationSet provides an // easy way to store all doc blocks. @@ -706,16 +711,22 @@ const getContents = (element: Element): [HTMLDivElement, boolean] => { }; // Allow only spaces and delete/backspaces when editing the indent of a doc -// block. This is registered (see `DocBlockPlugin`'s `focusin` handler below) as -// a `beforeinput` listener on a doc block's indent div. It's defined here, as a -// single stable function reference, rather than as an inline arrow function -// created inside the `focusin` handler: `addEventListener` only skips re-adding -// a listener that's reference-equal to one already registered on the same -// target, and `focusin` can fire repeatedly on the same (unchanged, and -// therefore DOM-preserving -- see `DocBlockWidget.eq`) indent div, e.g. by -// blurring then refocusing it. A fresh arrow function per `focusin` call would -// defeat that dedup and accumulate listeners. +// block, and nothing in a read-only Client, since neither CodeMirror nor +// TinyMCE manages the indent. This is registered (see `DocBlockPlugin`'s +// `focusin` handler below) as a `beforeinput` listener on a doc block's indent +// div. It's defined here, as a single stable function reference, rather than +// as an inline arrow function created inside the `focusin` handler: +// `addEventListener` only skips re-adding a listener that's reference-equal to +// one already registered on the same target, and `focusin` can fire repeatedly +// on the same (unchanged, and therefore DOM-preserving -- see +// `DocBlockWidget.eq`) indent div, e.g. by blurring then refocusing it. A fresh +// arrow function per `focusin` call would defeat that dedup and accumulate +// listeners. const onIndentBeforeinput = (event: InputEvent) => { + if (getIsReadOnly()) { + event.preventDefault(); + return; + } // Only modify the behavior of inserts. if (event.data) { // Block any insert that's not an insert of spaces. TODO: need to @@ -869,10 +880,10 @@ const linkOutsideTinymce = ( // `tinymce.util.VK.metaKeyPressed` accepts the click (see `Following links` in // [tinymce-config.mts](tinymce-config.mts)), so `isFollowClick` repeats that // test: TinyMCE loads only once a doc block gains the focus, too late for a -// click which arrives first. On macOS and iOS, which TinyMCE recognizes from the -// user agent much as below, the test requires Cmd; elsewhere, it requires Ctrl -// without Alt, since AltGr, which types characters on many Windows keyboard -// layouts, reports both. +// click which arrives first. On macOS and iOS, which TinyMCE recognizes from +// the user agent much as below, the test requires Cmd; elsewhere, it requires +// Ctrl without Alt, since AltGr, which types characters on many Windows +// keyboard layouts, reports both. const isMacOsOrIos = /iphone|ipad|mac os x/.test( navigator.userAgent.toLowerCase(), ); @@ -1792,6 +1803,8 @@ export const codeMirrorLoad = async ( break; default: + // Load an arbitrary parser, since `parser` is required when + // creating the editor. parser = ( await import("@codemirror/lang-javascript") ).javascript(); @@ -1824,6 +1837,9 @@ export const codeMirrorLoad = async ( }), exceptionSink, autosaveExtension, + readOnlyCompartment.of( + EditorState.readOnly.of(getIsReadOnly()), + ), // Make tab an indent per the // [docs](https://codemirror.net/examples/tab/). TODO: // document a way to escape the tab key per the same docs. @@ -1978,6 +1994,18 @@ export const scrollToLine = ( } }; +// Make the code blocks read-only or editable. CodeMirror then ignores input and +// disables its editing commands, but still moves the cursor. +export const setCodeMirrorReadOnly = ( + // True to make the code blocks read-only. + readOnly: boolean, +) => + currentView?.dispatch({ + effects: readOnlyCompartment.reconfigure( + EditorState.readOnly.of(readOnly), + ), + }); + // Apply a `StringDiff` to the before string to produce the after string. export const applyDiffStr = (before: string, diffs: StringDiff[]) => { // Walk from the last diff to the first. JavaScript doesn't have reverse diff --git a/client/src/tinymce-config.mts b/client/src/tinymce-config.mts index de71df9c..a68cbd84 100644 --- a/client/src/tinymce-config.mts +++ b/client/src/tinymce-config.mts @@ -103,12 +103,6 @@ export const init = async ( // [docs](https://www.tiny.cloud/docs/configure/editor-appearance/#fixed_toolbar_container). fixed_toolbar_container: "#CodeChat-menu", inline: true, - // When true, this still prevents hyperlinks to anchors on the - // current page from working correctly. There's an onClick handler - // that prevents links in the current page from working -- need to - // look into this. See also - // [a related GitHub issue](https://github.com/tinymce/tinymce/issues/3836). - //readonly: true // Per the comment above, this is commented out. // Use relative URLs in hyperlinks. relative_urls: true, // Disable the diff --git a/dist-workspace.toml b/dist-workspace.toml index 7667dabc..d6d5707a 100644 --- a/dist-workspace.toml +++ b/dist-workspace.toml @@ -28,18 +28,13 @@ members = ["cargo:."] # Extra static files to include in each App (path relative to this Cargo.toml's dir) include = ["client/static", "server/hashLocations.json", "server/log4rs.yml"] # The preferred dist version to use in CI (Cargo.toml SemVer syntax) -cargo-dist-version = "0.33.1" +cargo-dist-version = "0.34.0" # CI backends to support ci = "github" # The installers to generate for each app installers = [] # Target platforms to build apps for (Rust target-triple syntax) -targets = [ - "aarch64-apple-darwin", - "x86_64-apple-darwin", - "x86_64-unknown-linux-gnu", - "x86_64-pc-windows-msvc", -] +targets = ["aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"] # Skip checking whether the specified configuration files are up to date allow-dirty = ["ci"] license-files = ["LICENSE.md"] diff --git a/docs/design.md b/docs/design.md index 9cd2d31b..0f9a568e 100644 --- a/docs/design.md +++ b/docs/design.md @@ -29,7 +29,7 @@ To build from source 3. [Install NPM](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) (the Node.js package manager). 4. In the root directory of the project: - 1. Run `./bt install --dev`. + 1. Run `./bt install`. 2. Run `./bt build`. 5. In the `server/` directory, run `cargo run -- start ../README.md`. diff --git a/docs/implementation.md b/docs/implementation.md index defdd9cd..a8f45b31 100644 --- a/docs/implementation.md +++ b/docs/implementation.md @@ -269,7 +269,7 @@ builder.

`bt` (build tool) script

+>bt (build tool) script Misc topics ----------- diff --git a/docs/style_guide.cpp b/docs/style_guide.cpp index 6fc6c4fa..8172fa23 100644 --- a/docs/style_guide.cpp +++ b/docs/style_guide.cpp @@ -110,6 +110,12 @@ class LedBlinker { ); }; +// Keep comments in source files short. Place specifications or long +// documentation for a file in an accompanying Markdown file, and refer to it +// following the file's title. For example, `cache.rs` refers to +// `cache-spec.md`, which gives the design of the +// cache. +// // Use of mathematics // ------------------ // diff --git a/extensions/VSCode/package.json b/extensions/VSCode/package.json index bc730499..1945323d 100644 --- a/extensions/VSCode/package.json +++ b/extensions/VSCode/package.json @@ -41,7 +41,7 @@ "type": "git", "url": "https://github.com/bjones1/CodeChat_Editor" }, - "version": "0.3.2", + "version": "0.3.3", "activationEvents": [ "onCommand:extension.codeChatEditorActivate", "onCommand:extension.codeChatEditorDeactivate", @@ -118,7 +118,7 @@ "@emnapi/core": "^1.11.3", "@emnapi/runtime": "^1.11.3", "@eslint/js": "^10.0.1", - "@napi-rs/cli": "^3.10.9", + "@napi-rs/cli": "^3.10.12", "@tybys/wasm-util": "^0.10.4", "@types/escape-html": "^1.0.4", "@types/node": "^26.6.6", @@ -140,7 +140,7 @@ "typescript-eslint": "^8.72.1" }, "optionalDependencies": { - "bufferutil": "^4.1.0" + "bufferutil": "^4.2.0" }, "scripts": { "compile": "cargo run --manifest-path=../../builder/Cargo.toml ext-build", diff --git a/extensions/VSCode/pnpm-lock.yaml b/extensions/VSCode/pnpm-lock.yaml index 5c7ccc9c..a97b9dfc 100644 --- a/extensions/VSCode/pnpm-lock.yaml +++ b/extensions/VSCode/pnpm-lock.yaml @@ -22,8 +22,8 @@ importers: specifier: ^10.0.1 version: 10.0.1(eslint@10.14.0) '@napi-rs/cli': - specifier: ^3.10.9 - version: 3.10.9(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@26.6.6) + specifier: ^3.10.12 + version: 3.10.12(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@26.6.6) '@tybys/wasm-util': specifier: ^0.10.4 version: 0.10.4 @@ -83,8 +83,8 @@ importers: version: 8.72.1(@typescript/typescript6@6.0.2)(eslint@10.14.0) optionalDependencies: bufferutil: - specifier: ^4.1.0 - version: 4.1.0 + specifier: ^4.2.0 + version: 4.2.0 packages: @@ -96,16 +96,16 @@ packages: resolution: {integrity: sha512-IUZydyTUkDnYdstOW9pFOOUQlBjAepK5teihDE3x6yxsPJs/hsAaaYpeGxdxrgtOiJbBKSjKW7MDk7AEhb4LRg==} engines: {node: '>=22.0.0'} - '@azure/core-client@1.11.1': - resolution: {integrity: sha512-2QygG2F76ZpMP2eMztiJvAiFMu71M9rDeU7vO/QKg5Css7MgM4frUOslFjhVjRhbGaCNPtz/S8M6y46/fFKVuQ==} + '@azure/core-client@1.11.2': + resolution: {integrity: sha512-ajuIU1aMoTs/ERYrKnIqQrV5Vz3RL8mwDC5RdedIXUvR7pi6cWzeYmt0LfNz6+W91CuCO4WJG0zA6+PhU1X+hw==} engines: {node: '>=22.0.0'} '@azure/core-process@1.0.0': resolution: {integrity: sha512-/shnJ+ooO8WPxDhPEeI/2oRQuubn16gZ6CvlbpWbEswZfzwI9tI/sMAHmF3x1LuQ9yZYXfLW3TjzGMLEC5blKg==} engines: {node: '>=22.0.0'} - '@azure/core-rest-pipeline@1.25.0': - resolution: {integrity: sha512-bMs8ekJLjX8wPV+9IPBges1SLPyuDtE9g5gLDWOpxzKcoOFQnpLGkbcT1tdw3FaAmDS1gnPmMmJ6y/T5B96kIA==} + '@azure/core-rest-pipeline@1.25.1': + resolution: {integrity: sha512-fTIA3CAm/cdODqiXkO6jYOIkU2Ylld7vq65KGc70gTwl12sLQsC8v7I5t6tp2N2CfUONzZBXyeFw7KEu6Ks2zg==} engines: {node: '>=22.0.0'} '@azure/core-tracing@1.4.0': @@ -124,16 +124,16 @@ packages: resolution: {integrity: sha512-rbAE25KUfjU/s3XHUdJgceoCP5dEOpMx85J04kF+QMdta73XkuG9JGHHinch+XIoKpBdqljin+KqURpJriSzLA==} engines: {node: '>=22.0.0'} - '@azure/msal-browser@5.27.0': - resolution: {integrity: sha512-i2CKKyuCuOZEBZJiAoFK/viYZAP6CRaqqlkeHl3ViteDHOUE/tkI/Slq1cdGnwhkIB+k1OE0g00QGl9O0gAFNQ==} + '@azure/msal-browser@5.29.0': + resolution: {integrity: sha512-Ko/Ovw6h+Gu33mp8f0FUyddr/KDWzbGzcgR8HKZaT4wgTYljLPKJP1rcDu0RHj7pkd4CR2hCHK51XFzgvq/Q5Q==} engines: {node: '>=0.8.0'} - '@azure/msal-common@16.15.0': - resolution: {integrity: sha512-lwdLb1B9Q5nEhPLVIKe78XH5wFMN15fCiDkY7ylPDSWZuWcD93G3jpJajrKhO3CQld8SLKz0sHiOi24mxdvtsg==} + '@azure/msal-common@16.16.1': + resolution: {integrity: sha512-dSKdL9h/iercb4GumsKFh+wVvLe1ohuDPiviklgnQVHnY2FYNUlbQJ3E1Qd37vkof9CfraK9BQpCW1hoOg0znQ==} engines: {node: '>=0.8.0'} - '@azure/msal-node@7.1.2': - resolution: {integrity: sha512-52hKQLGpEQzwNufIXG1SPVU+wQ3RIe7Rp2+g+VdAmZojCAZ6yCdGEffzQEQ6RnBZGBEs40nl14rWBmfJpCoHsg==} + '@azure/msal-node@7.2.1': + resolution: {integrity: sha512-6mntsfCNq7H1eAPSZik74jT3C5at4nRqiVk7OC+D5Hy3Pe3s76uwE4+J0xvDvlVPmoX2kasf3mSwUmzeq9rW/A==} engines: {node: '>=20'} '@cacheable/memory@2.2.0': @@ -145,33 +145,24 @@ packages: '@dual-bundle/import-meta-resolve@4.2.1': resolution: {integrity: sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==} - '@emnapi/core@1.11.2': - resolution: {integrity: sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==} - '@emnapi/core@1.11.3': resolution: {integrity: sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==} - '@emnapi/core@1.9.2': - resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} - - '@emnapi/runtime@1.11.2': - resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} + '@emnapi/core@2.0.0-beta.3': + resolution: {integrity: sha512-KA+gOBtbifRATmUa/Gpf5C2B2EJ0r4brHUT3XSgACeHREcuiObXH56xd+B3fFsEFbUT04VBEe6MuZiCtMp0tQg==} '@emnapi/runtime@1.11.3': resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} - '@emnapi/runtime@1.9.2': - resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} - - '@emnapi/wasi-threads@1.2.1': - resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} - - '@emnapi/wasi-threads@1.2.2': - resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + '@emnapi/runtime@2.0.0-beta.3': + resolution: {integrity: sha512-ayb/PyyLzpwRyFVxeC0uoEHu59QlB1iWGcGsOpXQcaB/Dc+uGfBmNmpCHp3HmTT0t8lSsMmg3j7+tdJW/TlHjQ==} '@emnapi/wasi-threads@1.2.3': resolution: {integrity: sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==} + '@emnapi/wasi-threads@2.2.0': + resolution: {integrity: sha512-JP7OYH38Q7+pyTAe14raZHLQIK7BDKbdwji+Xi3pcd/6QkJYQH3SX4wu6EplGrGJWRepoNzedfm0G3B9Z4e9Rw==} + '@esbuild/aix-ppc64@0.28.2': resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} engines: {node: '>=18'} @@ -334,8 +325,8 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + '@eslint-community/regexpp@4.12.3': + resolution: {integrity: sha512-R76UKbvsqI68DJJVTVyqFKqU98CN4+B+acxNfEA2IFarSzP0SjtKf/3+fFiXzTyv5Fj3PxLkGHe2wnVWWMxobQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} '@eslint/config-array@0.23.5': @@ -530,14 +521,14 @@ packages: '@keyv/serialize@1.1.1': resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} - '@napi-rs/cli@3.10.9': - resolution: {integrity: sha512-RpzJrTDlSxUi2Deo+dh4bmDTKklAVe295aSQjZspwbZyUBG7twbXbiKskL2w/bL4kNg3DdkrwbI/iQwI9kgQaQ==} + '@napi-rs/cli@3.10.12': + resolution: {integrity: sha512-8QDEW10Ld/uAemSP9g5WFIcmKh7I6PMA78ttc2UtZb+6cyAsX7RkVt2H5B658j7504R2JRE6JHs+b0WERHc+4w==} engines: {node: ^20.17.0 || ^22.13.0 || >= 23.5.0} hasBin: true peerDependencies: - '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 - '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 - emnapi: ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/core': ^1.7.1 || ^2.0.0-beta.2 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-beta.2 + emnapi: ^1.7.1 || ^2.0.0-beta.2 peerDependenciesMeta: '@emnapi/core': optional: true @@ -546,19 +537,19 @@ packages: emnapi: optional: true - '@napi-rs/cross-toolchain@1.0.3': - resolution: {integrity: sha512-ENPfLe4937bsKVTDA6zdABx4pq9w0tHqRrJHyaGxgaPq03a2Bd1unD5XSKjXJjebsABJ+MjAv1A2OvCgK9yehg==} + '@napi-rs/cross-toolchain@1.0.5': + resolution: {integrity: sha512-UhzMXkaW8xc1ekwDeahmezVU0BEeK68VvkpgmdDPcJPhGVdHrAF/xQTD8lpyMEkFat0w2vBMmklpoFtzNCUneQ==} peerDependencies: - '@napi-rs/cross-toolchain-arm64-target-aarch64': ^1.0.3 - '@napi-rs/cross-toolchain-arm64-target-armv7': ^1.0.3 - '@napi-rs/cross-toolchain-arm64-target-ppc64le': ^1.0.3 - '@napi-rs/cross-toolchain-arm64-target-s390x': ^1.0.3 - '@napi-rs/cross-toolchain-arm64-target-x86_64': ^1.0.3 - '@napi-rs/cross-toolchain-x64-target-aarch64': ^1.0.3 - '@napi-rs/cross-toolchain-x64-target-armv7': ^1.0.3 - '@napi-rs/cross-toolchain-x64-target-ppc64le': ^1.0.3 - '@napi-rs/cross-toolchain-x64-target-s390x': ^1.0.3 - '@napi-rs/cross-toolchain-x64-target-x86_64': ^1.0.3 + '@napi-rs/cross-toolchain-arm64-target-aarch64': ^1.0.5 + '@napi-rs/cross-toolchain-arm64-target-armv7': ^1.0.5 + '@napi-rs/cross-toolchain-arm64-target-ppc64le': ^1.0.5 + '@napi-rs/cross-toolchain-arm64-target-s390x': ^1.0.5 + '@napi-rs/cross-toolchain-arm64-target-x86_64': ^1.0.5 + '@napi-rs/cross-toolchain-x64-target-aarch64': ^1.0.5 + '@napi-rs/cross-toolchain-x64-target-armv7': ^1.0.5 + '@napi-rs/cross-toolchain-x64-target-ppc64le': ^1.0.5 + '@napi-rs/cross-toolchain-x64-target-s390x': ^1.0.5 + '@napi-rs/cross-toolchain-x64-target-x86_64': ^1.0.5 peerDependenciesMeta: '@napi-rs/cross-toolchain-arm64-target-aarch64': optional: true @@ -662,313 +653,313 @@ packages: resolution: {integrity: sha512-WrOw/bcXm0f9qHkumlT1QlArXSTWqaY9sunsDpOk+yCCorCKMxvWT/a3xko4EYHVdeZoh00yI2TydXn6eyICDA==} engines: {node: '>= 10'} - '@napi-rs/lzma-android-arm-eabi@1.5.1': - resolution: {integrity: sha512-sahBe4ko2Z69NPTddaX6ZgbQZu9SDoITxw1S3dWl1gAGynZG34qHHCT8UaUMFxf3h3zMhCJjEzz4basaBxiTuQ==} + '@napi-rs/lzma-android-arm-eabi@1.5.3': + resolution: {integrity: sha512-Jo8Ej9sTXZO+vHVllHPYxcHVoW4dQe30eLx7wk3H786vv2zy/qIIi5KoO6WhK/VsSBhAb13xbIa/vc4maUgp8Q==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [arm] os: [android] - '@napi-rs/lzma-android-arm64@1.5.1': - resolution: {integrity: sha512-7tkQAJJuBHxAxiEBNFgSTpvrtGpbwZYYJUSOmGEK3OfbdbNeoT2rdBxpM/gY1s+itEVbtOSlpaRPPG19MnwOzA==} + '@napi-rs/lzma-android-arm64@1.5.3': + resolution: {integrity: sha512-BUEMluJxOJ/9WkZH/IFyyi3viNQGEByodAHDbmJ/k7mVhabGIxjYBea3MmnyTZoIoqZs/ftAKH7jhVCIj+k6mw==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [arm64] os: [android] - '@napi-rs/lzma-darwin-arm64@1.5.1': - resolution: {integrity: sha512-XWX8gtF+GHGk3nH3Wm3QUZNcxw9QHsFVZz3MzVLhWWHhceede1J4/vD+3dj3E1iKB9G6mualaZxOoD08R3E+7g==} + '@napi-rs/lzma-darwin-arm64@1.5.3': + resolution: {integrity: sha512-ea46AUzmoGqWnrDP8JNea14TCiVMmxWtaD/d5YjRgh1KbL3YfZ9O2BZzfF7DAF+yrVuAQqS52rHveysjnzYlJA==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [arm64] os: [darwin] - '@napi-rs/lzma-darwin-x64@1.5.1': - resolution: {integrity: sha512-CfsqUpMTI1z8enrA/b+GcHM6YDI8D0kqCiqPYEnst4rbOABQ9KZ92ybTTNnlnZ7A017WoMZKUEWc36KXDwi0xg==} + '@napi-rs/lzma-darwin-x64@1.5.3': + resolution: {integrity: sha512-/vz8UpAe/9fV7JiTrT+lAV9Xk9bK4F28u8JRDNIYdGaT7lXP0r/e7YjDvBuJZ9bJtStW4nn/08q5Q7yfFmsF1Q==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [x64] os: [darwin] - '@napi-rs/lzma-freebsd-x64@1.5.1': - resolution: {integrity: sha512-bTyNfg90FXIgE61U7l14aMmVOqRQ6AyP5JMT3jmCStaZI18apLNPdzZ8i7yqxZfKvRMVfPjE2brXIw27c+RRgA==} + '@napi-rs/lzma-freebsd-x64@1.5.3': + resolution: {integrity: sha512-gAxemzm8Zk1OaMXihd0L8zeAb/P+71NqhrYnrPVweW3cTXg7XACC+zXQsvENAvHhkroeHCfaMmFupRwfHi+u7A==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [x64] os: [freebsd] - '@napi-rs/lzma-linux-arm-gnueabihf@1.5.1': - resolution: {integrity: sha512-vNE+D8nrw+eOkBsdKCsmDhowDV3pIMKXEhedvXfbgrWbrO7GlZJH+RXL+X+RYLxGwi8Ym61ZMt15sIOnNmh9Sw==} + '@napi-rs/lzma-linux-arm-gnueabihf@1.5.3': + resolution: {integrity: sha512-T7ZvCSEAKGoYSw7vIwdKgk1ZaYl8V1JLTgWSlGhnYBau23R9qZP79ONiF7FTosXnvR8G9RLe9peVuVGS5GI7ig==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [arm] os: [linux] - '@napi-rs/lzma-linux-arm64-gnu@1.5.1': - resolution: {integrity: sha512-csUem4WgoKGTprv/pOPm9UIWbb+hrfUwYXefpTHPAEGVFLl5behEFabisJ7FtihCa3yG2Efcl+yw25rlhhrIYw==} + '@napi-rs/lzma-linux-arm64-gnu@1.5.3': + resolution: {integrity: sha512-fEfgGb/y8jo2X57cTtMQ62XSD57rxDbpSbT38TSq0gSMKg6A/zq3oOxZLRfoCuZkL3cDtuZMi4fAuo6xIkP5eQ==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [arm64] os: [linux] libc: [glibc] - '@napi-rs/lzma-linux-arm64-musl@1.5.1': - resolution: {integrity: sha512-kB/xhlVN1eLvVmDJSKZEjp5Gg2xDYexNrB5jwpSMbOkeGS6N9AasByPBg5VqCpMYC+zZi7DM458DRhtWYhqXTQ==} + '@napi-rs/lzma-linux-arm64-musl@1.5.3': + resolution: {integrity: sha512-Phe10HwfNrtM7U2XsVLhJGePWOgx0BVW2/EWUBq1hoPkmKuUTjbrFj8y4XSTGS5eHMWABUtehnkbX+MPnN5sKg==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [arm64] os: [linux] libc: [musl] - '@napi-rs/lzma-linux-ppc64-gnu@1.5.1': - resolution: {integrity: sha512-s28RW0W1yBWQc1nbPdF7tp14koqslY3ZWLVI8uaanX292Dc6ezd4NPVwxEoCNBVON/oD7BmUbWGtyFvmm7dQ5A==} + '@napi-rs/lzma-linux-ppc64-gnu@1.5.3': + resolution: {integrity: sha512-rhuUE76jYbXZaR5oXAWqvfXzxoZKaCFM1nTH3yrdmz2Jtog5mnFcmyJ9WjDFmUgzQo062p1WfXWm3FA8SJOwaA==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [ppc64] os: [linux] libc: [glibc] - '@napi-rs/lzma-linux-riscv64-gnu@1.5.1': - resolution: {integrity: sha512-+lGNwYlIN14YPMTNvYtIJJqHFevDTd6Juw/1NmXbWx/iRd/LLrjhlM/yluMX6pxs6NkOGsuuEXJJrbbEUS59OQ==} + '@napi-rs/lzma-linux-riscv64-gnu@1.5.3': + resolution: {integrity: sha512-ogeKmHMV80J1uGYu5Lg4XVacyQxv9wapsEMEKH6beFtouIpo5wZMod5/zGLNHA+sg0/9HIAQbm/bVFJ5flkiQQ==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [riscv64] os: [linux] libc: [glibc] - '@napi-rs/lzma-linux-s390x-gnu@1.5.1': - resolution: {integrity: sha512-PB44FFWWFrLeQowhcep1hPD1YcLqKlnnY60RMU74qrxTlr4YGEyzeMItJqh2uivBfv9kQScOF/B0J9+Vab/oyw==} + '@napi-rs/lzma-linux-s390x-gnu@1.5.3': + resolution: {integrity: sha512-FvFzkI1zzVUqpX21UQdLZ0efTPxDolaCH1bqIp6k7hMTtx0RNwHJgcrsbGXQisAJ8uLWKRKncwNVL8MzcBVxUg==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [s390x] os: [linux] libc: [glibc] - '@napi-rs/lzma-linux-x64-gnu@1.5.1': - resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + '@napi-rs/lzma-linux-x64-gnu@1.5.3': + resolution: {integrity: sha512-cqF0sRTngwVgnH0y7OV/5zWKWZomMYY71t3gzjtmJou4oPoWQHjxmO1Jo5E3GqUg2bPk+Fp3DcRw1xLAeKs1cg==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [x64] os: [linux] libc: [glibc] - '@napi-rs/lzma-linux-x64-musl@1.5.1': - resolution: {integrity: sha512-I3nsYrWtrW9JpeCr+mkJIVDt0HY3m6qVUBs5vTtoIvJQxwqf1PBXSy5IS7T53ksQFH2kd2UX8rLxJ7B4WISpZg==} + '@napi-rs/lzma-linux-x64-musl@1.5.3': + resolution: {integrity: sha512-ZBMasmon/mQmwIKNCWDJagq/zq45vvDQzhSijJSBSIgyef8IRvoD9O4H2lq62Lrq3toHxhlMD2D85jwUVr4QQw==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [x64] os: [linux] libc: [musl] - '@napi-rs/lzma-wasm32-wasi@1.5.1': - resolution: {integrity: sha512-gy3wwPBa6+XEyA4fUzq6CClrXA1ajXjuVf5zbnHytJRgoHznj+mvpU3+co2fxXwqTCmIpn6KrzqH5bRDztBPhA==} + '@napi-rs/lzma-wasm32-wasi@1.5.3': + resolution: {integrity: sha512-gJ2YpVByn8xNbSCbOwQhCN9Jc2ZQY0ERx/K3XFDldbyiFXCphbEnciptp3bwqcp+WUJvIvpZxcKP1+6tcUEj1g==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [wasm32] - '@napi-rs/lzma-win32-arm64-msvc@1.5.1': - resolution: {integrity: sha512-dK+huOsHiyH6oJjij+cnjqFCakk2HgWmpI12Xm4pLUyPphe4ebYoJBgehaNAxprmjFqBQ7nL95YPVz9BHyqmPg==} + '@napi-rs/lzma-win32-arm64-msvc@1.5.3': + resolution: {integrity: sha512-oB9iJluslRc3bZ3upZ7ZD2tJfICX3tjTsqS8jUUWK+d7PpJei/oZ3YklBLNyczmLZ+JXHYZlBbotIeVCaoNGPw==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [arm64] os: [win32] - '@napi-rs/lzma-win32-ia32-msvc@1.5.1': - resolution: {integrity: sha512-dGE8L+0EQ+GyU9ap9InqB/t/PmPG/bLj918q7OsJ29FuTdn8fK4OX3U4IQZhylHIA+/dQ/SXJk5n4yfah2XVvA==} + '@napi-rs/lzma-win32-ia32-msvc@1.5.3': + resolution: {integrity: sha512-b5HxoRno1C9kS9I9pH9E7uYO9oMEQZ2RuOzAs8+PafoHzcHA5KMzSibNfA//seedILG1w22IS7YfrW4s0+4FvA==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [ia32] os: [win32] - '@napi-rs/lzma-win32-x64-msvc@1.5.1': - resolution: {integrity: sha512-EKW4t/iqdCT/xnd5t9oXLvVER/PMNAWXKqUAl3fgvUcOILeZIIht77/dVnfFcc9htA/DCBXC/6YQWdW+LusjFA==} + '@napi-rs/lzma-win32-x64-msvc@1.5.3': + resolution: {integrity: sha512-cPH8uIK0aaD9KZ0FTPBBPTIvncNHQ2Si3DNTP2rjPWyDRVV+syT2dWvlmkiklKgnRipXtx4eJ+tYQZhG30/+9w==} engines: {node: ^22.20 || ^24.12 || >=25} cpu: [x64] os: [win32] - '@napi-rs/lzma@1.5.1': - resolution: {integrity: sha512-sgOZ89+y8cDbY+3WbzR8CtIhCuFRWotZ9/2PjPVDJHz6np5KFTAev0DrwiyTJTgFsCRDhfGlbmhMgyhHbWdZ6g==} + '@napi-rs/lzma@1.5.3': + resolution: {integrity: sha512-QSIzELPyd2A7mcaDiJEWjwzApoAOWq9PVl9xYq+CxzIwstufv48s8aBgOUr0sgbjGmb15aYU88YKNaFaCaOuhQ==} engines: {node: ^22.20 || ^24.12 || >=25} - '@napi-rs/tar-android-arm-eabi@1.1.1': - resolution: {integrity: sha512-cAhnA10cSusAUbcE9HtjQY/tZ9BH/0w2sKtRcQc94TzIlnm7QSr1htJSd/PPrbWNPtrv1orXb2CkrHlVlbnlHA==} + '@napi-rs/tar-android-arm-eabi@1.1.3': + resolution: {integrity: sha512-WDzurP2WgSlMVi6X96kTJRS9Nu+EKxTQkbLzdrGhhkVptO3cwvbY53S/H6c43xIFsI0ZskmyTNmYiAvj2nfwSQ==} engines: {node: '>= 10'} cpu: [arm] os: [android] - '@napi-rs/tar-android-arm64@1.1.1': - resolution: {integrity: sha512-EslUWHCDBY/g5abTPBiHLsMaML4GagV0TXLm5WL9hAjx/DDtlxz9fegMb77RJ+f7nFLOIsUxF/3QWFvgOT0sMQ==} + '@napi-rs/tar-android-arm64@1.1.3': + resolution: {integrity: sha512-cVhQUzlHy/YY7tLqCPa3ibRQlocM8haPLW/ZR9FysI1JN/T9TDUiEhWl+SJIMDr+EvSQxyPwOYP45adtx6ZCXw==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@napi-rs/tar-darwin-arm64@1.1.1': - resolution: {integrity: sha512-+A42/6ES5G9CQ35BOwzwA+WBjLID28r2jNPgc0dteD2hhClIhng0mva7D2ujUlXBNmgNOsr1LHn3stA4uTf4NQ==} + '@napi-rs/tar-darwin-arm64@1.1.3': + resolution: {integrity: sha512-LOGjc5FwCjZdGNRVjXZr0ItdsweAfwmVCnLkQLpx9IovNHhLKzwCWAa2ePdN/e+bbsOXDoUc8MrAtY0IUVWKcA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@napi-rs/tar-darwin-x64@1.1.1': - resolution: {integrity: sha512-RYtE8w1dkEvj8hSJCDV5Jw0Rz2i13fsM7u893zv5O9n/4Ad5GNsw/f4RQ7/0YGSFaenkVxqPFrjmEvUHlKzsrg==} + '@napi-rs/tar-darwin-x64@1.1.3': + resolution: {integrity: sha512-Lqk5gYf5mlrGTPrIZKaRfGOKvbrqLxXAGsHre2zHLIvsFxJH6lJpPB/YXIYEMMCeSrySiZAtRlA2rKPlNGxTHg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@napi-rs/tar-freebsd-x64@1.1.1': - resolution: {integrity: sha512-rEepBvCJUwcuvUYkY83e8aot8RsR5Jcnal4PsG3tbWGKW1yAvcXhyMXf0fN6ZGpVRZFnB+FJqDyBxvsCPEXKhw==} + '@napi-rs/tar-freebsd-x64@1.1.3': + resolution: {integrity: sha512-HnrZ7YISLyPWwafzM3+xAlmgo3glb8L9jUvpVMBSVP4uo11/WXe+3GVFe9WywmXE047neDsWXYz6S4gXAX52Cw==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@napi-rs/tar-linux-arm-gnueabihf@1.1.1': - resolution: {integrity: sha512-an1bJdfyhI5FpZYyTQ20mrqwR+a676i8GkaYc4Uy12dH/a7TJIfrK6Qa2Gm46arZvxUvx56qxoRKXbpOjUPvwA==} + '@napi-rs/tar-linux-arm-gnueabihf@1.1.3': + resolution: {integrity: sha512-BLXGHslkW6jBInBuYVWMcmnlCqeWZOOWVZvn0Cr5bcMmPuq2Va18A7DOz6yYs/ebI1FnnasddbShXhLZAOHWfw==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@napi-rs/tar-linux-arm64-gnu@1.1.1': - resolution: {integrity: sha512-w++Vtx36T2yHTKws7GVnmHHcUT1ybB59xLWSh9A8bwEpJVG4dG7Qub9mFe5cpcbfrJ+XP2mKKxC3oUJSunK3iQ==} + '@napi-rs/tar-linux-arm64-gnu@1.1.3': + resolution: {integrity: sha512-V7sdJPgYWx6msrpNO2v5OREbyEgk5eOJOF9rUpVzEA6Z4BWubFcElcQMyBkDgb8jOtor3b/z91Ep+aD4C2GHVw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@napi-rs/tar-linux-arm64-musl@1.1.1': - resolution: {integrity: sha512-Rh6UFhNtj3i4deJHOBINFIeRL0072mgbeyuK5rl1HokKnNoMKx8qKIZNEzBTTqpogMfDHWGvzyTQdnVxes5dpA==} + '@napi-rs/tar-linux-arm64-musl@1.1.3': + resolution: {integrity: sha512-wkkRDMI6+8duivzcvgoXJAfEAI0MFoRkjPq0fEMaBakK8E4xAePWjpLk4757ejQ0UwoV6aVFCgHJafySvuFXFg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@napi-rs/tar-linux-ppc64-gnu@1.1.1': - resolution: {integrity: sha512-Cp+AxFbv9zcyAXtnzQi0OzmgDnQgy2w9D4Ubr+iwzMtVgJcztzcEoCcCrN1k2ATdEB01LX2Vb49IaocGOZhC9Q==} + '@napi-rs/tar-linux-ppc64-gnu@1.1.3': + resolution: {integrity: sha512-1eaqPDSrBfmaDK7PHhOGwfm8S+Yg/0uOB5heY9b/B8vCm5+CmKt8Z2x4KfI39udz4kcwlMXAhDQrctRzGRravA==} engines: {node: '>= 10'} cpu: [ppc64] os: [linux] libc: [glibc] - '@napi-rs/tar-linux-s390x-gnu@1.1.1': - resolution: {integrity: sha512-ZyscC3SYKTBWyDRYjLOKAd5TyJ7q0KACRdQ8bWrb3rgrra1CCIJD66CsGTH6Dh0AVSdfLwZ8MfIIXU6+14BMjQ==} + '@napi-rs/tar-linux-s390x-gnu@1.1.3': + resolution: {integrity: sha512-o6qluAuWUZP9YUL3uzr7kBabbWyb/hVi7jlNU58snxZXgmtn+N3vbk67F67KD5LqJn8DQR3IgA13Sfu/v+IR3A==} engines: {node: '>= 10'} cpu: [s390x] os: [linux] libc: [glibc] - '@napi-rs/tar-linux-x64-gnu@1.1.1': - resolution: {integrity: sha512-LlIv+zg4fiOQge9LQX/ieBdRWE2fhVDjCTHxnunZkbugNmdhdelxWf1RpZb/6ZujWpNF4LPu4N/MW7ygg2oYAQ==} + '@napi-rs/tar-linux-x64-gnu@1.1.3': + resolution: {integrity: sha512-mt32bxTy7cSDVpca7T8Y3b9LgV8s/dBqGVZrZvIkVm2EFAyKe7rD0FjGgciw2BZNVmLGZCl1wIdRfzS45boFzg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@napi-rs/tar-linux-x64-musl@1.1.1': - resolution: {integrity: sha512-gZBeoKLjanOVj55qk4EMu13P2i9M0SuINmlGQkOxm1niIJofexzddHUYtqO5o/5QqtyL8lADmAcZplLILMLhHA==} + '@napi-rs/tar-linux-x64-musl@1.1.3': + resolution: {integrity: sha512-XbKOipWcorf08qf/KZ8MV1OwW9Wtgcg210yzONW0T9HTkgY1vRj5KzFuXoPLO/0H29GCO1xokY8HT4c6NDzCpA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@napi-rs/tar-wasm32-wasi@1.1.1': - resolution: {integrity: sha512-rwtQ1Mdt/ft6g6I54fJzbUeLspl4yTwj6I3UJ6mitKnrN42soJkcDrdh3Y/FGvlpqZTad2YMQ96fGJl3EtAm2Q==} - engines: {node: '>=14.0.0'} + '@napi-rs/tar-wasm32-wasi@1.1.3': + resolution: {integrity: sha512-pUZYJ51H8sMB9vG1sT1aJVQqmoT4d7JmT1nER/pCsHtFQzk5aBvXuvj4G3Wo2BBCRr2eY+7zXFpJCtj50QuzeA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} cpu: [wasm32] - '@napi-rs/tar-win32-arm64-msvc@1.1.1': - resolution: {integrity: sha512-30PVp1AehRpfwxmv5wI4cg0yj3WmWBsZ+1QnLGnvEELu7Eu/+dhNU0nrmhI7VfPgLwSRK2eg9DQTB3tP7Wv9bA==} + '@napi-rs/tar-win32-arm64-msvc@1.1.3': + resolution: {integrity: sha512-KtAW+o86AZfMng8lC83pisb6Xe50NrbYpNa5ENOapWZBrLl3HU9+PxDQfoxoGTCvLTHU7aoiSzQntE8Ej9cYGg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@napi-rs/tar-win32-ia32-msvc@1.1.1': - resolution: {integrity: sha512-aI3/rmz+izUChiSeaPxcasAOxhf3FpJNuIHMXlxS/vpW+HIxUsSDR5+XV61PEG5DL4L/75iENVUxmSGM5l2yaw==} + '@napi-rs/tar-win32-ia32-msvc@1.1.3': + resolution: {integrity: sha512-A82IKQLi/ZIYgbeLmN+h/LU/H9O78CUAEffdH6PCLsQznX4oZwSvAIXmFxqU7QVk+zLkYQvD7Kau2sBDlCOcIw==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@napi-rs/tar-win32-x64-msvc@1.1.1': - resolution: {integrity: sha512-yJsB2IsrODQVLKbm2Fg1nHiVRbEj49mSPbj4x7JPZWJI0jGVPjohE2Sif0FBbx8OxsVoUODvS0BwksZZ8jl/OA==} + '@napi-rs/tar-win32-x64-msvc@1.1.3': + resolution: {integrity: sha512-Iq/zg92fzXEX7ajcjg2cnAf3YIVR6osfqd7OWucIEWg1NdtA2t2C4Eg8AiDgxHp9/ym+YQ+w5TMhAqJ5FCGo+A==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@napi-rs/tar@1.1.1': - resolution: {integrity: sha512-p6q2HhUc5vwH1CNwfOcrhLoxfgn8ust8Sqlfx+sA4VzAcp1cMbvbkl99tZZlDqOjCHgQNSiTfk/yWPjl/D42qA==} + '@napi-rs/tar@1.1.3': + resolution: {integrity: sha512-W1TENanv88k5OvB+TfkRnTc35ISN8vqvBqAxbWws64AToZKJjtay2yOw2QNVvJmX2SSkKM5JwmHzy96L8c53MQ==} engines: {node: '>= 10'} - '@napi-rs/wasm-runtime@1.2.6': - resolution: {integrity: sha512-mRyDmEw9/fCDXCGfL1sbgIw/GUK0PVxRW4YwgPN61F3LQ+fSyoBFarJVzgGyhF6kRzEQZ0FejDqm4WLXSeqQmw==} + '@napi-rs/wasm-runtime@1.2.7': + resolution: {integrity: sha512-zJccwplOAbgfZju95IUHazLnx9RAPtPN2YGJXI6UbrgeaR9QfPjGrQL6ERkSAtnVCA4Q+83ApGyaX5zdpCaKkQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} peerDependencies: - '@emnapi/core': ^1.7.1 || 2.0.0-beta.2 - '@emnapi/runtime': ^1.7.1 || 2.0.0-beta.2 + '@emnapi/core': ^1.7.1 || 2.0.0-beta.2 || 2.0.0-beta.3 + '@emnapi/runtime': ^1.7.1 || 2.0.0-beta.2 || 2.0.0-beta.3 - '@napi-rs/wasm-tools-android-arm-eabi@1.1.0': - resolution: {integrity: sha512-p6J8PB59I8d/XItXB/go5JH6nKW+xIbpzaL43EBTV0hi7mrS/Z4gs+MsB04ZrlqZN29BdZV8fChRyasuXLhRaA==} + '@napi-rs/wasm-tools-android-arm-eabi@1.1.2': + resolution: {integrity: sha512-a+SYoe8acnmJsBCeJ23V9Gxp0rKHY7tm+mDCouOxaf4ELQuoVLPMso8t4ofIK3PpVLIEKY98YdS1cqJ5wLabNQ==} engines: {node: '>= 12.22.0'} cpu: [arm] os: [android] - '@napi-rs/wasm-tools-android-arm64@1.1.0': - resolution: {integrity: sha512-lWoKN3suypeBSCIRPIw+++sH9V2K6nQkhtdt1opu7XY3v9JwLs6Gw063HWRqkNjphlYpkd/Qy8XcfSPGbJj7nQ==} + '@napi-rs/wasm-tools-android-arm64@1.1.2': + resolution: {integrity: sha512-NP82W1n8Gtg9C5mO6Bv6TyTGWBuq/5yJtRC9btnjDb98XPK7GRzb/Pzdta+tojzyojnpbre2jYCbEx98y6QrWw==} engines: {node: '>= 12.22.0'} cpu: [arm64] os: [android] - '@napi-rs/wasm-tools-darwin-arm64@1.1.0': - resolution: {integrity: sha512-jfw5vyNDUf6oe0kP8lMveFN9U7cLk1cUosS7uMIfw/xmqmopYfKQ198DAx2g/6aEF7Tm+CqER2gpMpYKui30LA==} + '@napi-rs/wasm-tools-darwin-arm64@1.1.2': + resolution: {integrity: sha512-bROsO82JGuTgvK9UoqRT45i8MtfMvF5HQ0DCBlWU3sDywWJTWWITXA/GFUuTnLE1XU+02VIVAPYujmbLdCaosQ==} engines: {node: '>= 12.22.0'} cpu: [arm64] os: [darwin] - '@napi-rs/wasm-tools-darwin-x64@1.1.0': - resolution: {integrity: sha512-R+pjeudAB7BYdH1vKkOJM61Tfv5jB6uXkxmFscYd+KKpdUpWBlNG+s4hr0w4i1rMBM91VhIAETZn2pz+MDHK9A==} + '@napi-rs/wasm-tools-darwin-x64@1.1.2': + resolution: {integrity: sha512-uZ/0Z3Ru4DRhHALWyejYXQCbeyI60eYqOwBvdjSk51oMjLXMA6mfpc7ly3MaFGLcjV3mE9fBdNa9TXlsTHzQng==} engines: {node: '>= 12.22.0'} cpu: [x64] os: [darwin] - '@napi-rs/wasm-tools-freebsd-x64@1.1.0': - resolution: {integrity: sha512-hQJTe+aazrT++Vgm6I4lUd9099ItUCFYdd+aKg6Ys6nax6d/cZ1barDLTwA2lwOoVDsXMekJI/FOL6ZvVlIYBg==} + '@napi-rs/wasm-tools-freebsd-x64@1.1.2': + resolution: {integrity: sha512-6vcpEv4VC0uPTk6USmP7MRElqqbtEKs5jtdUApuTLCE7HrHkms9Qa/s8c/d2mUoywJ6EuzbAuY4vC2KWY6swCQ==} engines: {node: '>= 12.22.0'} cpu: [x64] os: [freebsd] - '@napi-rs/wasm-tools-linux-arm64-gnu@1.1.0': - resolution: {integrity: sha512-1TAXJxUHsWGar90k3W/MknavvBMwOWzjh7Q6Spxo8twRcWJbBD5Kow/Q2KhhDq5hxh2sKGDXn3uLc1tdtz4WUg==} + '@napi-rs/wasm-tools-linux-arm64-gnu@1.1.2': + resolution: {integrity: sha512-3/hLebdY3mgLx/RR3OBgJv0+mPge0/K0IzlTNRqv7sgGQPcKL3eYIfQfcPZu7DqCwBliJwnrrHJUTkOCRWGlew==} engines: {node: '>= 12.22.0'} cpu: [arm64] os: [linux] libc: [glibc] - '@napi-rs/wasm-tools-linux-arm64-musl@1.1.0': - resolution: {integrity: sha512-7rw3nlubTjNAVRH2LwphCxHy1b/N2/TerXocQ6XRn4Q+buaY1Z7P/hbdALy1i1ex2yfOU2Xcij7ib7ZLi/lKfw==} + '@napi-rs/wasm-tools-linux-arm64-musl@1.1.2': + resolution: {integrity: sha512-MJlyQuZqY2xzVezkwJY/JFVemFFMsbR9HyutG7jqlLjuGgTVHqj0gQzw40FVEl43EWnn/w6e8M5T/FNjkf3mpA==} engines: {node: '>= 12.22.0'} cpu: [arm64] os: [linux] libc: [musl] - '@napi-rs/wasm-tools-linux-x64-gnu@1.1.0': - resolution: {integrity: sha512-1sel0t9MRjI/tdT89M8Dd6gPfANeeFP24Xa46R11WeHNwhjsXXZh+xUk50uWCRTSGcaCy3ugm3AMK/lmHYQJkg==} + '@napi-rs/wasm-tools-linux-x64-gnu@1.1.2': + resolution: {integrity: sha512-G68ncazFlsRwXyflUncSu59p3Xfd5AUy79dIh01AeHgrEu8hMCj/g+63NUsaNjzgL8pwuB21rnA8hN0xtA3+Gw==} engines: {node: '>= 12.22.0'} cpu: [x64] os: [linux] libc: [glibc] - '@napi-rs/wasm-tools-linux-x64-musl@1.1.0': - resolution: {integrity: sha512-o2jH5AMfor4EKF2HII1LBnMQxoWu7+usPifTEY8Zk6e9OiSi4EJkAXf9v3ANlX7TI2V/cUEV34OEW7r10GiVIA==} + '@napi-rs/wasm-tools-linux-x64-musl@1.1.2': + resolution: {integrity: sha512-skm8hhSd/qxBwenE5msnMyRo58spnH5YQdWCgFgJXltiMqCcBMI7e3qcPt1Ir4tfkPn0kSKeliKS3bvw1yNxHA==} engines: {node: '>= 12.22.0'} cpu: [x64] os: [linux] libc: [musl] - '@napi-rs/wasm-tools-wasm32-wasi@1.1.0': - resolution: {integrity: sha512-s6YDtDR1UWrsqJPtaxf+JLYLceWVyn3l8OpQYElHkDhf3Qfz9R6Ba3S0OgznTBv38L5/TIHysQ9Q4yO73Z0csg==} - engines: {node: '>=14.0.0'} + '@napi-rs/wasm-tools-wasm32-wasi@1.1.2': + resolution: {integrity: sha512-ZLeQOPDsIlvRWro6zIHe77d8VPDAwvzCk5QLQcoHseEi0TtgjqVLn5/HxjqtNZVPdWgujpm02XVxq5Dc1f9o/Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} cpu: [wasm32] - '@napi-rs/wasm-tools-win32-arm64-msvc@1.1.0': - resolution: {integrity: sha512-x+NuxbG84VxU68tU8w7Rf5lSyq0l584M6dVlke5DTweHYFZoMyeqkpbwEq+qsyAX6ivfipK8xRsmFwamb5uDnA==} + '@napi-rs/wasm-tools-win32-arm64-msvc@1.1.2': + resolution: {integrity: sha512-ctoE1iYL2VVBc+cSyj3qIil1FIZ+T9EdraGxH/awZnCag3+bUjdXl/gIv59DmFLqb9DsH6cl0KYyF7EcRGXdXg==} engines: {node: '>= 12.22.0'} cpu: [arm64] os: [win32] - '@napi-rs/wasm-tools-win32-ia32-msvc@1.1.0': - resolution: {integrity: sha512-mdD96QDEp70SX67rXFTY6c725nVYeqEEjyDqzzbNh6u1APj7CI7IMNpMmvE75XbCRl4C2MHZVU4U6AWdAzvyQQ==} + '@napi-rs/wasm-tools-win32-ia32-msvc@1.1.2': + resolution: {integrity: sha512-2qLV0CacEbm/IxL/iPdABjayj67UUT1wOBbBcsylXsZd+ELxnzmYSS/PCAHQwAuANgnNMY6Y7F5CYx0SKAYL4Q==} engines: {node: '>= 12.22.0'} cpu: [ia32] os: [win32] - '@napi-rs/wasm-tools-win32-x64-msvc@1.1.0': - resolution: {integrity: sha512-bVVjuvhlyVX++3eJXfDR63cXdw1ay5QYac6iq0MKQw8wZARInTM+bXCtByDT4fzVFI3+7ZthYb/ERWRdBNIqgQ==} + '@napi-rs/wasm-tools-win32-x64-msvc@1.1.2': + resolution: {integrity: sha512-06DvdhcaUN29c62IE96/ZQcNykWNQAf9wWELyo4eLim3baSDw9OvdPHseLtfzs27cev2YyuvwaSuxAdYpD2LMw==} engines: {node: '>= 12.22.0'} cpu: [x64] os: [win32] - '@napi-rs/wasm-tools@1.1.0': - resolution: {integrity: sha512-VjHyKEqXAwYZK+HY7iJctYvRm3TFEbaQxeZwvAG1QRkoo1a39phMY8J6x9tUEqJI03W6MysB8F2jacI6wvcx+w==} + '@napi-rs/wasm-tools@1.1.2': + resolution: {integrity: sha512-VM6AVh5aYrUZtadC/ozmyx6lr1mE5RKqBXSrF6HkTrft9wFhHKD8hcKJ9v7QeA0H0QX5Og/7L21hILAICqFLww==} engines: {node: '>= 12.22.0'} '@octokit/auth-token@6.0.0': @@ -1266,8 +1257,8 @@ packages: resolution: {integrity: sha512-mbCddXd+jm7hfx7w2YU64/Av4/NqqeG3GoRZgxPcgoTxYjhrcfJRw9ULch71SS4G+Q3bOXFhRvPqjguN0Hyp5w==} hasBin: true - '@typespec/ts-http-runtime@0.3.9': - resolution: {integrity: sha512-edSdeAqkdxBVzA1yL1LrLCml1YjyCVvPMtMqJpbF+6K609tHe8V6sQUzFQSGcYNhcuhOceZtjvN32+mpIth30A==} + '@typespec/ts-http-runtime@0.3.10': + resolution: {integrity: sha512-vddvvtZ7sejSlCv+OIkn2ztjB1O31Fc2JsxI/YK725r3elXXlF/J3o3lbXJFRhoeWRWK1tjdZ+GTi6Fdtrp+EA==} engines: {node: '>=22.0.0'} '@vscode/vsce-sign-alpine-arm64@2.0.6': @@ -1333,9 +1324,9 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} + agent-base@9.0.0: + resolution: {integrity: sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==} + engines: {node: '>= 20'} ajv@6.15.0: resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} @@ -1412,8 +1403,8 @@ packages: buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} - bufferutil@4.1.0: - resolution: {integrity: sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==} + bufferutil@4.2.0: + resolution: {integrity: sha512-gyy58jET9kst2IGyBKb96a4Y2bPGTHXGyCd0/1eqIV3hr1Sz3VxtA8n7bXh8fLIuE2K6Z0Upax5a5Msx+HU1IQ==} engines: {node: '>=6.14.2'} bundle-name@4.1.1: @@ -1540,8 +1531,8 @@ packages: resolution: {integrity: sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==} engines: {ecmascript: '>= es5', node: '>=4'} - entities@8.1.0: - resolution: {integrity: sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==} + entities@9.0.0: + resolution: {integrity: sha512-oJFNDJg3kTPwAD1cNn2+WmUq4wFoo09npc3Ydf1D7ED4smRiWrsKnaLxykrTWgyGEcusc87P5dxlAleol9kpkg==} engines: {node: '>=20.19.0'} es-abstract-get@1.0.0: @@ -1576,8 +1567,8 @@ packages: resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==} engines: {node: '>= 0.4'} - es-toolkit@1.53.1: - resolution: {integrity: sha512-VhMc6IXmexu8iYFfL2aaAww6IvJTdHlqBLruLoEUs33YD4IcP5DdZcLOybMsMmmLsiy1c8PsiLsrM0DdIuuRUA==} + es-toolkit@1.53.2: + resolution: {integrity: sha512-iUqZ+NlwH4jUgRmXZUxFBsV/9762TQEa1O4IXLFBmDEjVHScBytKuseX23I0+v9ShZ5MYxEx6WKNzm6IPnex8g==} esbuild@0.28.2: resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} @@ -1832,13 +1823,13 @@ packages: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} + http-proxy-agent@9.1.0: + resolution: {integrity: sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig==} + engines: {node: '>= 20'} - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} + https-proxy-agent@9.1.0: + resolution: {integrity: sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==} + engines: {node: '>= 20'} iconv-lite@0.7.3: resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} @@ -1880,8 +1871,8 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - is-core-module@2.17.0: - resolution: {integrity: sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==} + is-core-module@2.18.0: + resolution: {integrity: sha512-qyax9fgaKOEC4qK8WZn7Q4IcoZC9RC1O1fFxRcRTq/oMMkWT/uXpqpXa12kzWR409zAt1drYN9N9BO26UmBCmw==} engines: {node: '>= 0.4'} is-data-view@1.0.2: @@ -2062,8 +2053,8 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} - marked@18.1.2: - resolution: {integrity: sha512-DfOnvLAQ6WYeWxWO1u4RyFOeqyHup6dks5PPqnoFiooU7ipRvidO/2j8plhAHIiZg574E9ZlzSjUiPMLAzFkgg==} + marked@18.1.3: + resolution: {integrity: sha512-9ChMH8EVVgjgID49nsL6IWxWk5c6GtAsq/xw7U1ggkjkU5AGuv68oLTVlFRtvcUYZtpbNyjyvGo3YDu0fGapiw==} engines: {node: '>= 20'} hasBin: true @@ -2172,8 +2163,8 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - parse5@8.0.1: - resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} + parse5@8.1.1: + resolution: {integrity: sha512-EcR/6WDcU7b2N3vQSxKALCk9lXGtUMQxXio008OEMBE0kavu/7JLfBEeFPzi43nMqVDSbEn3QCK+BMCc9zO//w==} path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} @@ -2222,6 +2213,15 @@ packages: proper-lockfile@4.1.2: resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + proxy-agent-negotiate@1.1.0: + resolution: {integrity: sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==} + engines: {node: '>= 20'} + peerDependencies: + kerberos: ^2.0.0 + peerDependenciesMeta: + kerberos: + optional: true + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -2254,8 +2254,8 @@ packages: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} - resolve@1.22.13: - resolution: {integrity: sha512-Dj/cW9zBV2aRj6XzCxuGIs3ESZKv02jixne3q6jFZYZ3/Tg09gHHviSMDL4kObh9pqSahdRHEnDoaP2gn8YLhA==} + resolve@1.22.14: + resolution: {integrity: sha512-1ZjYvR9sbkiwC5+9QHetqW5HmA2pHRMaoupD01t2HlYnV/vydC2zPwLixhsMieSWVZt0JJRg5LVIk0Ow1D/TrA==} engines: {node: '>= 0.4'} hasBin: true @@ -2294,12 +2294,12 @@ packages: resolution: {integrity: sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==} engines: {node: '>=11.0.0'} - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + semver@6.3.2: + resolution: {integrity: sha512-GYrCADwpu6yV5OAvchkQ27Z5wwMxWAEMg5NNWjyHh/5DboFFqbdbvYNIvZouQpxXyeMPoTOh0vdPYKlf0ZswdQ==} hasBin: true - semver@7.8.5: - resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + semver@7.8.6: + resolution: {integrity: sha512-9lpSSU4Mly3mrtruwLs1eLK6+gzbzqeBFwRNjIjE+9LuDpWdYctrQlQ3ej1Ilgi7gknpsTRnPoLP8DpCHqHIJw==} engines: {node: '>=10'} hasBin: true @@ -2539,32 +2539,35 @@ snapshots: '@azure/core-util': 1.14.0 tslib: 2.9.1 transitivePeerDependencies: + - kerberos - supports-color - '@azure/core-client@1.11.1': + '@azure/core-client@1.11.2': dependencies: '@azure/abort-controller': 2.2.0 '@azure/core-auth': 1.11.0 - '@azure/core-rest-pipeline': 1.25.0 + '@azure/core-rest-pipeline': 1.25.1 '@azure/core-tracing': 1.4.0 '@azure/core-util': 1.14.0 '@azure/logger': 1.4.0 tslib: 2.9.1 transitivePeerDependencies: + - kerberos - supports-color '@azure/core-process@1.0.0': {} - '@azure/core-rest-pipeline@1.25.0': + '@azure/core-rest-pipeline@1.25.1': dependencies: '@azure/abort-controller': 2.2.0 '@azure/core-auth': 1.11.0 '@azure/core-tracing': 1.4.0 '@azure/core-util': 1.14.0 '@azure/logger': 1.4.0 - '@typespec/ts-http-runtime': 0.3.9 + '@typespec/ts-http-runtime': 0.3.10 tslib: 2.9.1 transitivePeerDependencies: + - kerberos - supports-color '@azure/core-tracing@1.4.0': @@ -2574,44 +2577,47 @@ snapshots: '@azure/core-util@1.14.0': dependencies: '@azure/abort-controller': 2.2.0 - '@typespec/ts-http-runtime': 0.3.9 + '@typespec/ts-http-runtime': 0.3.10 tslib: 2.9.1 transitivePeerDependencies: + - kerberos - supports-color '@azure/identity@4.14.1': dependencies: '@azure/abort-controller': 2.2.0 '@azure/core-auth': 1.11.0 - '@azure/core-client': 1.11.1 + '@azure/core-client': 1.11.2 '@azure/core-process': 1.0.0 - '@azure/core-rest-pipeline': 1.25.0 + '@azure/core-rest-pipeline': 1.25.1 '@azure/core-tracing': 1.4.0 '@azure/core-util': 1.14.0 '@azure/logger': 1.4.0 - '@azure/msal-browser': 5.27.0 - '@azure/msal-node': 7.1.2 + '@azure/msal-browser': 5.29.0 + '@azure/msal-node': 7.2.1 open: 11.0.4 tslib: 2.9.1 transitivePeerDependencies: + - kerberos - supports-color '@azure/logger@1.4.0': dependencies: - '@typespec/ts-http-runtime': 0.3.9 + '@typespec/ts-http-runtime': 0.3.10 tslib: 2.9.1 transitivePeerDependencies: + - kerberos - supports-color - '@azure/msal-browser@5.27.0': + '@azure/msal-browser@5.29.0': dependencies: - '@azure/msal-common': 16.15.0 + '@azure/msal-common': 16.16.1 - '@azure/msal-common@16.15.0': {} + '@azure/msal-common@16.16.1': {} - '@azure/msal-node@7.1.2': + '@azure/msal-node@7.2.1': dependencies: - '@azure/msal-common': 16.15.0 + '@azure/msal-common': 16.16.1 jsonwebtoken: 9.0.3 '@cacheable/memory@2.2.0': @@ -2628,25 +2634,14 @@ snapshots: '@dual-bundle/import-meta-resolve@4.2.1': {} - '@emnapi/core@1.11.2': - dependencies: - '@emnapi/wasi-threads': 1.2.2 - tslib: 2.9.1 - optional: true - '@emnapi/core@1.11.3': dependencies: '@emnapi/wasi-threads': 1.2.3 tslib: 2.9.1 - '@emnapi/core@1.9.2': - dependencies: - '@emnapi/wasi-threads': 1.2.1 - tslib: 2.9.1 - optional: true - - '@emnapi/runtime@1.11.2': + '@emnapi/core@2.0.0-beta.3': dependencies: + '@emnapi/wasi-threads': 2.2.0 tslib: 2.9.1 optional: true @@ -2654,25 +2649,20 @@ snapshots: dependencies: tslib: 2.9.1 - '@emnapi/runtime@1.9.2': + '@emnapi/runtime@2.0.0-beta.3': dependencies: tslib: 2.9.1 optional: true - '@emnapi/wasi-threads@1.2.1': + '@emnapi/wasi-threads@1.2.3': dependencies: tslib: 2.9.1 - optional: true - '@emnapi/wasi-threads@1.2.2': + '@emnapi/wasi-threads@2.2.0': dependencies: tslib: 2.9.1 optional: true - '@emnapi/wasi-threads@1.2.3': - dependencies: - tslib: 2.9.1 - '@esbuild/aix-ppc64@0.28.2': optional: true @@ -2756,7 +2746,7 @@ snapshots: eslint: 10.14.0 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.12.2': {} + '@eslint-community/regexpp@4.12.3': {} '@eslint/config-array@0.23.5': dependencies: @@ -2928,18 +2918,18 @@ snapshots: '@keyv/serialize@1.1.1': {} - '@napi-rs/cli@3.10.9(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@26.6.6)': + '@napi-rs/cli@3.10.12(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@26.6.6)': dependencies: '@inquirer/prompts': 8.7.5(@types/node@26.6.6) - '@napi-rs/cross-toolchain': 1.0.3 - '@napi-rs/wasm-tools': 1.1.0 + '@napi-rs/cross-toolchain': 1.0.5 + '@napi-rs/wasm-tools': 1.1.2 '@octokit/rest': 22.0.1 clipanion: 4.0.0-rc.4(typanion@3.14.0) colorette: 2.0.20 - es-toolkit: 1.53.1 + es-toolkit: 1.53.2 js-yaml: 5.5.0 obug: 3.0.0 - semver: 7.8.5 + semver: 7.8.6 typanion: 3.14.0 typescript: 6.0.3 optionalDependencies: @@ -2959,10 +2949,10 @@ snapshots: - '@types/node' - supports-color - '@napi-rs/cross-toolchain@1.0.3': + '@napi-rs/cross-toolchain@1.0.5': dependencies: - '@napi-rs/lzma': 1.5.1 - '@napi-rs/tar': 1.1.1 + '@napi-rs/lzma': 1.5.3 + '@napi-rs/tar': 1.1.3 debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -3018,224 +3008,217 @@ snapshots: '@napi-rs/keyring-win32-ia32-msvc': 1.3.0 '@napi-rs/keyring-win32-x64-msvc': 1.3.0 - '@napi-rs/lzma-android-arm-eabi@1.5.1': + '@napi-rs/lzma-android-arm-eabi@1.5.3': optional: true - '@napi-rs/lzma-android-arm64@1.5.1': + '@napi-rs/lzma-android-arm64@1.5.3': optional: true - '@napi-rs/lzma-darwin-arm64@1.5.1': + '@napi-rs/lzma-darwin-arm64@1.5.3': optional: true - '@napi-rs/lzma-darwin-x64@1.5.1': + '@napi-rs/lzma-darwin-x64@1.5.3': optional: true - '@napi-rs/lzma-freebsd-x64@1.5.1': + '@napi-rs/lzma-freebsd-x64@1.5.3': optional: true - '@napi-rs/lzma-linux-arm-gnueabihf@1.5.1': + '@napi-rs/lzma-linux-arm-gnueabihf@1.5.3': optional: true - '@napi-rs/lzma-linux-arm64-gnu@1.5.1': + '@napi-rs/lzma-linux-arm64-gnu@1.5.3': optional: true - '@napi-rs/lzma-linux-arm64-musl@1.5.1': + '@napi-rs/lzma-linux-arm64-musl@1.5.3': optional: true - '@napi-rs/lzma-linux-ppc64-gnu@1.5.1': + '@napi-rs/lzma-linux-ppc64-gnu@1.5.3': optional: true - '@napi-rs/lzma-linux-riscv64-gnu@1.5.1': + '@napi-rs/lzma-linux-riscv64-gnu@1.5.3': optional: true - '@napi-rs/lzma-linux-s390x-gnu@1.5.1': + '@napi-rs/lzma-linux-s390x-gnu@1.5.3': optional: true - '@napi-rs/lzma-linux-x64-gnu@1.5.1': + '@napi-rs/lzma-linux-x64-gnu@1.5.3': optional: true - '@napi-rs/lzma-linux-x64-musl@1.5.1': + '@napi-rs/lzma-linux-x64-musl@1.5.3': optional: true - '@napi-rs/lzma-wasm32-wasi@1.5.1': + '@napi-rs/lzma-wasm32-wasi@1.5.3': dependencies: - '@emnapi/core': 1.11.2 - '@emnapi/runtime': 1.11.2 - '@napi-rs/wasm-runtime': 1.2.6(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@emnapi/core': 2.0.0-beta.3 + '@emnapi/runtime': 2.0.0-beta.3 + '@napi-rs/wasm-runtime': 1.2.7(@emnapi/core@2.0.0-beta.3)(@emnapi/runtime@2.0.0-beta.3) optional: true - '@napi-rs/lzma-win32-arm64-msvc@1.5.1': + '@napi-rs/lzma-win32-arm64-msvc@1.5.3': optional: true - '@napi-rs/lzma-win32-ia32-msvc@1.5.1': + '@napi-rs/lzma-win32-ia32-msvc@1.5.3': optional: true - '@napi-rs/lzma-win32-x64-msvc@1.5.1': + '@napi-rs/lzma-win32-x64-msvc@1.5.3': optional: true - '@napi-rs/lzma@1.5.1': + '@napi-rs/lzma@1.5.3': optionalDependencies: - '@napi-rs/lzma-android-arm-eabi': 1.5.1 - '@napi-rs/lzma-android-arm64': 1.5.1 - '@napi-rs/lzma-darwin-arm64': 1.5.1 - '@napi-rs/lzma-darwin-x64': 1.5.1 - '@napi-rs/lzma-freebsd-x64': 1.5.1 - '@napi-rs/lzma-linux-arm-gnueabihf': 1.5.1 - '@napi-rs/lzma-linux-arm64-gnu': 1.5.1 - '@napi-rs/lzma-linux-arm64-musl': 1.5.1 - '@napi-rs/lzma-linux-ppc64-gnu': 1.5.1 - '@napi-rs/lzma-linux-riscv64-gnu': 1.5.1 - '@napi-rs/lzma-linux-s390x-gnu': 1.5.1 - '@napi-rs/lzma-linux-x64-gnu': 1.5.1 - '@napi-rs/lzma-linux-x64-musl': 1.5.1 - '@napi-rs/lzma-wasm32-wasi': 1.5.1 - '@napi-rs/lzma-win32-arm64-msvc': 1.5.1 - '@napi-rs/lzma-win32-ia32-msvc': 1.5.1 - '@napi-rs/lzma-win32-x64-msvc': 1.5.1 - - '@napi-rs/tar-android-arm-eabi@1.1.1': + '@napi-rs/lzma-android-arm-eabi': 1.5.3 + '@napi-rs/lzma-android-arm64': 1.5.3 + '@napi-rs/lzma-darwin-arm64': 1.5.3 + '@napi-rs/lzma-darwin-x64': 1.5.3 + '@napi-rs/lzma-freebsd-x64': 1.5.3 + '@napi-rs/lzma-linux-arm-gnueabihf': 1.5.3 + '@napi-rs/lzma-linux-arm64-gnu': 1.5.3 + '@napi-rs/lzma-linux-arm64-musl': 1.5.3 + '@napi-rs/lzma-linux-ppc64-gnu': 1.5.3 + '@napi-rs/lzma-linux-riscv64-gnu': 1.5.3 + '@napi-rs/lzma-linux-s390x-gnu': 1.5.3 + '@napi-rs/lzma-linux-x64-gnu': 1.5.3 + '@napi-rs/lzma-linux-x64-musl': 1.5.3 + '@napi-rs/lzma-wasm32-wasi': 1.5.3 + '@napi-rs/lzma-win32-arm64-msvc': 1.5.3 + '@napi-rs/lzma-win32-ia32-msvc': 1.5.3 + '@napi-rs/lzma-win32-x64-msvc': 1.5.3 + + '@napi-rs/tar-android-arm-eabi@1.1.3': optional: true - '@napi-rs/tar-android-arm64@1.1.1': + '@napi-rs/tar-android-arm64@1.1.3': optional: true - '@napi-rs/tar-darwin-arm64@1.1.1': + '@napi-rs/tar-darwin-arm64@1.1.3': optional: true - '@napi-rs/tar-darwin-x64@1.1.1': + '@napi-rs/tar-darwin-x64@1.1.3': optional: true - '@napi-rs/tar-freebsd-x64@1.1.1': + '@napi-rs/tar-freebsd-x64@1.1.3': optional: true - '@napi-rs/tar-linux-arm-gnueabihf@1.1.1': + '@napi-rs/tar-linux-arm-gnueabihf@1.1.3': optional: true - '@napi-rs/tar-linux-arm64-gnu@1.1.1': + '@napi-rs/tar-linux-arm64-gnu@1.1.3': optional: true - '@napi-rs/tar-linux-arm64-musl@1.1.1': + '@napi-rs/tar-linux-arm64-musl@1.1.3': optional: true - '@napi-rs/tar-linux-ppc64-gnu@1.1.1': + '@napi-rs/tar-linux-ppc64-gnu@1.1.3': optional: true - '@napi-rs/tar-linux-s390x-gnu@1.1.1': + '@napi-rs/tar-linux-s390x-gnu@1.1.3': optional: true - '@napi-rs/tar-linux-x64-gnu@1.1.1': + '@napi-rs/tar-linux-x64-gnu@1.1.3': optional: true - '@napi-rs/tar-linux-x64-musl@1.1.1': + '@napi-rs/tar-linux-x64-musl@1.1.3': optional: true - '@napi-rs/tar-wasm32-wasi@1.1.1': + '@napi-rs/tar-wasm32-wasi@1.1.3': dependencies: - '@emnapi/core': 1.11.2 - '@emnapi/runtime': 1.11.2 - '@napi-rs/wasm-runtime': 1.2.6(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@emnapi/core': 2.0.0-beta.3 + '@emnapi/runtime': 2.0.0-beta.3 + '@napi-rs/wasm-runtime': 1.2.7(@emnapi/core@2.0.0-beta.3)(@emnapi/runtime@2.0.0-beta.3) optional: true - '@napi-rs/tar-win32-arm64-msvc@1.1.1': + '@napi-rs/tar-win32-arm64-msvc@1.1.3': optional: true - '@napi-rs/tar-win32-ia32-msvc@1.1.1': + '@napi-rs/tar-win32-ia32-msvc@1.1.3': optional: true - '@napi-rs/tar-win32-x64-msvc@1.1.1': + '@napi-rs/tar-win32-x64-msvc@1.1.3': optional: true - '@napi-rs/tar@1.1.1': + '@napi-rs/tar@1.1.3': optionalDependencies: - '@napi-rs/tar-android-arm-eabi': 1.1.1 - '@napi-rs/tar-android-arm64': 1.1.1 - '@napi-rs/tar-darwin-arm64': 1.1.1 - '@napi-rs/tar-darwin-x64': 1.1.1 - '@napi-rs/tar-freebsd-x64': 1.1.1 - '@napi-rs/tar-linux-arm-gnueabihf': 1.1.1 - '@napi-rs/tar-linux-arm64-gnu': 1.1.1 - '@napi-rs/tar-linux-arm64-musl': 1.1.1 - '@napi-rs/tar-linux-ppc64-gnu': 1.1.1 - '@napi-rs/tar-linux-s390x-gnu': 1.1.1 - '@napi-rs/tar-linux-x64-gnu': 1.1.1 - '@napi-rs/tar-linux-x64-musl': 1.1.1 - '@napi-rs/tar-wasm32-wasi': 1.1.1 - '@napi-rs/tar-win32-arm64-msvc': 1.1.1 - '@napi-rs/tar-win32-ia32-msvc': 1.1.1 - '@napi-rs/tar-win32-x64-msvc': 1.1.1 - - '@napi-rs/wasm-runtime@1.2.6(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': - dependencies: - '@emnapi/core': 1.11.2 - '@emnapi/runtime': 1.11.2 + '@napi-rs/tar-android-arm-eabi': 1.1.3 + '@napi-rs/tar-android-arm64': 1.1.3 + '@napi-rs/tar-darwin-arm64': 1.1.3 + '@napi-rs/tar-darwin-x64': 1.1.3 + '@napi-rs/tar-freebsd-x64': 1.1.3 + '@napi-rs/tar-linux-arm-gnueabihf': 1.1.3 + '@napi-rs/tar-linux-arm64-gnu': 1.1.3 + '@napi-rs/tar-linux-arm64-musl': 1.1.3 + '@napi-rs/tar-linux-ppc64-gnu': 1.1.3 + '@napi-rs/tar-linux-s390x-gnu': 1.1.3 + '@napi-rs/tar-linux-x64-gnu': 1.1.3 + '@napi-rs/tar-linux-x64-musl': 1.1.3 + '@napi-rs/tar-wasm32-wasi': 1.1.3 + '@napi-rs/tar-win32-arm64-msvc': 1.1.3 + '@napi-rs/tar-win32-ia32-msvc': 1.1.3 + '@napi-rs/tar-win32-x64-msvc': 1.1.3 + + '@napi-rs/wasm-runtime@1.2.7(@emnapi/core@2.0.0-beta.3)(@emnapi/runtime@2.0.0-beta.3)': + dependencies: + '@emnapi/core': 2.0.0-beta.3 + '@emnapi/runtime': 2.0.0-beta.3 '@tybys/wasm-util': 0.10.4 optional: true - '@napi-rs/wasm-runtime@1.2.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': - dependencies: - '@emnapi/core': 1.9.2 - '@emnapi/runtime': 1.9.2 - '@tybys/wasm-util': 0.10.4 - optional: true - - '@napi-rs/wasm-tools-android-arm-eabi@1.1.0': + '@napi-rs/wasm-tools-android-arm-eabi@1.1.2': optional: true - '@napi-rs/wasm-tools-android-arm64@1.1.0': + '@napi-rs/wasm-tools-android-arm64@1.1.2': optional: true - '@napi-rs/wasm-tools-darwin-arm64@1.1.0': + '@napi-rs/wasm-tools-darwin-arm64@1.1.2': optional: true - '@napi-rs/wasm-tools-darwin-x64@1.1.0': + '@napi-rs/wasm-tools-darwin-x64@1.1.2': optional: true - '@napi-rs/wasm-tools-freebsd-x64@1.1.0': + '@napi-rs/wasm-tools-freebsd-x64@1.1.2': optional: true - '@napi-rs/wasm-tools-linux-arm64-gnu@1.1.0': + '@napi-rs/wasm-tools-linux-arm64-gnu@1.1.2': optional: true - '@napi-rs/wasm-tools-linux-arm64-musl@1.1.0': + '@napi-rs/wasm-tools-linux-arm64-musl@1.1.2': optional: true - '@napi-rs/wasm-tools-linux-x64-gnu@1.1.0': + '@napi-rs/wasm-tools-linux-x64-gnu@1.1.2': optional: true - '@napi-rs/wasm-tools-linux-x64-musl@1.1.0': + '@napi-rs/wasm-tools-linux-x64-musl@1.1.2': optional: true - '@napi-rs/wasm-tools-wasm32-wasi@1.1.0': + '@napi-rs/wasm-tools-wasm32-wasi@1.1.2': dependencies: - '@emnapi/core': 1.9.2 - '@emnapi/runtime': 1.9.2 - '@napi-rs/wasm-runtime': 1.2.6(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + '@emnapi/core': 2.0.0-beta.3 + '@emnapi/runtime': 2.0.0-beta.3 + '@napi-rs/wasm-runtime': 1.2.7(@emnapi/core@2.0.0-beta.3)(@emnapi/runtime@2.0.0-beta.3) optional: true - '@napi-rs/wasm-tools-win32-arm64-msvc@1.1.0': + '@napi-rs/wasm-tools-win32-arm64-msvc@1.1.2': optional: true - '@napi-rs/wasm-tools-win32-ia32-msvc@1.1.0': + '@napi-rs/wasm-tools-win32-ia32-msvc@1.1.2': optional: true - '@napi-rs/wasm-tools-win32-x64-msvc@1.1.0': + '@napi-rs/wasm-tools-win32-x64-msvc@1.1.2': optional: true - '@napi-rs/wasm-tools@1.1.0': + '@napi-rs/wasm-tools@1.1.2': optionalDependencies: - '@napi-rs/wasm-tools-android-arm-eabi': 1.1.0 - '@napi-rs/wasm-tools-android-arm64': 1.1.0 - '@napi-rs/wasm-tools-darwin-arm64': 1.1.0 - '@napi-rs/wasm-tools-darwin-x64': 1.1.0 - '@napi-rs/wasm-tools-freebsd-x64': 1.1.0 - '@napi-rs/wasm-tools-linux-arm64-gnu': 1.1.0 - '@napi-rs/wasm-tools-linux-arm64-musl': 1.1.0 - '@napi-rs/wasm-tools-linux-x64-gnu': 1.1.0 - '@napi-rs/wasm-tools-linux-x64-musl': 1.1.0 - '@napi-rs/wasm-tools-wasm32-wasi': 1.1.0 - '@napi-rs/wasm-tools-win32-arm64-msvc': 1.1.0 - '@napi-rs/wasm-tools-win32-ia32-msvc': 1.1.0 - '@napi-rs/wasm-tools-win32-x64-msvc': 1.1.0 + '@napi-rs/wasm-tools-android-arm-eabi': 1.1.2 + '@napi-rs/wasm-tools-android-arm64': 1.1.2 + '@napi-rs/wasm-tools-darwin-arm64': 1.1.2 + '@napi-rs/wasm-tools-darwin-x64': 1.1.2 + '@napi-rs/wasm-tools-freebsd-x64': 1.1.2 + '@napi-rs/wasm-tools-linux-arm64-gnu': 1.1.2 + '@napi-rs/wasm-tools-linux-arm64-musl': 1.1.2 + '@napi-rs/wasm-tools-linux-x64-gnu': 1.1.2 + '@napi-rs/wasm-tools-linux-x64-musl': 1.1.2 + '@napi-rs/wasm-tools-wasm32-wasi': 1.1.2 + '@napi-rs/wasm-tools-win32-arm64-msvc': 1.1.2 + '@napi-rs/wasm-tools-win32-ia32-msvc': 1.1.2 + '@napi-rs/wasm-tools-win32-x64-msvc': 1.1.2 '@octokit/auth-token@6.0.0': {} @@ -3356,7 +3339,7 @@ snapshots: '@typescript-eslint/eslint-plugin@8.72.1(@typescript-eslint/parser@8.72.1(@typescript/typescript6@6.0.2)(eslint@10.14.0))(@typescript/typescript6@6.0.2)(eslint@10.14.0)': dependencies: - '@eslint-community/regexpp': 4.12.2 + '@eslint-community/regexpp': 4.12.3 '@typescript-eslint/parser': 8.72.1(@typescript/typescript6@6.0.2)(eslint@10.14.0) '@typescript-eslint/scope-manager': 8.72.1 '@typescript-eslint/type-utils': 8.72.1(@typescript/typescript6@6.0.2)(eslint@10.14.0) @@ -3422,7 +3405,7 @@ snapshots: '@typescript-eslint/visitor-keys': 8.72.1 debug: 4.4.3 minimatch: 10.2.6 - semver: 7.8.5 + semver: 7.8.6 tinyglobby: 0.2.17 ts-api-utils: 2.5.0(@typescript/typescript6@6.0.2) typescript: '@typescript/typescript6@6.0.2' @@ -3509,12 +3492,13 @@ snapshots: dependencies: '@typescript/old': typescript@6.0.3 - '@typespec/ts-http-runtime@0.3.9': + '@typespec/ts-http-runtime@0.3.10': dependencies: - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 + http-proxy-agent: 9.1.0 + https-proxy-agent: 9.1.0 tslib: 2.9.1 transitivePeerDependencies: + - kerberos - supports-color '@vscode/vsce-sign-alpine-arm64@2.0.6': @@ -3571,13 +3555,13 @@ snapshots: commander: 12.1.0 hosted-git-info: 4.1.0 jsonc-parser: 3.3.1 - marked: 18.1.2 + marked: 18.1.3 mime: 1.6.0 minimatch: 10.2.6 - parse5: 8.0.1 + parse5: 8.1.1 proper-lockfile: 4.1.2 read: 1.0.7 - semver: 7.8.5 + semver: 7.8.6 tinyglobby: 0.2.17 typed-rest-client: 1.8.11 url-join: 4.0.1 @@ -3585,6 +3569,7 @@ snapshots: yauzl: 3.4.0 yazl: 2.5.1 transitivePeerDependencies: + - kerberos - supports-color acorn-jsx@5.3.2(acorn@8.19.0): @@ -3593,7 +3578,7 @@ snapshots: acorn@8.19.0: {} - agent-base@7.1.4: {} + agent-base@9.0.0: {} ajv@6.15.0: dependencies: @@ -3692,7 +3677,7 @@ snapshots: buffer-equal-constant-time@1.0.1: {} - bufferutil@4.1.0: + bufferutil@4.2.0: dependencies: node-gyp-build: 4.8.4 optional: true @@ -3819,7 +3804,7 @@ snapshots: dependencies: version-range: 4.15.0 - entities@8.1.0: {} + entities@9.0.0: {} es-abstract-get@1.0.0: dependencies: @@ -3913,7 +3898,7 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - es-toolkit@1.53.1: {} + es-toolkit@1.53.2: {} esbuild@0.28.2: optionalDependencies: @@ -3955,7 +3940,7 @@ snapshots: eslint-import-resolver-node@0.3.10: dependencies: debug: 3.2.7 - is-core-module: 2.17.0 + is-core-module: 2.18.0 resolve: 2.0.0-next.7 transitivePeerDependencies: - supports-color @@ -3989,13 +3974,13 @@ snapshots: eslint-import-resolver-node: 0.3.10 eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.72.1(@typescript/typescript6@6.0.2)(eslint@10.14.0))(eslint-import-resolver-node@0.3.10)(eslint@10.14.0) hasown: 2.0.4 - is-core-module: 2.17.0 + is-core-module: 2.18.0 is-glob: 4.0.3 minimatch: 3.1.5 object.fromentries: 2.0.8 object.groupby: 1.0.3 object.values: 1.2.1 - semver: 6.3.1 + semver: 6.3.2 string.prototype.trimend: 1.0.10 tsconfig-paths: 3.15.0 optionalDependencies: @@ -4012,8 +3997,8 @@ snapshots: eslint-utils: 2.1.0 ignore: 5.3.2 minimatch: 3.1.5 - resolve: 1.22.13 - semver: 6.3.1 + resolve: 1.22.14 + semver: 6.3.2 eslint-plugin-prettier@5.5.7(eslint-config-prettier@10.1.8(eslint@10.14.0))(eslint@10.14.0)(prettier@3.9.10): dependencies: @@ -4044,7 +4029,7 @@ snapshots: eslint@10.14.0: dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@10.14.0) - '@eslint-community/regexpp': 4.12.2 + '@eslint-community/regexpp': 4.12.3 '@eslint/config-array': 0.23.5 '@eslint/config-helpers': 0.7.0 '@eslint/core': 1.2.1 @@ -4224,18 +4209,22 @@ snapshots: dependencies: lru-cache: 6.0.0 - http-proxy-agent@7.0.2: + http-proxy-agent@9.1.0: dependencies: - agent-base: 7.1.4 + agent-base: 9.0.0 debug: 4.4.3 + proxy-agent-negotiate: 1.1.0 transitivePeerDependencies: + - kerberos - supports-color - https-proxy-agent@7.0.6: + https-proxy-agent@9.1.0: dependencies: - agent-base: 7.1.4 + agent-base: 9.0.0 debug: 4.4.3 + proxy-agent-negotiate: 1.1.0 transitivePeerDependencies: + - kerberos - supports-color iconv-lite@0.7.3: @@ -4279,7 +4268,7 @@ snapshots: is-callable@1.2.7: {} - is-core-module@2.17.0: + is-core-module@2.18.0: dependencies: hasown: 2.0.4 @@ -4417,7 +4406,7 @@ snapshots: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 7.8.5 + semver: 7.8.6 jwa@2.0.1: dependencies: @@ -4461,7 +4450,7 @@ snapshots: dependencies: yallist: 4.0.0 - marked@18.1.2: {} + marked@18.1.3: {} math-intrinsics@1.1.0: {} @@ -4492,7 +4481,7 @@ snapshots: array.prototype.flatmap: 1.3.3 es-errors: 1.3.0 object.entries: 1.1.9 - semver: 6.3.1 + semver: 6.3.2 node-gyp-build@4.8.4: optional: true @@ -4585,9 +4574,9 @@ snapshots: dependencies: p-limit: 3.1.0 - parse5@8.0.1: + parse5@8.1.1: dependencies: - entities: 8.1.0 + entities: 9.0.0 path-exists@4.0.0: {} @@ -4619,6 +4608,8 @@ snapshots: retry: 0.12.0 signal-exit: 3.0.7 + proxy-agent-negotiate@1.1.0: {} + punycode@2.3.1: {} qified@0.10.1: @@ -4661,17 +4652,17 @@ snapshots: regexpp@3.2.0: {} - resolve@1.22.13: + resolve@1.22.14: dependencies: es-errors: 1.3.0 - is-core-module: 2.17.0 + is-core-module: 2.18.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 resolve@2.0.0-next.7: dependencies: es-errors: 1.3.0 - is-core-module: 2.17.0 + is-core-module: 2.18.0 node-exports-info: 1.6.2 object-keys: 1.1.1 path-parse: 1.0.7 @@ -4706,9 +4697,9 @@ snapshots: sax@1.6.1: {} - semver@6.3.1: {} + semver@6.3.2: {} - semver@7.8.5: {} + semver@7.8.6: {} set-function-length@1.2.2: dependencies: diff --git a/extensions/standalone/src/main.rs b/extensions/standalone/src/main.rs index 77bc7e1d..1dba9da6 100644 --- a/extensions/standalone/src/main.rs +++ b/extensions/standalone/src/main.rs @@ -16,8 +16,8 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // // Relax a few pedantic Clippy lints for test code only; see the -// `[lints.clippy]` section in `Cargo.toml` for the full-crate (production) lint -// config. +// `[workspace.lints.clippy]` section in `Cargo.toml` for the full-crate +// (production) lint config. #![cfg_attr( test, allow( diff --git a/server/Cargo.toml b/server/Cargo.toml index cab06685..ca5f4865 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -51,20 +51,20 @@ actix-ws = "0.4" ammonia = "4.1.2" bytes = { version = "1", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] } -dprint-plugin-markdown = { git = "https://github.com/bjones1/dprint-plugin-markdown.git", branch = "all-fixes" } +dprint-plugin-markdown = "0.29" dunce = "1.0.5" futures-util = "0.3.29" htmd = { git = "https://github.com/bjones1/htmd.git", branch = "dom-interface", version = "0.5" } # This must match the version of `markup5ever_rcdom`. -html5ever = "0.39" -htmlize = "1.0.6" +html5ever = "0.40" +htmlize = { version = "1.0.6", features = ["unescape"] } ignore = "0.4" imara-diff = { version = "0.2", features = [] } indoc = "2.0.5" log.workspace = true log4rs = "1.3" lru = "0.19" -markup5ever_rcdom = "0.39" +markup5ever_rcdom = "0.40" mime = "0.3.17" mime_guess = "2.0.5" minify-html = { git = "https://github.com/bjones1/minify-html.git", branch = "dev", version = "0.18.1" } diff --git a/server/src/ide/vscode/tests.rs b/server/src/ide/vscode/tests.rs index 9c6fe661..5cf34a20 100644 --- a/server/src/ide/vscode/tests.rs +++ b/server/src/ide/vscode/tests.rs @@ -21,12 +21,12 @@ use std::{ env, fs::{self, File}, - io::{Error, Read}, + io::Read, net::SocketAddr, path::{self, Path, PathBuf}, sync::LazyLock, - thread::{self, JoinHandle}, - time::{Duration, SystemTime}, + thread, + time::Duration, }; use assert_fs::TempDir; @@ -54,7 +54,7 @@ use crate::webserver::{ use crate::{ ide::vscode::VscodeRoutes, translation::{EolType, find_eol_type}, - webserver::{LifecycleRoutes, main, test_root_path}, + webserver::{init_server, setup_server, test_root_path}, }; use crate::{ processing::{ @@ -71,26 +71,29 @@ use test_utils::{ // Globals // ------- // -// Run a single webserver for all tests. -static WEBSERVER_HANDLE: LazyLock>> = LazyLock::new(|| { +// Start a webserver shared by all tests in this process; this is the port it +// listens on. Bind to an OS-assigned port, so these tests don't collide with +// anything else holding a fixed port (a running CodeChat Editor, or another +// test process under `cargo nextest`). The port is bound before this returns, +// so the OS queues connections until the server begins accepting them; tests +// needn't wait for it to start. +static IP_PORT: LazyLock = LazyLock::new(|| { + init_server(&test_root_path(), log::LevelFilter::Debug).unwrap(); + let (server, app_state) = setup_server( + // A port of 0 requests the OS to assign an open port. + &SocketAddr::new("127.0.0.1".parse().unwrap(), 0), + None, + VscodeRoutes, + ) + .expect("Unable to start the test webserver."); thread::spawn(|| { - main( - &test_root_path(), - &SocketAddr::new("127.0.0.1".parse().unwrap(), IP_PORT), - None, - log::LevelFilter::Debug, - (VscodeRoutes, LifecycleRoutes), - ) - }) + actix_web::rt::System::new() + .block_on(server) + .expect("The test webserver failed."); + }); + *app_state.port.lock().unwrap() }); -// Constants -// --------- -/// The default port on which the server listens for incoming connections. -pub const IP_PORT: u16 = 8080; -/// Allow slower CI runners enough time to start the shared test webserver. -const WEBSERVER_START_TIMEOUT: Duration = Duration::from_secs(6); - // Support functions // ----------------- /// Send a message via a websocket. @@ -138,10 +141,13 @@ async fn read_message( type WebSocketStreamTcp = WebSocketStream>; async fn connect_async_server(prefix: &str, connection_id: &str) -> WebSocketStreamTcp { - connect_async(format!("ws://127.0.0.1:{IP_PORT}{prefix}/{connection_id}")) - .await - .expect("Failed to connect") - .0 + connect_async(format!( + "ws://127.0.0.1:{}{prefix}/{connection_id}", + *IP_PORT + )) + .await + .expect("Failed to connect") + .0 } async fn connect_async_ide(connection_id: &str) -> WebSocketStreamTcp { @@ -208,22 +214,6 @@ async fn prep_test_core( ) -> (TempDir, PathBuf, WebSocketStreamTcp, WebSocketStreamTcp) { configure_testing_logger(); let (temp_dir, test_dir) = prep_test_dir_impl(test_full_name); - // Ensure the webserver is running. - let _ = &*WEBSERVER_HANDLE; - let now = SystemTime::now(); - let mut started = false; - while now.elapsed().unwrap() < WEBSERVER_START_TIMEOUT { - if minreq::get(format!("http://127.0.0.1:{IP_PORT}/ping")) - .send() - .is_ok_and(|response| response.as_bytes() == b"pong") - { - started = true; - break; - } - sleep(Duration::from_millis(10)).await; - } - - assert!(started, "Webserver failed to start."); // Connect to the VSCode IDE websocket. let ws_ide = connect_async_ide(connection_id).await; @@ -253,7 +243,8 @@ async fn test_vscode_ide_websocket1() { // Start a second connection; verify that it fails. let err = connect_async(format!( - "ws://127.0.0.1:{IP_PORT}/vsc/ws-ide/{connection_id}", + "ws://127.0.0.1:{}/vsc/ws-ide/{connection_id}", + *IP_PORT, )) .await .expect_err("Should fail to connect"); @@ -351,7 +342,8 @@ async fn test_vscode_ide_websocket3() { let join_handle = thread::spawn(move || { assert_eq!( minreq::get(format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{file_path_str_thread}", + "http://localhost:{}/vsc/fs/{connection_id}/{file_path_str_thread}", + *IP_PORT, )) .send() .unwrap() @@ -414,7 +406,8 @@ async fn test_vscode_ide_websocket3a() { let join_handle = thread::spawn(move || { assert_eq!( minreq::get(format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{file_path_str_thread}", + "http://localhost:{}/vsc/fs/{connection_id}/{file_path_str_thread}", + *IP_PORT, )) .send() .unwrap() @@ -508,7 +501,8 @@ async fn test_vscode_ide_websocket8() { let join_handle = thread::spawn(move || { assert_eq!( minreq::get(format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}", + "http://localhost:{}/vsc/fs/{connection_id}/{}", + *IP_PORT, drop_leading_slash(&file_path_thread.to_slash().unwrap()) )) .send() @@ -617,7 +611,8 @@ async fn test_vscode_ide_websocket7() { id: INITIAL_CLIENT_MESSAGE_ID, message: EditorMessageContents::CurrentFile( format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}", + "http://localhost:{}/vsc/fs/{connection_id}/{}", + *IP_PORT, file_path.to_slash().unwrap(), ), None, @@ -809,6 +804,312 @@ async fn test_vscode_ide_websocket7() { temp_dir.close().unwrap(); } +/// Send an `Update` message from the IDE containing the given source code. +async fn send_ide_update( + // The websocket to send this on. + ws_ide: &mut WebSocketStream, + // The id of this message. + id: f64, + // The file this message updates. + file_path: &str, + // The source code. + doc: &str, + // The version of this source code. + version: f64, +) { + send_message( + ws_ide, + &EditorMessage { + id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: file_path.to_string(), + cursor_position: None, + scroll_position: None, + is_re_translation: false, + contents: Some(CodeChatForWeb { + metadata: SourceFileMetadata { + mode: "python".to_string(), + }, + source: CodeMirrorDiffable::Plain(CodeMirror { + doc: doc.to_string(), + doc_blocks: vec![], + }), + version, + }), + }), + }, + ) + .await; +} + +/// Send the Client's edit of a Python file which replaces it with a single doc +/// block containing "edited". +async fn send_client_edit( + // The websocket to send this on. + ws_client: &mut WebSocketStream, + // The id of this message. + id: f64, + // The file this message updates. + file_path: &str, + // The version of the edited file. + version: f64, +) { + send_message( + ws_client, + &EditorMessage { + id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: file_path.to_string(), + cursor_position: None, + scroll_position: None, + is_re_translation: false, + contents: Some(CodeChatForWeb { + metadata: SourceFileMetadata { + mode: "python".to_string(), + }, + source: CodeMirrorDiffable::Plain(CodeMirror { + doc: "\n".to_string(), + doc_blocks: vec![CodeMirrorDocBlock { + from: 0, + to: 1, + indent: String::new(), + delimiter: "#".to_string(), + contents: "

edited".to_string(), + }], + }), + version, + }), + }), + }, + ) + .await; +} + +/// Send a success response on one websocket, then check that the Server +/// forwards it to the other. +async fn send_and_check_result( + // The websocket which sends the response. + ws_from: &mut WebSocketStream, + // The websocket which receives the response. + ws_to: &mut WebSocketStream, + // The id of the message this responds to. + id: f64, +) { + let result = EditorMessage { + id, + message: EditorMessageContents::Result(Ok(ResultOkTypes::Void)), + }; + send_message(ws_from, &result).await; + assert_eq!(read_message(ws_to).await, result); +} + +/// Verify that source from the IDE which can't be translated produces one error +/// for the Client and leaves it on the last source which could be: the next +/// update which translates is a diff against that source, and an edit from the +/// Client doesn't replace the IDE's newer source. +#[actix_web::test] +async fn test_vscode_ide_websocket13() { + let connection_id = "test-connection-id13"; + let (temp_dir, test_dir, mut ws_ide, mut ws_client) = prep_test!(connection_id).await; + open_client(&mut ws_ide).await; + + // A lexer directive naming an unknown lexer can't be translated. Obscure + // this, so that this file can be successfully lexed by the CodeChat Editor. + let untranslatable = concat!("# CodeChat Editor ", "lexer: nope\ncode\n# most"); + let translation_error = "unknown lexer nope".to_string(); + + // Set the current file, so subsequent `Update` messages can be translated. + let file_path = test_dir.join("test.py"); + let file_path_str = file_path.to_str().unwrap().to_string(); + send_message( + &mut ws_client, + &EditorMessage { + id: INITIAL_CLIENT_MESSAGE_ID, + message: EditorMessageContents::CurrentFile( + format!( + "http://localhost:{}/vsc/fs/{connection_id}/{}", + *IP_PORT, + file_path.to_slash().unwrap(), + ), + None, + ), + }, + ) + .await; + let em = read_message(&mut ws_ide).await; + cast!( + em.message, + EditorMessageContents::CurrentFile, + file_name, + is_text + ); + send_and_check_result(&mut ws_ide, &mut ws_client, INITIAL_CLIENT_MESSAGE_ID).await; + + // Give the Client its first translation. + let mut ide_id = INITIAL_IDE_MESSAGE_ID; + send_ide_update(&mut ws_ide, ide_id, &file_path_str, "# more", 0.0).await; + let em = read_message(&mut ws_client).await; + cast!(em.message, EditorMessageContents::Update); + send_and_check_result(&mut ws_client, &mut ws_ide, ide_id).await; + + // The Client, but not the IDE, learns of an update which can't be + // translated. + let ide_success = |id| EditorMessage { + id, + message: EditorMessageContents::Result(Ok(ResultOkTypes::Void)), + }; + let client_error = |id| EditorMessage { + id, + message: EditorMessageContents::Result(Err(ResultErrTypes::CannotTranslateSource( + translation_error.clone(), + ))), + }; + ide_id += MESSAGE_ID_INCREMENT; + send_ide_update(&mut ws_ide, ide_id, &file_path_str, untranslatable, 1.0).await; + assert_eq!(read_message(&mut ws_ide).await, ide_success(ide_id)); + assert_eq!(read_message(&mut ws_client).await, client_error(ide_id)); + + // The same error isn't reported to the Client again. If it were, then the + // next read from `ws_client` below would fail, since it would return this + // error. + ide_id += MESSAGE_ID_INCREMENT; + send_ide_update(&mut ws_ide, ide_id, &file_path_str, untranslatable, 1.5).await; + assert_eq!(read_message(&mut ws_ide).await, ide_success(ide_id)); + + // The next update which translates is a diff against the Client's version. + ide_id += MESSAGE_ID_INCREMENT; + send_ide_update( + &mut ws_ide, + ide_id, + &file_path_str, + "# more\ncode\n# most", + 2.0, + ) + .await; + assert_eq!( + read_message(&mut ws_client).await, + EditorMessage { + id: ide_id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: file_path_str.clone(), + cursor_position: None, + scroll_position: None, + is_re_translation: false, + contents: Some(CodeChatForWeb { + metadata: SourceFileMetadata { + mode: "python".to_string(), + }, + source: CodeMirrorDiffable::Diff(CodeMirrorDiff { + doc: vec![StringDiff { + from: 1, + to: None, + insert: "code\n\n".to_string() + }], + doc_blocks: vec![CodeMirrorDocBlockTransaction::Add(CodeMirrorDocBlock { + from: 6, + to: 7, + indent: String::new(), + delimiter: "#".to_string(), + contents: "

most".to_string(), + })], + version: 0.0, + }), + version: 2.0, + }), + }), + } + ); + send_and_check_result(&mut ws_client, &mut ws_ide, ide_id).await; + + // Fail again, so that the IDE holds source newer than the Client's. Since + // the last update translated, this reports the error to the Client again. + ide_id += MESSAGE_ID_INCREMENT; + send_ide_update(&mut ws_ide, ide_id, &file_path_str, untranslatable, 3.0).await; + assert_eq!(read_message(&mut ws_ide).await, ide_success(ide_id)); + assert_eq!(read_message(&mut ws_client).await, client_error(ide_id)); + + // The Client can still report its cursor position ... + let mut client_id = INITIAL_CLIENT_MESSAGE_ID + MESSAGE_ID_INCREMENT; + send_message( + &mut ws_client, + &EditorMessage { + id: client_id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: file_path_str.clone(), + cursor_position: None, + scroll_position: None, + is_re_translation: false, + contents: None, + }), + }, + ) + .await; + let em = read_message(&mut ws_ide).await; + assert_eq!(em.id, client_id); + cast!(em.message, EditorMessageContents::Update); + send_and_check_result(&mut ws_ide, &mut ws_client, client_id).await; + + // ... but its edits are rejected. If one reached the IDE, then the next + // read from `ws_ide` below would fail, since it would return this edit. + client_id += MESSAGE_ID_INCREMENT; + send_client_edit(&mut ws_client, client_id, &file_path_str, 4.0).await; + assert_eq!( + read_message(&mut ws_client).await, + EditorMessage { + id: client_id, + message: EditorMessageContents::Result(Err(ResultErrTypes::IgnoredClientEdit( + translation_error.clone() + ))), + } + ); + + // The Client now holds text which the Server doesn't, so the next update + // which translates contains the full text. + ide_id += MESSAGE_ID_INCREMENT; + send_ide_update(&mut ws_ide, ide_id, &file_path_str, "# newest", 5.0).await; + assert_eq!( + read_message(&mut ws_client).await, + EditorMessage { + id: ide_id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: file_path_str.clone(), + cursor_position: None, + scroll_position: None, + is_re_translation: false, + contents: Some(CodeChatForWeb { + metadata: SourceFileMetadata { + mode: "python".to_string(), + }, + source: CodeMirrorDiffable::Plain(CodeMirror { + doc: "\n".to_string(), + doc_blocks: vec![CodeMirrorDocBlock { + from: 0, + to: 1, + indent: String::new(), + delimiter: "#".to_string(), + contents: "

newest".to_string(), + }], + }), + version: 5.0, + }), + }), + } + ); + send_and_check_result(&mut ws_client, &mut ws_ide, ide_id).await; + + // With the IDE's source translating again, edits from the Client reach it. + client_id += MESSAGE_ID_INCREMENT; + send_client_edit(&mut ws_client, client_id, &file_path_str, 6.0).await; + let em = read_message(&mut ws_ide).await; + assert_eq!(em.id, client_id); + cast!(em.message, EditorMessageContents::Update); + send_and_check_result(&mut ws_ide, &mut ws_client, client_id).await; + + check_logger_errors(0); + // Report any errors produced when removing the temporary directory. + temp_dir.close().unwrap(); +} + /// Send an `Update` message from the Client. #[actix_web::test] async fn test_vscode_ide_websocket6() { @@ -908,7 +1209,8 @@ async fn test_vscode_ide_websocket4() { id: INITIAL_CLIENT_MESSAGE_ID, message: EditorMessageContents::CurrentFile( format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}", + "http://localhost:{}/vsc/fs/{connection_id}/{}", + *IP_PORT, file_path.to_slash().unwrap() ), None, @@ -946,7 +1248,8 @@ async fn test_vscode_ide_websocket4() { // Get the file itself. assert_eq!( minreq::get(format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}/{}", + "http://localhost:{}/vsc/fs/{connection_id}/{}/{}", + *IP_PORT, test_dir_thread.to_slash().unwrap(), // On Windows, send incorrect case for this file; the server // should correct it. @@ -1039,7 +1342,8 @@ async fn test_vscode_ide_websocket4() { let join_handle = thread::spawn(move || { assert_eq!( minreq::get(format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}/toc.md", + "http://localhost:{}/vsc/fs/{connection_id}/{}/toc.md", + *IP_PORT, test_dir_thread.to_slash().unwrap() )) .send() @@ -1173,7 +1477,8 @@ async fn test_vscode_ide_websocket4a() { id: INITIAL_CLIENT_MESSAGE_ID, message: EditorMessageContents::CurrentFile( format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}", + "http://localhost:{}/vsc/fs/{connection_id}/{}", + *IP_PORT, file_path.to_slash().unwrap() ), None, @@ -1216,7 +1521,8 @@ async fn test_vscode_ide_websocket4a() { let join_handle = thread::spawn(move || { // Read the file. let response = minreq::get(format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}/{hw}", + "http://localhost:{}/vsc/fs/{connection_id}/{}/{hw}", + *IP_PORT, test_dir_thread.to_slash().unwrap(), )) .send() @@ -1275,7 +1581,8 @@ async fn test_vscode_ide_websocket4b() { id: INITIAL_CLIENT_MESSAGE_ID, message: EditorMessageContents::CurrentFile( format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}", + "http://localhost:{}/vsc/fs/{connection_id}/{}", + *IP_PORT, file_path.to_slash().unwrap() ), None, @@ -1318,7 +1625,8 @@ async fn test_vscode_ide_websocket4b() { let join_handle = thread::spawn(move || { // Read the file. let response = minreq::get(format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}/{hw}", + "http://localhost:{}/vsc/fs/{connection_id}/{}/{hw}", + *IP_PORT, test_dir_thread.to_slash().unwrap(), )) .send() @@ -1332,7 +1640,8 @@ async fn test_vscode_ide_websocket4b() { // Now, request the PDF as a raw file. let response = minreq::get(format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}/{hw}?raw", + "http://localhost:{}/vsc/fs/{connection_id}/{}/{hw}?raw", + *IP_PORT, test_dir_thread.to_slash().unwrap(), )) .send() @@ -1471,7 +1780,8 @@ async fn test_vscode_ide_websocket10() { id: INITIAL_CLIENT_MESSAGE_ID, message: EditorMessageContents::CurrentFile( format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}", + "http://localhost:{}/vsc/fs/{connection_id}/{}", + *IP_PORT, file_path.to_slash().unwrap() ), None, @@ -1508,7 +1818,8 @@ async fn test_vscode_ide_websocket10() { let join_handle = thread::spawn(move || { assert_eq!( minreq::get(format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}/test.py", + "http://localhost:{}/vsc/fs/{connection_id}/{}/test.py", + *IP_PORT, test_dir_thread.to_slash().unwrap(), )) .send() @@ -1552,7 +1863,7 @@ async fn test_vscode_ide_websocket10() { to: 1, indent: String::new(), delimiter: "#".to_string(), - contents: r#"

See id "foo" not found."#.to_string(), + contents: r#"

See id "foo" not found."#.to_string(), }], }), version: 0.0, @@ -1615,8 +1926,8 @@ async fn test_vscode_ide_websocket10() { delimiter: None, contents: vec![StringDiff { from: 0, - to: Some(97), - insert: "

See Foo.".to_string(), + to: Some(110), + insert: "

See Foo.".to_string(), }], } )], @@ -1680,7 +1991,8 @@ async fn fetch_sidebar_toc( // The body of the response: the page showing the TOC. ) -> String { let url = format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}/toc.md?mode=toc", + "http://localhost:{}/vsc/fs/{connection_id}/{}/toc.md?mode=toc", + *IP_PORT, test_dir.to_slash().unwrap() ); let join_handle = thread::spawn(move || { @@ -1759,7 +2071,8 @@ async fn test_vscode_ide_websocket11() { id: INITIAL_CLIENT_MESSAGE_ID, message: EditorMessageContents::CurrentFile( format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}", + "http://localhost:{}/vsc/fs/{connection_id}/{}", + *IP_PORT, file_path.to_slash().unwrap() ), None, @@ -1793,7 +2106,8 @@ async fn test_vscode_ide_websocket11() { let join_handle = thread::spawn(move || { assert_eq!( minreq::get(format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}/test.py", + "http://localhost:{}/vsc/fs/{connection_id}/{}/test.py", + *IP_PORT, test_dir_thread.to_slash().unwrap(), )) .send() @@ -1854,7 +2168,7 @@ async fn test_vscode_ide_websocket11() { EditorMessage { id: INITIAL_MESSAGE_ID + 4.0 * MESSAGE_ID_INCREMENT, message: EditorMessageContents::UpdateToc( - "

" + "" .to_string() ), } @@ -1897,7 +2211,7 @@ async fn test_vscode_ide_websocket11() { EditorMessage { id: INITIAL_MESSAGE_ID + 6.0 * MESSAGE_ID_INCREMENT, message: EditorMessageContents::UpdateToc( - "" + "" .to_string() ), } @@ -1934,7 +2248,8 @@ async fn test_vscode_ide_websocket12() { id: INITIAL_CLIENT_MESSAGE_ID, message: EditorMessageContents::CurrentFile( format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}", + "http://localhost:{}/vsc/fs/{connection_id}/{}", + *IP_PORT, file_path.to_slash().unwrap() ), None, @@ -1968,7 +2283,8 @@ async fn test_vscode_ide_websocket12() { let join_handle = thread::spawn(move || { assert_eq!( minreq::get(format!( - "http://localhost:{IP_PORT}/vsc/fs/{connection_id}/{}/toc.md", + "http://localhost:{}/vsc/fs/{connection_id}/{}/toc.md", + *IP_PORT, test_dir_thread.to_slash().unwrap(), )) .send() diff --git a/server/src/lib.rs b/server/src/lib.rs index b1261af0..fba030d1 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -2,21 +2,22 @@ // (C) 2024-2026 Bryan A. Jones. // // This file is part of the CodeChat Editor. The CodeChat Editor is free -// software: you can redistribute it and/or modify it under the terms of the -// GNU General Public License as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. +// software: you can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, either +// version 3 of the License, or (at your option) any later version. // // The CodeChat Editor is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -// more details. +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. // // You should have received a copy of the GNU General Public License along with // the CodeChat Editor. If not, see // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // -// Relax a few pedantic Clippy lints for test code only; see the `[lints.clippy]` -// section in `Cargo.toml` for the full-crate (production) lint config. +// Relax a few pedantic Clippy lints for test code only; see the +// `[workspace.lints.clippy]` section in `Cargo.toml` for the full-crate +// (production) lint config. #![cfg_attr( test, allow( diff --git a/server/src/processing.rs b/server/src/processing.rs index 0edbcefc..6c02415d 100644 --- a/server/src/processing.rs +++ b/server/src/processing.rs @@ -59,7 +59,7 @@ use htmd::{ options::{BrStyle, LinkStyle, TranslationMode}, }; use html5ever::{ - Attribute, LocalName, Namespace, ParseOpts, QualName, ns, parse_document, serialize, + Attribute, LocalName, Namespace, ParseOpts, QualName, ns, parse_fragment, serialize, serialize::{SerializeOpts, TraversalScope}, tendril::TendrilSink, tree_builder::TreeBuilderOpts, @@ -268,10 +268,10 @@ static DOC_BLOCK_SEPARATOR_BROKEN_FENCE: LazyLock = LazyLock::new(|| { .unwrap() }); /// After converting Markdown to HTML, this can be used to split doc blocks -/// apart. Since this is post hydration, the element names are normalized to -/// lower case. +/// apart. It ignores case since html5ever normalizes the element names to lower +/// case, while the HTML it parses keeps the case of the separator string. static DOC_BLOCK_SEPARATOR_SPLIT_REGEX: LazyLock = LazyLock::new(|| { - Regex::new(r"\d+").unwrap() + Regex::new(r"(?i)\d+").unwrap() }); /// Match a valid /// [CSS identifier](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/ident), @@ -296,8 +296,12 @@ const DOC_BLOCK_SEPARATOR_STRING: &str = concat!( // the length of the opening code fence, which is hard to find. Since // CommonMark doesn't care if there are multiple HTML start conditions, // abuse this by not closing the fence until the very end of this string. + // The first fence line is doubled because a declaration (item 4) ends at + // the first `>`, which is the end of that line; the second line then begins + // the raw HTML block which hides everything else. r#" + -->?>]]> "#, // Likewise, if there's an unterminated fenced code block with \`\`\` @@ -318,6 +322,7 @@ const DOC_BLOCK_SEPARATOR_STRING: &str = concat!( // Correctly terminated fenced code blocks produce this, which can be removed // from the HTML produced by Markdown conversion. const DOC_BLOCK_SEPARATOR_REMOVE_FENCE: &str = r" + -->?>]]> ``````````````````````` @@ -330,6 +335,9 @@ const DOC_BLOCK_SEPARATOR_REMOVE_FENCE: &str = r" // which it replaces here. const DOC_BLOCK_SEPARATOR_MENDED_FENCE: &str = "\n$1\n"; +// The element `parse_doc_block` appends to a doc block, to discover what an +// unclosed tag does to the text after it. +const DOC_BLOCK_SENTINEL: &str = "codechateditor-sentinel"; // The value of an `id` attribute which requests that the cache assign an id; // see `Auto-assignment of ids` in the cache spec. const AUTO_ID: &str = "*"; @@ -490,14 +498,36 @@ pub fn codechat_for_web_to_source( let html_to_markdown = new_html_to_markdown(); let converter = HtmlToMarkdownWrapped::new(&html_to_markdown); let tree = html_to_dom(&code_mirror.doc, None)?; - dehydrating_walk_node(&tree); + dehydrating_walk_node(&tree)?; return converter .convert(&tree) .map_err(CodechatForWebToSourceError::HtmlToMarkdownFailed); } let code_doc_block_vec_html = code_mirror_to_code_doc_blocks(code_mirror); - let code_doc_block_vec = doc_block_html_to_markdown(code_doc_block_vec_html, None) + let mut code_doc_block_vec = doc_block_html_to_markdown(code_doc_block_vec_html, None) .map_err(CodechatForWebToSourceError::HtmlToMarkdownFailed)?; + // Word wrapping normally supplies the newline ending a doc block, but not + // if its output has no printed width (empty Markdown or only zero-width + // characters) or if a `dprint-ignore-file` comment makes it skip the text. + // Without this newline, the next line of the file joins the comment. Supply + // it here rather than during Markdown conversion, since only the CodeMirror + // document shows whether this newline exists: the document holds it at the + // doc block's `from`, unless the doc block is a comment with no text ending + // a file with no final newline. In this case, `from` lies at the end of the + // document. + let doc_utf16_len = len_utf16(&code_mirror.doc); + let doc_blocks = + code_doc_block_vec + .iter_mut() + .filter_map(|code_doc_block| match code_doc_block { + CodeDocBlock::DocBlock(doc_block) => Some(doc_block), + CodeDocBlock::CodeBlock(_) => None, + }); + for (doc_block, code_mirror_doc_block) in doc_blocks.zip(&code_mirror.doc_blocks) { + if !doc_block.contents.ends_with('\n') && code_mirror_doc_block.from < doc_utf16_len { + doc_block.contents.push('\n'); + } + } code_doc_block_vec_to_source(&code_doc_block_vec, lexer) .map_err(CodechatForWebToSourceError::CannotTranslateCodeChat) } @@ -704,7 +734,7 @@ pub fn doc_block_html_to_markdown( if let CodeDocBlock::DocBlock(doc_block) = code_doc_block { last_doc_block_index = Some(index); let tree = html_to_dom(&doc_block.contents, dom_location)?; - dehydrating_walk_node(&tree); + dehydrating_walk_node(&tree)?; // Calculate the total delimiter width: the delimiter width plus the // extra space after it. Special case: an empty delimiter means @@ -821,6 +851,17 @@ fn code_doc_block_vec_to_source( } }; + // An empty comment has no lines to place the delimiters + // around, so write it directly. + if doc_block.contents.is_empty() || doc_block.contents == "\n" { + append_doc_block( + &doc_block.indent, + &doc_block.delimiter, + &format!("{block_comment_closing_delimiter}{}", doc_block.contents), + ); + continue; + } + // Then, split the contents into a series of lines. Build a // properly-indented block comment around these lines. let content_lines: Vec<&str> = @@ -1044,9 +1085,16 @@ pub fn source_to_codechat_for_web( .replace_all(&html, DOC_BLOCK_SEPARATOR_MENDED_FENCE); // 2. Remove good fences. let html = html.replace(DOC_BLOCK_SEPARATOR_REMOVE_FENCE, ""); - // 3. Hydrate the cleaned HTML: commit this file's facts to the - // cache, then patch cross-references and fragment backlinks. - let (dom, walk_context) = hydrate_dom(&html, file_path, &cache, false) + // 3. Parse the cleaned HTML, then hydrate it: commit this file's + // facts to the cache, then patch cross-references and fragment + // backlinks. + let doc_block_count = code_doc_block_arr + .iter() + .filter(|code_doc_block| matches!(code_doc_block, CodeDocBlock::DocBlock(_))) + .count(); + let dom = doc_blocks_to_dom(&html, doc_block_count) + .map_err(|e| SourceToCodeChatForWebError::ParseFailed(e.to_string()))?; + let (dom, walk_context) = hydrate_dom(dom, file_path, &cache, false) .map_err(|e| SourceToCodeChatForWebError::ParseFailed(e.to_string()))?; // 4. Serialize and split on the separator, giving each doc block's // hydrated HTML -- the form in which fragment contents are @@ -1058,14 +1106,13 @@ pub fn source_to_codechat_for_web( chunk_iter.next(); // Pair the index of each doc block in `code_doc_block_arr` with its // hydrated HTML. - let mut doc_block_html: HashMap = HashMap::new(); - for (index, code_doc_block) in code_doc_block_arr.iter().enumerate() { - if matches!(code_doc_block, CodeDocBlock::DocBlock(_)) - && let Some(chunk) = chunk_iter.next() - { - doc_block_html.insert(index, chunk); - } - } + let doc_block_html: HashMap = code_doc_block_arr + .iter() + .enumerate() + .filter(|(_, code_doc_block)| matches!(code_doc_block, CodeDocBlock::DocBlock(_))) + .map(|(index, _)| index) + .zip(chunk_iter) + .collect(); // 5. Store each fragment's content in the cache, which marks the // files containing gather elements listing changed fragments as // outdated. @@ -1107,6 +1154,9 @@ pub fn source_to_codechat_for_web( delimiter: doc_block.delimiter.clone(), // Used the markdown-translated replacement for this // doc block, rather than the original string. + // `doc_blocks_to_dom` checks that no separators are + // missing and parses each to a top-level node, + // which hydration keeps, so this can't fail. contents: minify(doc_block_contents_iter.next().unwrap())?, }); // Append newlines to the document; the doc block will @@ -1212,7 +1262,7 @@ static AMMONIA_OPTIONS: LazyLock = LazyLock::new(|| { "iframe", &["width", "height", "src", "allowfullscreen", "frameborder"], ) - .add_tag_attributes("xref", &["contenteditable", "ref"]) + .add_tag_attributes("xref", &["contenteditable", "data-content", "ref"]) .add_tag_attributes("fragment", &["contenteditable", "id", "following"]) // Keep HTML comments, which Ammonia strips by default. .strip_comments(false) @@ -1220,44 +1270,60 @@ static AMMONIA_OPTIONS: LazyLock = LazyLock::new(|| { // manually and it should not be stripped without some extra work (perhaps // adding custom attributes?). .link_rel(None); + allow_phrasing_attributes(&mut b); b }); -// Clean HTML for storage as a `Target`'s inner HTML, per the spec in -// `cache.rs`: only the +// Clean HTML which becomes the content of a hydrated link -- a `Target`'s inner +// HTML, or a cross-reference's optional content -- per +// : only the // [permitted content for an `` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a#technical_summary) -// is allowed (phrasing content, excluding interactive content), since this HTML -// becomes the text of a hydrated cross-reference link. Disallowed tags are -// stripped but their text is kept; `id` attributes are stripped because they -// aren't in the allowlist, preventing duplicate ids when the HTML is rendered -// in a referencing file. -static CLEAN_TARGET_HTML: LazyLock = LazyLock::new(|| { +// is allowed. This is a conservative subset of phrasing content which excludes +// interactive content, along with media and other elements not useful in link +// text. It also includes `` and ``, which aren't phrasing content but +// are needed by ``; Ammonia can't limit them to that parent, so a stray +// one remains. Most disallowed tags are stripped but their content is kept, +// which unwraps a nested `` to its own optional content. A ``, +// `