diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 06555318..4974ff66 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -17,7 +17,11 @@ // Install Node.js. "ghcr.io/devcontainers/features/node:latest": {}, // Add the GitHub CLI as a feature (to support the CodeChat Editor). - "ghcr.io/devcontainers/features/github-cli:1": {} + "ghcr.io/devcontainers/features/github-cli:1": {}, + // Include Chrome for browser testing. Note: this installs the binary + // as `/usr/local/bin/chrome`; postCreateCommand.sh symlinks it to + // `google-chrome` so Selenium Manager can find it. + "ghcr.io/kreemer/features/chrometesting:1": {} }, // Run this script after the container is created. "postCreateCommand": "./.devcontainer/postCreateCommand.sh", diff --git a/.devcontainer/postCreateCommand.sh b/.devcontainer/postCreateCommand.sh index cf951753..95b59c62 100755 --- a/.devcontainer/postCreateCommand.sh +++ b/.devcontainer/postCreateCommand.sh @@ -1,5 +1,13 @@ #!/usr/bin/env bash +# The chrometesting feature installs the Chrome binary as +# `/usr/local/bin/chrome`, but `thirtyfour`'s webdriver manager (Selenium +# Manager) only looks for binaries named `google-chrome`, `chromium-browser`, +# or `chromium` on Linux. Symlink it so the browser can be found. +if [ -x /usr/local/bin/chrome ] && [ ! -e /usr/local/bin/google-chrome ]; then + sudo ln -s /usr/local/bin/chrome /usr/local/bin/google-chrome +fi + cd server ./bt install --dev ./bt build \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e774e430..666662c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,24 @@ Changelog * No changes. -Version 0.1.58 -- 2026-Jun-26 +Version 0.1.60 -- 2026-Jul-08 +----------------------------- + +* Fix [#113](https://github.com/bjones1/CodeChat_Editor/issues/113) -- when + selecting a doc block in the IDE that contains a line wider than the Client's + view, the Client scrolled the horizontal scrollbar all the way to the end of + the line. This fix only performs vertical scrolling, but leaves the horizontal + scroll unchanged. +* Fix keyboard navigation -- moving between doc blocks and code blocks with + arrow keys is now supported. +* Fix regression -- `id` attributes on HTML elements are no longer blocked. +* Fix unexpected scrolling when editing doc blocks which exceed the screen + height. +* Update the delimiter when a doc block is updated. +* Remove highlight around the a doc block when it's being edited, which hides + the cursor when the cursor is at the beginning of the line. + +Version 0.1.59 -- 2026-Jun-26 ----------------------------- * Block malicious HTML in source code/Markdown documents. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..354a7513 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,46 @@ +Instructions for Claude Code +============================ + +Code blocks and doc blocks +-------------------------- + +The CodeChat Editor divides source code into code blocks and documentation (doc) +blocks. These blocks are separated by newlines. A code block consists of all +lines in a source file which aren't classified as a doc block. Note that code +blocks may consist entirely of a comment, as illustrated below. + +A doc block consists of a comment (inline or block) optionally preceded by +whitespace and optionally succeeded by whitespace. At least one whitespace +character must separate the opening comment delimiter from the doc block text. +Doc blocks are differentiated by their indent: the whitespace characters +preceding the opening comment delimiter. Adjacent doc blocks with identical +indents are combined into a single, larger doc block. + +```c +// This is all one doc block, since only the preceding +// whitespace (there is none) matters, not the amount of +// whitespace following the opening comment delimiters. + // This is the beginning of a different doc + // block, since the indent is different. + // Here's a third doc block; inline and block comments + /* combine as long as the whitespace preceding the comment +delimiters is identical. Whitespace inside the comment doesn't affect + the classification. */ +// These are two separate doc blocks, +void foo(); +// since they are separated by a code block. +``` + +Architecture +------------ + +A Visual Studio Code extension in `extensions/VSCode` exchanges messages with the CodeChat Editor Server, located in `server/` (also terms the Server), which also exchanges message with the CodeChat Editor Client (also termed the Client) located in `client/`. + +Project build +------------- + +All build commands must be executed from the `server/` directory. + +* To build the entire project, execute `./bt build`. +* To build (bundle) only the Client, execute `./bt client-build`. +* To run tests, execute `cargo test`. diff --git a/builder/Cargo.lock b/builder/Cargo.lock index 711109e4..3d7fd6db 100644 --- a/builder/Cargo.lock +++ b/builder/Cargo.lock @@ -177,9 +177,9 @@ checksum = "a74858bcfe44b22016cb49337d7b6f04618c58e5dbfdef61b06b8c434324a0bc" [[package]] name = "defmt" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6e524506490a1953d237cb87b1cfc1e46f88c18f10a22dfe0f507dc6bfc7f7f" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" dependencies = [ "bitflags", "defmt-macros", @@ -187,12 +187,11 @@ dependencies = [ [[package]] name = "defmt-macros" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0a27770e9c8f719a79d8b638281f4d828f77d8fd61e0bd94451b9b85e576a0b" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" dependencies = [ "defmt-parser", - "proc-macro-error2", "proc-macro2", "quote", "syn", @@ -280,9 +279,9 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "jiff" -version = "0.2.29" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34f877a98676d2fb664698d74cc6a51ce6c484ce8c770f05d0108ec9090aeb46" +checksum = "ccfe6121cbe750cf81efa362d85c0bde7ea298ec43092d3a193baca59cdbd634" dependencies = [ "defmt", "jiff-static", @@ -294,9 +293,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.29" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0666b5ab5ecaca213fc2a85b8c0083d9004e84ee2d5f9a7e0017aaf50986f25f" +checksum = "e165e897f662d428f3cd3828a919dbe067c2d42bb1031eede74ef9d27ecdedd2" dependencies = [ "proc-macro2", "quote", @@ -317,9 +316,9 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "memchr" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "miette" @@ -357,13 +356,12 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "open" -version = "5.3.5" +version = "5.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fbaa89d2ddc8473c78a3adf69eea8cffa28c483b8e02a971ef31527cd0fc92c" +checksum = "cd8d3b65c44123a56e0133d2cd06ce4361bd3ca99d41198b2f25e3c3db9b8b4a" dependencies = [ "is-wsl", "libc", - "pathdiff", ] [[package]] @@ -382,12 +380,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" -[[package]] -name = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - [[package]] name = "portable-atomic" version = "1.13.1" diff --git a/builder/src/main.rs b/builder/src/main.rs index 9ddca396..c0623838 100644 --- a/builder/src/main.rs +++ b/builder/src/main.rs @@ -380,7 +380,7 @@ fn run_install(dev: bool) -> io::Result<()> { cargo fetch --manifest-path=$BUILDER_PATH/Cargo.toml; info "VSCode extension: cargo fetch"; cargo fetch --manifest-path=$VSCODE_PATH/Cargo.toml; - info "test_utils: cargo fetch" + info "test_utils: cargo fetch"; cargo fetch --manifest-path=$TEST_UTILS_PATH/Cargo.toml; info "cargo fetch"; cargo fetch; @@ -437,7 +437,7 @@ fn run_update() -> io::Result<()> { cargo update --manifest-path=$BUILDER_PATH/Cargo.toml; info "VSCode extension: cargo update"; cargo update --manifest-path=$VSCODE_PATH/Cargo.toml; - info "test_utils: cargo update" + info "test_utils: cargo update"; cargo update --manifest-path=$TEST_UTILS_PATH/Cargo.toml; info "cargo update"; cargo update; @@ -450,7 +450,7 @@ fn run_update() -> io::Result<()> { cargo outdated --manifest-path=$BUILDER_PATH/Cargo.toml; info "VSCode extension: cargo outdated"; cargo outdated --manifest-path=$VSCODE_PATH/Cargo.toml; - info "test_utils: cargo outdated" + info "test_utils: cargo outdated"; cargo outdated --manifest-path=$TEST_UTILS_PATH/Cargo.toml; info "cargo outdated"; cargo outdated; @@ -476,7 +476,7 @@ fn run_format_and_lint(check_only: bool) -> io::Result<()> { info "VSCode extension: cargo clippy and fmt"; cargo clippy --all-targets --all-features --manifest-path=$VSCODE_PATH/Cargo.toml -- $clippy_check_only; cargo fmt --all $check --manifest-path=$VSCODE_PATH/Cargo.toml; - info "test_utils: cargo clippy and fmt" + info "test_utils: cargo clippy and fmt"; cargo clippy --all-targets --all-features --manifest-path=$TEST_UTILS_PATH/Cargo.toml -- $clippy_check_only; cargo fmt --all $check --manifest-path=$TEST_UTILS_PATH/Cargo.toml; @@ -486,7 +486,7 @@ fn run_format_and_lint(check_only: bool) -> io::Result<()> { cargo audit --file=$BUILDER_PATH/Cargo.lock --no-fetch; info "VSCode extension: cargo audit"; cargo audit --file=$VSCODE_PATH/Cargo.lock --no-fetch; - info "test_utils: cargo audit" + info "test_utils: cargo audit"; cargo audit --file=$TEST_UTILS_PATH/Cargo.lock --no-fetch; info "cargo sort"; @@ -497,8 +497,8 @@ fn run_format_and_lint(check_only: bool) -> io::Result<()> { cd $VSCODE_PATH; info "VSCode extension: cargo sort"; cargo sort $check; - info "test_utils: cargo sort" - cd $TEST_UTILS_PATH; + info "test_utils: cargo sort"; + cd ../$TEST_UTILS_PATH; cargo sort $check; )?; @@ -526,7 +526,7 @@ fn run_test() -> io::Result<()> { cargo test --manifest-path=$BUILDER_PATH/Cargo.toml; info "VSCode extension: cargo test"; cargo test --manifest-path=$VSCODE_PATH/Cargo.toml; - info "test_utils: cargo test" + info "test_utils: cargo test"; cargo test --manifest-path=$TEST_UTILS_PATH/Cargo.toml; info "cargo test"; cargo test; @@ -613,7 +613,7 @@ fn run_client_build( true, )?; - // \The PDF viewer for use with VSCode. Build it separately, // since it's loaded apart from the rest of the Client. run_script( &esbuild, diff --git a/client/package.json5 b/client/package.json5 index 6e4ff868..f64ef88c 100644 --- a/client/package.json5 +++ b/client/package.json5 @@ -43,7 +43,7 @@ url: 'https://github.com/bjones1/CodeChat_editor', }, type: 'module', - version: '0.1.59', + version: '0.1.60', dependencies: { '@codemirror/commands': '^6.10.4', '@codemirror/lang-cpp': '^6.0.3', @@ -62,19 +62,19 @@ '@codemirror/lang-yaml': '^6.1.3', '@codemirror/language': '^6.12.4', '@codemirror/legacy-modes': '^6.5.3', - '@codemirror/state': '^6.7.0', - '@codemirror/view': '^6.43.3', - '@hpcc-js/wasm-graphviz': '^1.22.2', - '@mathjax/mathjax-newcm-font': '^4.1.2', + '@codemirror/state': '^6.7.1', + '@codemirror/view': '^6.43.6', + '@hpcc-js/wasm-graphviz': '^1.24.1', + '@mathjax/mathjax-newcm-font': '^4.1.3', codemirror: '^6.0.2', - mathjax: '^4.1.2', - mermaid: '^11.15.0', - 'pdfjs-dist': '^6.0.227', - tinymce: '^8.6.0', + mathjax: '^4.1.3', + mermaid: '^11.16.0', + 'pdfjs-dist': '^6.1.200', + tinymce: '^8.7.0', 'toastify-js': '^1.12.0', }, devDependencies: { - '@eslint/css': '^1.3.0', + '@eslint/css': '^1.4.0', '@eslint/js': '^10.0.1', '@types/chai': '^5.2.3', '@types/dom-navigation': '^1.0.7', @@ -82,20 +82,20 @@ '@types/mocha': '^10.0.10', '@types/node': '^24.13.2', '@types/toastify-js': '^1.12.4', - '@typescript-eslint/eslint-plugin': '^8.62.0', - '@typescript-eslint/parser': '^8.62.0', + '@typescript-eslint/eslint-plugin': '^8.63.0', + '@typescript-eslint/parser': '^8.63.0', chai: '^6.2.2', esbuild: '^0.28.1', - eslint: '^10.5.0', + eslint: '^10.6.0', 'eslint-config-prettier': '^10.1.8', 'eslint-plugin-import': '^2.32.0', 'eslint-plugin-prettier': '^5.5.6', globals: '^17.7.0', mocha: '^11.7.6', - 'npm-check-updates': '^22.2.7', - prettier: '^3.8.4', + 'npm-check-updates': '^22.2.9', + prettier: '^3.9.4', typescript: '^6.0.3', - 'typescript-eslint': '^8.62.0', + 'typescript-eslint': '^8.63.0', }, scripts: { test: 'echo "Error: no test specified" && exit 1', diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml index 5b59aae1..c371cf7c 100644 --- a/client/pnpm-lock.yaml +++ b/client/pnpm-lock.yaml @@ -60,42 +60,42 @@ importers: specifier: ^6.5.3 version: 6.5.3 '@codemirror/state': - specifier: ^6.7.0 - version: 6.7.0 + specifier: ^6.7.1 + version: 6.7.1 '@codemirror/view': - specifier: ^6.43.3 - version: 6.43.3 + specifier: ^6.43.6 + version: 6.43.6 '@hpcc-js/wasm-graphviz': - specifier: ^1.22.2 - version: 1.22.2 + specifier: ^1.24.1 + version: 1.24.1 '@mathjax/mathjax-newcm-font': - specifier: ^4.1.2 - version: 4.1.2 + specifier: ^4.1.3 + version: 4.1.3 codemirror: specifier: ^6.0.2 version: 6.0.2 mathjax: - specifier: ^4.1.2 - version: 4.1.2 + specifier: ^4.1.3 + version: 4.1.3 mermaid: - specifier: ^11.15.0 - version: 11.15.0 + specifier: ^11.16.0 + version: 11.16.0 pdfjs-dist: - specifier: ^6.0.227 - version: 6.0.227 + specifier: ^6.1.200 + version: 6.1.200 tinymce: - specifier: ^8.6.0 - version: 8.6.0 + specifier: ^8.7.0 + version: 8.7.0 toastify-js: specifier: ^1.12.0 version: 1.12.0 devDependencies: '@eslint/css': - specifier: ^1.3.0 - version: 1.3.0 + specifier: ^1.4.0 + version: 1.4.0 '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.5.0) + version: 10.0.1(eslint@10.6.0) '@types/chai': specifier: ^5.2.3 version: 5.2.3 @@ -115,11 +115,11 @@ importers: specifier: ^1.12.4 version: 1.12.4 '@typescript-eslint/eslint-plugin': - specifier: ^8.62.0 - version: 8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3))(eslint@10.5.0)(typescript@6.0.3) + specifier: ^8.63.0 + version: 8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3))(eslint@10.6.0)(typescript@6.0.3) '@typescript-eslint/parser': - specifier: ^8.62.0 - version: 8.62.0(eslint@10.5.0)(typescript@6.0.3) + specifier: ^8.63.0 + version: 8.63.0(eslint@10.6.0)(typescript@6.0.3) chai: specifier: ^6.2.2 version: 6.2.2 @@ -127,17 +127,17 @@ importers: specifier: ^0.28.1 version: 0.28.1 eslint: - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@10.5.0) + version: 10.1.8(eslint@10.6.0) eslint-plugin-import: specifier: ^2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3))(eslint@10.5.0) + version: 2.32.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3))(eslint@10.6.0) eslint-plugin-prettier: specifier: ^5.5.6 - version: 5.5.6(eslint-config-prettier@10.1.8(eslint@10.5.0))(eslint@10.5.0)(prettier@3.8.4) + version: 5.5.6(eslint-config-prettier@10.1.8(eslint@10.6.0))(eslint@10.6.0)(prettier@3.9.4) globals: specifier: ^17.7.0 version: 17.7.0 @@ -145,17 +145,17 @@ importers: specifier: ^11.7.6 version: 11.7.6 npm-check-updates: - specifier: ^22.2.7 - version: 22.2.7 + specifier: ^22.2.9 + version: 22.2.9 prettier: - specifier: ^3.8.4 - version: 3.8.4 + specifier: ^3.9.4 + version: 3.9.4 typescript: specifier: ^6.0.3 version: 6.0.3 typescript-eslint: - specifier: ^8.62.0 - version: 8.62.0(eslint@10.5.0)(typescript@6.0.3) + specifier: ^8.63.0 + version: 8.63.0(eslint@10.6.0)(typescript@6.0.3) packages: @@ -228,11 +228,11 @@ packages: '@codemirror/search@6.7.1': resolution: {integrity: sha512-uMe5UO6PamJtSHrXhhHOzSX3ReWtiJrva6GnPMwSOrZtiExb5X5eExhr2OUZQVvdxPsKpY3Ro2mFbQadpPWmHA==} - '@codemirror/state@6.7.0': - resolution: {integrity: sha512-Zbl9NyscLMZkfXPQnNAIIAFftidrA1UbcJEIMp24C0Bukc2I5T8wJS0wsXYsnDOqCFJUeJ1BITGNs5CqPDSmSg==} + '@codemirror/state@6.7.1': + resolution: {integrity: sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==} - '@codemirror/view@6.43.3': - resolution: {integrity: sha512-MwEwCAr/o0agJefhC2+reBv5kfOQpMcDRUNQrRYZgWlhH8IwQcerMZrpqWyUFSyO0ebgN2cnh/w87F7G4BGSng==} + '@codemirror/view@6.43.6': + resolution: {integrity: sha512-EVunGSYN1wz1p75WY1s3Xg7t3i8Yol0kGZGizNdX9BUFgMFILYVe8/u6EVpo7Ff5PwbZuILb4QAq7IZoKzIEQA==} '@esbuild/aix-ppc64@0.28.1': resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} @@ -416,8 +416,8 @@ packages: resolution: {integrity: sha512-nxMparyhqVWQvadx9x8dIfubfIPOE+X2b2waua8fzdnM9vdp9rgVtwEZlG0TmCwEUz/d/f40fzvO/eqBwdxz0A==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/css@1.3.0': - resolution: {integrity: sha512-MwY657chvFQWtXmO86syZgD+JpWlzDq7VkKZyi65PwHDbhELQPMzPXh5s8rhrjptG6FCuls0puCmlXk66+14uA==} + '@eslint/css@1.4.0': + resolution: {integrity: sha512-OnRNKgnbX+tufPuZc2kOJS+v1iIARvfJHRNEAVwN77DBpojl+rGjEP8NKTL6pEZ7BR+HtwIuSSdrymEFlANGxg==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/js@10.0.1': @@ -437,8 +437,8 @@ packages: resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@hpcc-js/wasm-graphviz@1.22.2': - resolution: {integrity: sha512-qofkC1bxiQKljs95A/7a0j3mvjEdTBiDPq2W6Eh3mJGOLJ+CEtLVe5pFtzf+FZhYW/V9p9hssS1TRl9PxoV8Sw==} + '@hpcc-js/wasm-graphviz@1.24.1': + resolution: {integrity: sha512-n2aImBtWdMm8G1kKOKK946n3DNGQiEk+aOX6qsQQj6URSSWCkwioXeQt1EeYTl3dRY3lcu09Wa5/teaVhiSJaw==} '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} @@ -463,8 +463,8 @@ packages: '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} - '@iconify/utils@3.1.3': - resolution: {integrity: sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw==} + '@iconify/utils@3.1.4': + resolution: {integrity: sha512-b1S7B1k9ohZ+iNTi2ATxbRYG9fTrJmUT0rc46bvVnNxqNRGW7dyo/vRREwyniI5IRN2RSJHDcm+s3BjWrSAjHw==} '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -476,8 +476,8 @@ packages: '@lezer/cpp@1.1.6': resolution: {integrity: sha512-vh9gWWJOXFVY8HBHK3Twzq8MgwG2iN4GSyzBP9sCGTe37P15x2R14VaBQk0VA0ezTRN1KHYBBsHhvpGZ2Xy/pA==} - '@lezer/css@1.3.3': - resolution: {integrity: sha512-RzBo8r+/6QJeow7aPHIpGVIH59xTcJXp399820gZoMo9noQDRVpJLheIBUicYwKcsbOYoBRoLZlf2720dG/4Tg==} + '@lezer/css@1.3.4': + resolution: {integrity: sha512-N+tn9tej2hPvyKgHEApMOQfHczDJCwxrRFS3SPn9QjYN+uwHvEDnCgKRrb3mxDYxRS8sKMM8fhC3+lc04Abz5Q==} '@lezer/go@1.0.1': resolution: {integrity: sha512-xToRsYxwsgJNHTgNdStpcvmbVuKxTapV0dM0wey1geMMRc9aggoVyKgzYp41D2/vVOx+Ii4hmE206kvxIXBVXQ==} @@ -518,88 +518,88 @@ packages: '@lezer/yaml@1.0.4': resolution: {integrity: sha512-2lrrHqxalACEbxIbsjhqGpSW8kWpUKuY6RHgnSAFZa6qK62wvnPxA8hGOwOoDbwHcOFs5M4o27mjGu+P7TvBmw==} - '@marijn/find-cluster-break@1.0.2': - resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} + '@marijn/find-cluster-break@1.0.3': + resolution: {integrity: sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==} - '@mathjax/mathjax-newcm-font@4.1.2': - resolution: {integrity: sha512-lZHMjNP2XbABHA3kVn40rbse5ERUeMEmrGH03qLkCwxq4/5Z/eNLr0akw1MmQcqTwCbvkx1BFcmJ7RCfbRlw3Q==} + '@mathjax/mathjax-newcm-font@4.1.3': + resolution: {integrity: sha512-gzAB3dFHilHX1l5x2xUqRL+1jDQt3Fyza1DkEMVXWC4E8SvsGdlgEza47HYi2WhVcgfkvf4zgUGzuhbq3Pjlew==} - '@mermaid-js/parser@1.1.1': - resolution: {integrity: sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==} + '@mermaid-js/parser@1.2.0': + resolution: {integrity: sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==} - '@napi-rs/canvas-android-arm64@1.0.1': - resolution: {integrity: sha512-d7ZCwJsgH4QNG50C7HQeVRsRG1gRDa1UeDUb1jEcqgLuiEJp6GVbGiZkFXPlmt0dEs2QHRQCPJoOv+bOkSQR/w==} + '@napi-rs/canvas-android-arm64@1.0.2': + resolution: {integrity: sha512-IMXKVQod0ol4vt3gmClUfXz4JAgHYESGPCUqmH3lQxBoL0K/2greJaQE1HVBVxWWFKfLc4OLZVdxg7kXVyXv+g==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@napi-rs/canvas-darwin-arm64@1.0.1': - resolution: {integrity: sha512-ppyVSzIHsVldc3B++mdh03ed0Q0hoVR2QDG9O/wEUR0PurJKwDEEYV87uBQDpbSumJBfLEINDndsOPzQj71qEQ==} + '@napi-rs/canvas-darwin-arm64@1.0.2': + resolution: {integrity: sha512-Sc8tPi6cF+5lqOzCCKFALJHhDiRwyMzTPYm3bbhdXsOunU0lQO5f05ucyOzN2r55I23Hg5bsjH63uSCvWp3EgQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@napi-rs/canvas-darwin-x64@1.0.1': - resolution: {integrity: sha512-/BlXif9VOzf/WP32g9zxl612dO0KLvwqplBFqfRcyr3PyR5fhPrilTuJxSBq3zkwCKGKy82JsoPd2JeQI/HBlA==} + '@napi-rs/canvas-darwin-x64@1.0.2': + resolution: {integrity: sha512-niDXZ9LhKB1zLrUdYB64RHQFDGz9rr0eGx061qtJJU3U20EMMIx28ADF5fVYbhtOgkWQrBjFicfaye1yM0U62A==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@napi-rs/canvas-linux-arm-gnueabihf@1.0.1': - resolution: {integrity: sha512-JTGq93/Pje+iSNVjL+ggB0+pqEfu7nXvQGrHTvugz+Lp08wCDa5rjov4JeEljGDk16/inVBU9sp4N9f0/+o+9A==} + '@napi-rs/canvas-linux-arm-gnueabihf@1.0.2': + resolution: {integrity: sha512-sgatQL9JxGRH/Amzcvu0P3t8Am3duou74CisfuJ41Dwt8cWy723z/9KZ8LlgmxfypEwEZxSTNFJtU8d281lmhQ==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@napi-rs/canvas-linux-arm64-gnu@1.0.1': - resolution: {integrity: sha512-i74zqEh5yFmYwHkszFo+4EH4l5ATD4bSlJG21iW2j5kpqiN2b0WN9SG/xdq2O60MjZK0ZLSu3a/Z3aQAsmDQ5A==} + '@napi-rs/canvas-linux-arm64-gnu@1.0.2': + resolution: {integrity: sha512-dgKuX0peF3xwY6ZF5QxGS4wbfDqpoFAJYXiLSp+guZKARQUKMkRqZSDrXKj7nfrec3UCMzC0PFCPte0ES98AiA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@napi-rs/canvas-linux-arm64-musl@1.0.1': - resolution: {integrity: sha512-COqBxybXcKb6gNgEhjh04rPHrpsJB+n/5+p4ySPgQWl0i+xVNYHn4rvzCtUBIFqOgY6HEJ9UaP6c4W9EMwzfpQ==} + '@napi-rs/canvas-linux-arm64-musl@1.0.2': + resolution: {integrity: sha512-qwROoDIC9upfvDoRLuPn2aNg9CGW1x0Ygr4k2Or+8paA9d0qBLwk87U+g8KQpoOviKoPoiwl97kvBYuYD7qZoA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@napi-rs/canvas-linux-riscv64-gnu@1.0.1': - resolution: {integrity: sha512-1vdAZGpD85lMUo7K3qtEdoIWeMc0xcpUD5PagK3fVcMSdf8dkSL5bg/KE4Rwv5NF+PYx4plrgfn0KRMOqdKtwA==} + '@napi-rs/canvas-linux-riscv64-gnu@1.0.2': + resolution: {integrity: sha512-fXRjnPihdnbO6qy1QQOgxAonb68A0TCEG7rj1x7v7rxNElsE8EVIKIEUTvyDtU+sthYSbX+8e7g3oZiLGnOmxw==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] libc: [glibc] - '@napi-rs/canvas-linux-x64-gnu@1.0.1': - resolution: {integrity: sha512-W/iC2qJZGqKKQJ0JrNo3QkhoAy/PvzlmdYLW8Yz5/L6XgT5d7t26dnqgP2rCbL58P3CbPw7ES0Rz8OG0gn7JeQ==} + '@napi-rs/canvas-linux-x64-gnu@1.0.2': + resolution: {integrity: sha512-nPR97DXhbWIAy7yazF3jc06kEPMqYMLmPzFOVNlwKPfIoSChnI+x7dc0hTLaihz3jxrjL6j4BbA7earxfx4X3g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@napi-rs/canvas-linux-x64-musl@1.0.1': - resolution: {integrity: sha512-a5mmIVwxF92UGUe+1c7Ap32ZRnApbRMnQC/KgYyFB0AXZShBCHVGaURq+BDkiV7jvHhVwvvAP0Q/3aWNhqgVZg==} + '@napi-rs/canvas-linux-x64-musl@1.0.2': + resolution: {integrity: sha512-l7zZY5+jL5qnBZtDz7CoBtY6p7EkHu422g/0zWwrOrzIwWyWxZFRfZZORY1UG7YApymPLx+UbOkN206xXn/c1Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@napi-rs/canvas-win32-arm64-msvc@1.0.1': - resolution: {integrity: sha512-rVnDhVvcXlqcHMsgnxxhZgdRkRIqVBlx+FJwSAHi4VbWWwsowvV5ldFEecEHD2+Ac/IL3fNWF/LB5CZTghNwRA==} + '@napi-rs/canvas-win32-arm64-msvc@1.0.2': + resolution: {integrity: sha512-yE0koHCFF4PIbMc2o2SEALhnipz7WBISh5glLvQiomtIoCcW0np3H4Lw93ceJAfJttTTeIIWFbwH84F7EVzjMQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@napi-rs/canvas-win32-x64-msvc@1.0.1': - resolution: {integrity: sha512-UMstkP/nZHbithgdSJv1EvYVrYhdao5B5N3szMVU2i5/b6ijMcVPXOEyrk0QXl0iPjv8Hkoow+Tap+MiOxppOQ==} + '@napi-rs/canvas-win32-x64-msvc@1.0.2': + resolution: {integrity: sha512-okU8/t2foV6C31n0GtvEMbfD5rOFc70+/6xUNME9Guld29sgSOIGUEDScAWFlcP3k5TYQRl9TNkwJEEjh15w8A==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@napi-rs/canvas@1.0.1': - resolution: {integrity: sha512-mPD43G7pXbQhIGa7z4IpT/vXm1jbF8cBM1oY5UqjL8LSaTCNGhNi2Lidc/0+LwKbNiqbv/Tq0JlBRwKu+LW3iw==} + '@napi-rs/canvas@1.0.2': + resolution: {integrity: sha512-EYEqlMYaCbpZDz+IgDH5xp9MTd3ui4dmGqbQYryhMLnSRxrhHKq5KQWHHKxFUcEP4Hp8/BWgvqXocX4j7iSbOQ==} engines: {node: '>= 10'} '@pkgjs/parseargs@0.11.0': @@ -676,8 +676,8 @@ packages: '@types/d3-quadtree@3.0.6': resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} - '@types/d3-random@3.0.3': - resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + '@types/d3-random@3.0.4': + resolution: {integrity: sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA==} '@types/d3-scale-chromatic@3.1.0': resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} @@ -745,63 +745,63 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@typescript-eslint/eslint-plugin@8.62.0': - resolution: {integrity: sha512-o+mpz7EYiMzXoySXiKmzlabIvTVqUuK5yLrAedRPRDA0IpPFMUV1IXt6OqljIxX/kumN6EjUYp41Hqelh6p/Dw==} + '@typescript-eslint/eslint-plugin@8.63.0': + resolution: {integrity: sha512-rvwSgqT+DHpWdzfSzPatRLm02a0GlESt++9iy3hLCDY4BgkaLcl8LBi9Yh7XGFBpwcBE/K3024QuXWTpbz4FfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.62.0 + '@typescript-eslint/parser': ^8.63.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.62.0': - resolution: {integrity: sha512-dzHeT2gySzZtLDsuqxU9AkYgIsQoHAHtRBpOqM+Ofzx1Bwrd2RcCjQJ+6iQbsHOIR6NS33bF2W1k3blN1zLDrA==} + '@typescript-eslint/parser@8.63.0': + resolution: {integrity: sha512-gwh4gvvlaVDKKxyfxMG+Gnu1u9X0OQBwyGLkbwB65dIzBKnxeRiJlNFqlI3zwVhNXJIs6qV7mlFCn/BIajlVig==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.62.0': - resolution: {integrity: sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==} + '@typescript-eslint/project-service@8.63.0': + resolution: {integrity: sha512-e5dh0/UI0ok53AlZ5wRkXCB32z/f2jUZqPR/ygAw5WYaSw8j9EoJWlS7wQjr/dmOaqWjnPIn2m+HhVPCMWGZVQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.62.0': - resolution: {integrity: sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==} + '@typescript-eslint/scope-manager@8.63.0': + resolution: {integrity: sha512-uUyfMWCnDSN8bCpcrY8nGP2BLkQ9Xn0GsipcONcpIDWhwhO4ZSyHvyS14U3X75mzxWxL3I2UZIrenTzdzcJO8A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.62.0': - resolution: {integrity: sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==} + '@typescript-eslint/tsconfig-utils@8.63.0': + resolution: {integrity: sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.62.0': - resolution: {integrity: sha512-+g5O3j0w2ldzC86Pv6fvbO/xhAonbJFIdf/MKQ1d30gndlsVzUOE83ldfSE15Qrl9fhFjK6AovHs5Wpp6vx86w==} + '@typescript-eslint/type-utils@8.63.0': + resolution: {integrity: sha512-Nzzh/OGxVCOjObjaj1CQF2RUasyYy2Jfuh+zZ3PjLzG2fYRriAiZLib9UKtO+CpQAS3YHiAS+ckZDclwqI1TPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.62.0': - resolution: {integrity: sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==} + '@typescript-eslint/types@8.63.0': + resolution: {integrity: sha512-xyLtl9DUBBFrcJS4x2pIqGLH68/tC2uOa4Z7pUteW09D3bXnnXUom4dyPikzWgB7llmIc1zoeI3aoUdC4rPK/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.62.0': - resolution: {integrity: sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==} + '@typescript-eslint/typescript-estree@8.63.0': + resolution: {integrity: sha512-ygBkU+B7ex5UI/gKhaqexWev79uISfIv7XQCRNYO/jmD8rGLPyWLAb3KMRT6nd8Gt9bmUBi9+iX6tBdYfOY81Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.62.0': - resolution: {integrity: sha512-82r66fi9zYwZ+mTq3vKgwjbZ1PVk/DJzrXFLpG6RnBbdvH8TEGVHIs9H4d2drhkOzf0syZuD/OZvvlu6GDbP4g==} + '@typescript-eslint/utils@8.63.0': + resolution: {integrity: sha512-fUKaeAvrTuQg/Tgt3nliAUSZHJM6DlCcfyEmxCvlX8kieWSStBX+5O5Fnidtc3i2JrH+9c/GL4RY2iasd/GPTA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.62.0': - resolution: {integrity: sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==} + '@typescript-eslint/visitor-keys@8.63.0': + resolution: {integrity: sha512-UexrHGnGTpbuQHct2ExOc2ZcFbGUS9FOesCxxqdBGcpI1BxYu/LZ6U8Aq6/72XtF/qRBk9nhuGHFJIXXMhPMdw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@upsetjs/venn.js@2.0.0': @@ -888,8 +888,8 @@ packages: brace-expansion@2.1.1: resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} - brace-expansion@5.0.6: - resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + brace-expansion@5.0.7: + resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==} engines: {node: 18 || 20 || >=22} browser-stdout@1.3.1: @@ -954,8 +954,8 @@ packages: cose-base@2.2.0: resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} - crelt@1.0.6: - resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + crelt@1.0.7: + resolution: {integrity: sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==} cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} @@ -1219,12 +1219,12 @@ packages: resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} engines: {node: '>= 0.4'} - es-to-primitive@1.3.1: - resolution: {integrity: sha512-CxN9N56HYfd2m/acc/NOFrZQsN9kU4eh+2kk6A707Kz1krH8tKmfrs5RnftB8WNX80T0NS7vSQsDOlg23diR2g==} + es-to-primitive@1.3.4: + resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==} engines: {node: '>= 0.4'} - es-toolkit@1.48.1: - resolution: {integrity: sha512-wfnXlwd5I75eXRtdD2vuEs50xHHESECDsGD7yiQnfFVNoa5522NwXEbmgo98LfiukSQHs+mBM7/YG3qKJB9/mQ==} + es-toolkit@1.49.0: + resolution: {integrity: sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==} esbuild@0.28.1: resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} @@ -1248,8 +1248,8 @@ packages: eslint-import-resolver-node@0.3.10: resolution: {integrity: sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==} - eslint-module-utils@2.13.0: - resolution: {integrity: sha512-bLohSkT6469rRs8czj0tLTD8vaeIS/whvPRJVjDr7IuoTT1k5DYDERlNycjDj/HkOlvQdYurmfZ/g3fG5bgeLQ==} + eslint-module-utils@2.14.0: + resolution: {integrity: sha512-W2WCRZ9Dqntd+2u8jJcVMV2PKulc6RdLgUUoh/yQr3uB6lo/ZOeGx11sv60/8S4QFFKNslAlWhr9u0Ef7ZW6Ig==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -1305,8 +1305,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.5.0: - resolution: {integrity: sha512-1y+7C+vi12bUK1IpZeaV3gsH9fHLBmPvYmPx42pvT/E9yG0IC8g3PUZZgp0+JLJl7ZDK0flc2gc+Aw9dpCvIsQ==} + eslint@10.6.0: + resolution: {integrity: sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -1623,8 +1623,8 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - js-yaml@4.2.0: - resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} + js-yaml@4.3.0: + resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} hasBin: true json-buffer@3.0.1: @@ -1683,14 +1683,14 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - mathjax@4.1.2: - resolution: {integrity: sha512-EQDS8xBpVg179BXoLeZ9JlwUFftOC5qylw20UlAMDhrTuooENigOocY79aNkkFSyvj/AST/89ZAo12+r5bPI4w==} + mathjax@4.1.3: + resolution: {integrity: sha512-BN/8Pkgn7G1pIDYJqd9md+JHsE/jydSYbyOZnSdSA0WziuVO8mRxdYiWFumkVVly/8U+hm9DpIIoWuvySverzw==} mdn-data@2.28.1: resolution: {integrity: sha512-U9w+PzSZ00Z5m9rZ5ARVFL5xOfuCHdKYi/1RRwDCJsboFgJDNT3zT6PIPD7mZQYaQLhsZM3GfDRgSMRHhSmVng==} - mermaid@11.15.0: - resolution: {integrity: sha512-pTMbcf3rWdtLiYGpmoTjHEpeY8seiy6sR+9nD7LOs8KfUbHE4lOUAprTRqRAcWSQ6MQpdX+YEsxShtGsINtPtw==} + mermaid@11.16.0: + resolution: {integrity: sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA==} minimatch@10.2.5: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} @@ -1725,8 +1725,8 @@ packages: resolution: {integrity: sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==} engines: {node: '>= 0.4'} - npm-check-updates@22.2.7: - resolution: {integrity: sha512-Pzs/lTswEe23hT8JUXABl4vgrr0WRKOhw55wAldwngUflk8CwP+grXJt00yGjYiZf2wD1HIfdPa3xaOi1RCyZQ==} + npm-check-updates@22.2.9: + resolution: {integrity: sha512-DVeZ0KirHfliSsHuR2o7cHE+tW439sVHfJjF6cGWeDiY0Wyl3BI/jS4zV0eixtcMOquFbcF1Su/FsxOvk5MoYA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: '>=10.0.0'} hasBin: true @@ -1777,8 +1777,8 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - package-manager-detector@1.6.0: - resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + package-manager-detector@1.7.0: + resolution: {integrity: sha512-xg1eHpwYL/D/HEdWw2goFZP6vV0FH7W+PZ5rFkGjdIDLtxq7EkzBUeT3m+lndYCt8wKbmofUu1MUdMCXkCk9ZQ==} path-data-parser@0.1.0: resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} @@ -1798,15 +1798,15 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - pdfjs-dist@6.0.227: - resolution: {integrity: sha512-/P6M4SXw+70waMVLUM7rdRtvo+dEzqE1t6W/zQNvBETo2MaRa5rrvCcAYdfWGiUzadTgM0lJmRApUrW0d9zgKg==} + pdfjs-dist@6.1.200: + resolution: {integrity: sha512-o8MolyzirkkLrcdsae/HEOiIcXWI7DS5zGpvqW8xTC2YUsW30rltFw2bDGvw/fskUdEMrQm2br68jzDS5BH2vw==} engines: {node: '>=22.13.0 || >=24'} picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} engines: {node: '>=12'} points-on-curve@0.2.0: @@ -1827,8 +1827,8 @@ packages: resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==} engines: {node: '>=6.0.0'} - prettier@3.8.4: - resolution: {integrity: sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==} + prettier@3.9.4: + resolution: {integrity: sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==} engines: {node: '>=14'} hasBin: true @@ -2013,8 +2013,8 @@ packages: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} - tinymce@8.6.0: - resolution: {integrity: sha512-qODYoNL4cPIzNFpkEEQDm3DWI78I/nQXIPwUMHRN+q/LyT9Wzt7xis2Nfhk88kV6sibp6MJXPSaUDVNe02ZB/w==} + tinymce@8.7.0: + resolution: {integrity: sha512-V3fBgEzKxKT5d41/3qkXs//2SjANGHzo1MWnU2ai8nss8YrzPprrRFlDbX2X9Z6ClyQAknojs7CzEgcsTdqhPQ==} toastify-js@1.12.0: resolution: {integrity: sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ==} @@ -2052,8 +2052,8 @@ packages: resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} engines: {node: '>= 0.4'} - typescript-eslint@8.62.0: - resolution: {integrity: sha512-8QxXi+ZACKX0kaqO4gY8kn0RSD9gFfaHDWwjqtEN48aWCBkX4MJaufWN+c3BzlrXLOxfywDL8CaoqUwcRq4j4Q==} + typescript-eslint@8.63.0: + resolution: {integrity: sha512-xgwXyzG4sK9ALkBxbyGkTMMOS+imnW65iPhxCQMK83KhxyoDNW7l+IDqEf9vMdoUidHpOoS967RCq4eMiTexwQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -2141,7 +2141,7 @@ snapshots: '@antfu/install-pkg@1.1.0': dependencies: - package-manager-detector: 1.6.0 + package-manager-detector: 1.7.0 tinyexec: 1.2.4 '@braintree/sanitize-url@7.1.2': {} @@ -2151,15 +2151,15 @@ snapshots: '@codemirror/autocomplete@6.20.3': dependencies: '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@codemirror/commands@6.10.4': dependencies: '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@codemirror/lang-cpp@6.0.3': @@ -2171,15 +2171,15 @@ snapshots: dependencies: '@codemirror/autocomplete': 6.20.3 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 + '@codemirror/state': 6.7.1 '@lezer/common': 1.5.2 - '@lezer/css': 1.3.3 + '@lezer/css': 1.3.4 '@codemirror/lang-go@6.0.1': dependencies: '@codemirror/autocomplete': 6.20.3 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 + '@codemirror/state': 6.7.1 '@lezer/common': 1.5.2 '@lezer/go': 1.0.1 @@ -2189,10 +2189,10 @@ snapshots: '@codemirror/lang-css': 6.3.1 '@codemirror/lang-javascript': 6.2.5 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 - '@lezer/css': 1.3.3 + '@lezer/css': 1.3.4 '@lezer/html': 1.3.13 '@codemirror/lang-java@6.0.2': @@ -2205,8 +2205,8 @@ snapshots: '@codemirror/autocomplete': 6.20.3 '@codemirror/language': 6.12.4 '@codemirror/lint': 6.9.7 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@lezer/javascript': 1.5.4 @@ -2220,8 +2220,8 @@ snapshots: '@codemirror/autocomplete': 6.20.3 '@codemirror/lang-html': 6.4.11 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@lezer/markdown': 1.6.4 @@ -2229,7 +2229,7 @@ snapshots: dependencies: '@codemirror/lang-html': 6.4.11 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 + '@codemirror/state': 6.7.1 '@lezer/common': 1.5.2 '@lezer/php': 1.0.5 @@ -2237,7 +2237,7 @@ snapshots: dependencies: '@codemirror/autocomplete': 6.20.3 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 + '@codemirror/state': 6.7.1 '@lezer/common': 1.5.2 '@lezer/python': 1.1.19 @@ -2250,7 +2250,7 @@ snapshots: dependencies: '@codemirror/autocomplete': 6.20.3 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 + '@codemirror/state': 6.7.1 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.10 @@ -2259,8 +2259,8 @@ snapshots: dependencies: '@codemirror/autocomplete': 6.20.3 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@lezer/xml': 1.0.6 @@ -2268,7 +2268,7 @@ snapshots: dependencies: '@codemirror/autocomplete': 6.20.3 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 + '@codemirror/state': 6.7.1 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.10 @@ -2276,8 +2276,8 @@ snapshots: '@codemirror/language@6.12.4': dependencies: - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.10 @@ -2289,24 +2289,24 @@ snapshots: '@codemirror/lint@6.9.7': dependencies: - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 - crelt: 1.0.6 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 + crelt: 1.0.7 '@codemirror/search@6.7.1': dependencies: - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 - crelt: 1.0.6 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 + crelt: 1.0.7 - '@codemirror/state@6.7.0': + '@codemirror/state@6.7.1': dependencies: - '@marijn/find-cluster-break': 1.0.2 + '@marijn/find-cluster-break': 1.0.3 - '@codemirror/view@6.43.3': + '@codemirror/view@6.43.6': dependencies: - '@codemirror/state': 6.7.0 - crelt: 1.0.6 + '@codemirror/state': 6.7.1 + crelt: 1.0.7 style-mod: 4.1.3 w3c-keyname: 2.2.8 @@ -2388,9 +2388,9 @@ snapshots: '@esbuild/win32-x64@0.28.1': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.5.0)': + '@eslint-community/eslint-utils@4.9.1(eslint@10.6.0)': dependencies: - eslint: 10.5.0 + eslint: 10.6.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -2416,15 +2416,15 @@ snapshots: mdn-data: 2.28.1 source-map-js: 1.2.1 - '@eslint/css@1.3.0': + '@eslint/css@1.4.0': dependencies: '@eslint/core': 1.2.1 '@eslint/css-tree': 4.0.4 '@eslint/plugin-kit': 0.7.2 - '@eslint/js@10.0.1(eslint@10.5.0)': + '@eslint/js@10.0.1(eslint@10.6.0)': optionalDependencies: - eslint: 10.5.0 + eslint: 10.6.0 '@eslint/object-schema@3.0.5': {} @@ -2433,7 +2433,7 @@ snapshots: '@eslint/core': 1.2.1 levn: 0.4.1 - '@hpcc-js/wasm-graphviz@1.22.2': {} + '@hpcc-js/wasm-graphviz@1.24.1': {} '@humanfs/core@0.19.2': dependencies: @@ -2453,7 +2453,7 @@ snapshots: '@iconify/types@2.0.0': {} - '@iconify/utils@3.1.3': + '@iconify/utils@3.1.4': dependencies: '@antfu/install-pkg': 1.1.0 '@iconify/types': 2.0.0 @@ -2476,7 +2476,7 @@ snapshots: '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.10 - '@lezer/css@1.3.3': + '@lezer/css@1.3.4': dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 @@ -2555,60 +2555,60 @@ snapshots: '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.10 - '@marijn/find-cluster-break@1.0.2': {} + '@marijn/find-cluster-break@1.0.3': {} - '@mathjax/mathjax-newcm-font@4.1.2': {} + '@mathjax/mathjax-newcm-font@4.1.3': {} - '@mermaid-js/parser@1.1.1': + '@mermaid-js/parser@1.2.0': dependencies: '@chevrotain/types': 11.1.2 - '@napi-rs/canvas-android-arm64@1.0.1': + '@napi-rs/canvas-android-arm64@1.0.2': optional: true - '@napi-rs/canvas-darwin-arm64@1.0.1': + '@napi-rs/canvas-darwin-arm64@1.0.2': optional: true - '@napi-rs/canvas-darwin-x64@1.0.1': + '@napi-rs/canvas-darwin-x64@1.0.2': optional: true - '@napi-rs/canvas-linux-arm-gnueabihf@1.0.1': + '@napi-rs/canvas-linux-arm-gnueabihf@1.0.2': optional: true - '@napi-rs/canvas-linux-arm64-gnu@1.0.1': + '@napi-rs/canvas-linux-arm64-gnu@1.0.2': optional: true - '@napi-rs/canvas-linux-arm64-musl@1.0.1': + '@napi-rs/canvas-linux-arm64-musl@1.0.2': optional: true - '@napi-rs/canvas-linux-riscv64-gnu@1.0.1': + '@napi-rs/canvas-linux-riscv64-gnu@1.0.2': optional: true - '@napi-rs/canvas-linux-x64-gnu@1.0.1': + '@napi-rs/canvas-linux-x64-gnu@1.0.2': optional: true - '@napi-rs/canvas-linux-x64-musl@1.0.1': + '@napi-rs/canvas-linux-x64-musl@1.0.2': optional: true - '@napi-rs/canvas-win32-arm64-msvc@1.0.1': + '@napi-rs/canvas-win32-arm64-msvc@1.0.2': optional: true - '@napi-rs/canvas-win32-x64-msvc@1.0.1': + '@napi-rs/canvas-win32-x64-msvc@1.0.2': optional: true - '@napi-rs/canvas@1.0.1': + '@napi-rs/canvas@1.0.2': optionalDependencies: - '@napi-rs/canvas-android-arm64': 1.0.1 - '@napi-rs/canvas-darwin-arm64': 1.0.1 - '@napi-rs/canvas-darwin-x64': 1.0.1 - '@napi-rs/canvas-linux-arm-gnueabihf': 1.0.1 - '@napi-rs/canvas-linux-arm64-gnu': 1.0.1 - '@napi-rs/canvas-linux-arm64-musl': 1.0.1 - '@napi-rs/canvas-linux-riscv64-gnu': 1.0.1 - '@napi-rs/canvas-linux-x64-gnu': 1.0.1 - '@napi-rs/canvas-linux-x64-musl': 1.0.1 - '@napi-rs/canvas-win32-arm64-msvc': 1.0.1 - '@napi-rs/canvas-win32-x64-msvc': 1.0.1 + '@napi-rs/canvas-android-arm64': 1.0.2 + '@napi-rs/canvas-darwin-arm64': 1.0.2 + '@napi-rs/canvas-darwin-x64': 1.0.2 + '@napi-rs/canvas-linux-arm-gnueabihf': 1.0.2 + '@napi-rs/canvas-linux-arm64-gnu': 1.0.2 + '@napi-rs/canvas-linux-arm64-musl': 1.0.2 + '@napi-rs/canvas-linux-riscv64-gnu': 1.0.2 + '@napi-rs/canvas-linux-x64-gnu': 1.0.2 + '@napi-rs/canvas-linux-x64-musl': 1.0.2 + '@napi-rs/canvas-win32-arm64-msvc': 1.0.2 + '@napi-rs/canvas-win32-x64-msvc': 1.0.2 optional: true '@pkgjs/parseargs@0.11.0': @@ -2678,7 +2678,7 @@ snapshots: '@types/d3-quadtree@3.0.6': {} - '@types/d3-random@3.0.3': {} + '@types/d3-random@3.0.4': {} '@types/d3-scale-chromatic@3.1.0': {} @@ -2729,7 +2729,7 @@ snapshots: '@types/d3-path': 3.1.1 '@types/d3-polygon': 3.0.2 '@types/d3-quadtree': 3.0.6 - '@types/d3-random': 3.0.3 + '@types/d3-random': 3.0.4 '@types/d3-scale': 4.0.9 '@types/d3-scale-chromatic': 3.1.0 '@types/d3-selection': 3.0.11 @@ -2767,15 +2767,15 @@ snapshots: '@types/trusted-types@2.0.7': optional: true - '@typescript-eslint/eslint-plugin@8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3))(eslint@10.5.0)(typescript@6.0.3)': + '@typescript-eslint/eslint-plugin@8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3))(eslint@10.6.0)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.62.0(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.62.0 - '@typescript-eslint/type-utils': 8.62.0(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.0(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.62.0 - eslint: 10.5.0 + '@typescript-eslint/parser': 8.63.0(eslint@10.6.0)(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.63.0 + '@typescript-eslint/type-utils': 8.63.0(eslint@10.6.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.63.0(eslint@10.6.0)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.63.0 + eslint: 10.6.0 ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@6.0.3) @@ -2783,56 +2783,56 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3)': + '@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/scope-manager': 8.62.0 - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.62.0 + '@typescript-eslint/scope-manager': 8.63.0 + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.63.0 debug: 4.4.3(supports-color@8.1.1) - eslint: 10.5.0 + eslint: 10.6.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.62.0(typescript@6.0.3)': + '@typescript-eslint/project-service@8.63.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.62.0(typescript@6.0.3) - '@typescript-eslint/types': 8.62.0 + '@typescript-eslint/tsconfig-utils': 8.63.0(typescript@6.0.3) + '@typescript-eslint/types': 8.63.0 debug: 4.4.3(supports-color@8.1.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.62.0': + '@typescript-eslint/scope-manager@8.63.0': dependencies: - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/visitor-keys': 8.62.0 + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/visitor-keys': 8.63.0 - '@typescript-eslint/tsconfig-utils@8.62.0(typescript@6.0.3)': + '@typescript-eslint/tsconfig-utils@8.63.0(typescript@6.0.3)': dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.62.0(eslint@10.5.0)(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.63.0(eslint@10.6.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.0(eslint@10.5.0)(typescript@6.0.3) + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.63.0(eslint@10.6.0)(typescript@6.0.3) debug: 4.4.3(supports-color@8.1.1) - eslint: 10.5.0 + eslint: 10.6.0 ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.62.0': {} + '@typescript-eslint/types@8.63.0': {} - '@typescript-eslint/typescript-estree@8.62.0(typescript@6.0.3)': + '@typescript-eslint/typescript-estree@8.63.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.62.0(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.62.0(typescript@6.0.3) - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/visitor-keys': 8.62.0 + '@typescript-eslint/project-service': 8.63.0(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.63.0(typescript@6.0.3) + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/visitor-keys': 8.63.0 debug: 4.4.3(supports-color@8.1.1) minimatch: 10.2.5 semver: 7.8.5 @@ -2842,20 +2842,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.62.0(eslint@10.5.0)(typescript@6.0.3)': + '@typescript-eslint/utils@8.63.0(eslint@10.6.0)(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0) - '@typescript-eslint/scope-manager': 8.62.0 - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3) - eslint: 10.5.0 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0) + '@typescript-eslint/scope-manager': 8.63.0 + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3) + eslint: 10.6.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.62.0': + '@typescript-eslint/visitor-keys@8.63.0': dependencies: - '@typescript-eslint/types': 8.62.0 + '@typescript-eslint/types': 8.63.0 eslint-visitor-keys: 5.0.1 '@upsetjs/venn.js@2.0.0': @@ -2959,7 +2959,7 @@ snapshots: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.6: + brace-expansion@5.0.7: dependencies: balanced-match: 4.0.4 @@ -3008,8 +3008,8 @@ snapshots: '@codemirror/language': 6.12.4 '@codemirror/lint': 6.9.7 '@codemirror/search': 6.7.1 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 color-convert@2.0.1: dependencies: @@ -3031,7 +3031,7 @@ snapshots: dependencies: layout-base: 2.0.1 - crelt@1.0.6: {} + crelt@1.0.7: {} cross-spawn@7.0.6: dependencies: @@ -3316,7 +3316,7 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.2 es-set-tostringtag: 2.1.0 - es-to-primitive: 1.3.1 + es-to-primitive: 1.3.4 function.prototype.name: 1.2.0 get-intrinsic: 1.3.0 get-proto: 1.0.1 @@ -3378,15 +3378,16 @@ snapshots: dependencies: hasown: 2.0.4 - es-to-primitive@1.3.1: + es-to-primitive@1.3.4: dependencies: es-abstract-get: 1.0.0 + es-define-property: 1.0.1 es-errors: 1.3.0 is-callable: 1.2.7 is-date-object: 1.1.0 is-symbol: 1.1.1 - es-toolkit@1.48.1: {} + es-toolkit@1.49.0: {} esbuild@0.28.1: optionalDependencies: @@ -3421,9 +3422,9 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.8(eslint@10.5.0): + eslint-config-prettier@10.1.8(eslint@10.6.0): dependencies: - eslint: 10.5.0 + eslint: 10.6.0 eslint-import-resolver-node@0.3.10: dependencies: @@ -3433,17 +3434,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.13.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.5.0): + eslint-module-utils@2.14.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.6.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.62.0(eslint@10.5.0)(typescript@6.0.3) - eslint: 10.5.0 + '@typescript-eslint/parser': 8.63.0(eslint@10.6.0)(typescript@6.0.3) + eslint: 10.6.0 eslint-import-resolver-node: 0.3.10 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3))(eslint@10.5.0): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3))(eslint@10.6.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -3452,9 +3453,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 10.5.0 + eslint: 10.6.0 eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.5.0) + eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.6.0) hasown: 2.0.4 is-core-module: 2.16.2 is-glob: 4.0.3 @@ -3466,20 +3467,20 @@ snapshots: string.prototype.trimend: 1.0.10 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.62.0(eslint@10.5.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.63.0(eslint@10.6.0)(typescript@6.0.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@10.5.0))(eslint@10.5.0)(prettier@3.8.4): + eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@10.6.0))(eslint@10.6.0)(prettier@3.9.4): dependencies: - eslint: 10.5.0 - prettier: 3.8.4 + eslint: 10.6.0 + prettier: 3.9.4 prettier-linter-helpers: 1.0.1 synckit: 0.11.13 optionalDependencies: - eslint-config-prettier: 10.1.8(eslint@10.5.0) + eslint-config-prettier: 10.1.8(eslint@10.6.0) eslint-scope@9.1.2: dependencies: @@ -3492,9 +3493,9 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.5.0: + eslint@10.6.0: dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.23.5 '@eslint/config-helpers': 0.6.0 @@ -3553,9 +3554,9 @@ snapshots: fast-levenshtein@2.0.6: {} - fdir@6.5.0(picomatch@4.0.4): + fdir@6.5.0(picomatch@4.0.5): optionalDependencies: - picomatch: 4.0.4 + picomatch: 4.0.5 file-entry-cache@8.0.0: dependencies: @@ -3826,7 +3827,7 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - js-yaml@4.2.0: + js-yaml@4.3.0: dependencies: argparse: 2.0.1 @@ -3876,17 +3877,17 @@ snapshots: math-intrinsics@1.1.0: {} - mathjax@4.1.2: + mathjax@4.1.3: dependencies: - '@mathjax/mathjax-newcm-font': 4.1.2 + '@mathjax/mathjax-newcm-font': 4.1.3 mdn-data@2.28.1: {} - mermaid@11.15.0: + mermaid@11.16.0: dependencies: '@braintree/sanitize-url': 7.1.2 - '@iconify/utils': 3.1.3 - '@mermaid-js/parser': 1.1.1 + '@iconify/utils': 3.1.4 + '@mermaid-js/parser': 1.2.0 '@types/d3': 7.4.3 '@upsetjs/venn.js': 2.0.0 cytoscape: 3.34.0 @@ -3897,7 +3898,7 @@ snapshots: dagre-d3-es: 7.0.14 dayjs: 1.11.21 dompurify: 3.4.11 - es-toolkit: 1.48.1 + es-toolkit: 1.49.0 katex: 0.16.47 khroma: 2.1.0 marked: 16.4.2 @@ -3908,7 +3909,7 @@ snapshots: minimatch@10.2.5: dependencies: - brace-expansion: 5.0.6 + brace-expansion: 5.0.7 minimatch@3.1.5: dependencies: @@ -3933,7 +3934,7 @@ snapshots: glob: 10.5.0 he: 1.2.0 is-path-inside: 3.0.3 - js-yaml: 4.2.0 + js-yaml: 4.3.0 log-symbols: 4.1.0 minimatch: 9.0.9 ms: 2.1.3 @@ -3957,7 +3958,7 @@ snapshots: object.entries: 1.1.9 semver: 6.3.1 - npm-check-updates@22.2.7: {} + npm-check-updates@22.2.9: {} object-inspect@1.13.4: {} @@ -4024,7 +4025,7 @@ snapshots: package-json-from-dist@1.0.1: {} - package-manager-detector@1.6.0: {} + package-manager-detector@1.7.0: {} path-data-parser@0.1.0: {} @@ -4039,13 +4040,13 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.3 - pdfjs-dist@6.0.227: + pdfjs-dist@6.1.200: optionalDependencies: - '@napi-rs/canvas': 1.0.1 + '@napi-rs/canvas': 1.0.2 picocolors@1.1.1: {} - picomatch@4.0.4: {} + picomatch@4.0.5: {} points-on-curve@0.2.0: {} @@ -4062,7 +4063,7 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@3.8.4: {} + prettier@3.9.4: {} punycode@2.3.1: {} @@ -4280,10 +4281,10 @@ snapshots: tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 - tinymce@8.6.0: {} + tinymce@8.7.0: {} toastify-js@1.12.0: {} @@ -4337,13 +4338,13 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.62.0(eslint@10.5.0)(typescript@6.0.3): + typescript-eslint@8.63.0(eslint@10.6.0)(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3))(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/parser': 8.62.0(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.0(eslint@10.5.0)(typescript@6.0.3) - eslint: 10.5.0 + '@typescript-eslint/eslint-plugin': 8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3))(eslint@10.6.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.63.0(eslint@10.6.0)(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.63.0(eslint@10.6.0)(typescript@6.0.3) + eslint: 10.6.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color diff --git a/client/src/CodeChatEditor-test.mts b/client/src/CodeChatEditor-test.mts index 999953d0..cf142563 100644 --- a/client/src/CodeChatEditor-test.mts +++ b/client/src/CodeChatEditor-test.mts @@ -17,8 +17,10 @@ // `CodeChatEditor-test.mts` -- Tests for the CodeChat Editor client // ================================================================= // -// To run tests, add a `?test` to any web page served by the CodeChat Editor -// server. +// To run tests, change to the `server/` directory then run `./bt client-build` +// to build any changes to the Client, followed by `cargo test --test overall_1 +// test_client`. Or, add a `?test` parameter to any web page served by the +// CodeChat Editor Server. // // Imports // ------- @@ -46,8 +48,8 @@ const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); // Tests // ----- // -// Defining this global variable signals the -// CodeChat Editor to [run tests](CodeChatEditor.mts#CodeChatEditor_test). +// Defining this global variable signals the CodeChat Editor to +// [run tests](CodeChatEditor.mts#CodeChatEditor_test). window.CodeChatEditor_test = () => { // See the [Mocha docs](https://mochajs.org/#browser-configuration). mocha.setup({ diff --git a/client/src/CodeChatEditor.mts b/client/src/CodeChatEditor.mts index 88b03151..fcdcd53f 100644 --- a/client/src/CodeChatEditor.mts +++ b/client/src/CodeChatEditor.mts @@ -749,8 +749,7 @@ on_dom_content_loaded(async () => { // Intercept links in this document to save before following the link. window.navigation.addEventListener("navigate", on_navigate); const ccb = document.getElementById("CodeChat-sidebar") as - | HTMLIFrameElement - | undefined; + HTMLIFrameElement | undefined; ccb?.contentWindow?.navigation.addEventListener("navigate", on_navigate); document.addEventListener("click", on_click); // Provide basic error reporting for uncaught errors. diff --git a/client/src/CodeMirror-integration.mts b/client/src/CodeMirror-integration.mts index 51e7eb54..ea32eeb0 100644 --- a/client/src/CodeMirror-integration.mts +++ b/client/src/CodeMirror-integration.mts @@ -64,6 +64,7 @@ import { ChangeDesc, EditorState, Extension, + Prec, StateField, StateEffect, EditorSelection, @@ -128,6 +129,15 @@ const docBlockFreezeAnnotation = Annotation.define(); // location updates. const noAutosaveAnnotation = Annotation.define(); +// When this is included in a transaction, `DocBlockPlugin.update` won't capture +// focus into a doc block even though the resulting selection touches its +// boundary. Used by `docBlockNavKeymap`'s `ArrowLeft` handler when it +// deliberately stops the cursor at a code block's start (a doc block's `to` is +// numerically identical to the following code line's `from`, so without this +// annotation that stop would be indistinguishable from -- and incorrectly +// treated as -- entry into the preceding doc block). +const stayInCodeBlockAnnotation = Annotation.define(); + // Define a facet called when extensions produce an error. const exceptionSink = EditorView.exceptionSink.of((exception) => { show_toast(`Error: ${exception}`); @@ -439,11 +449,12 @@ class DocBlockWidget extends WidgetType { } eq(other: DocBlockWidget) { + // Order these to do the fastest comparisons first. return ( - other.indent === this.indent && + other.is_user_change == this.is_user_change && other.delimiter === this.delimiter && - other.contents === this.contents && - other.is_user_change == this.is_user_change + other.indent === this.indent && + other.contents === this.contents ); } @@ -453,11 +464,26 @@ class DocBlockWidget extends WidgetType { const wrap = document.createElement("div"); wrap.className = "CodeChat-doc"; wrap.innerHTML = - // This doc block's indent. TODO: allow paste, but must only allow - // pasting whitespace. - `
${sanitize_html(this.indent)}
` + + )}>${this.indent}` + // The contents of this doc block. Make it focusable by assigning a // tab stop, but not editable (until it's replaced by the TinyMCE // editor). @@ -475,18 +501,26 @@ class DocBlockWidget extends WidgetType { // "Update a DOM element created by a widget of the same type (but // different, non-eq content) to reflect this widget." updateDOM(dom: HTMLElement, _view: EditorView): boolean { - // If this change was produced by a user edit, then the DOM was already - // updated, both for the indent and contents. Stop here. - if (this.is_user_change) { + // If this change was produced by a user edit and the DOM to "update" is + // a TinyMCE editor, then the DOM was already updated. Stop here. + const [contents_div, is_tinymce] = get_contents(dom); + if (this.is_user_change && is_tinymce) { return true; } - (dom.childNodes[0] as HTMLDivElement).innerHTML = sanitize_html( - this.indent, - ); - // The contents div could be a TinyMCE instance, or just a plain div. - // Handle both cases. - const [contents_div, is_tinymce] = get_contents(dom); + // Update the indent and delimiter. Assume both have already been + // sanitized: the server only allows whitespace for the indent; only + // specific, safe delimiters are allowed. The Client only allows editing + // the indent, and only whitespace is allowed there as well. + (dom.childNodes[0] as HTMLDivElement).innerHTML = this.indent; + dom.dataset.delimiter = this.delimiter; + + // Update the contents. The contents div could be a TinyMCE instance, or + // just a plain div. Handle both cases. Again, we assume sanitized + // content, since this comes from the server (which uses Ammonia) or + // TinyMCE (which uses a + // [sanitizer](https://www.tiny.cloud/docs/tinymce/latest/security/#sanitizing-html-input-to-protect-against-xss-attacks) + // for all user input). window.MathJax?.typesetClear?.([contents_div]); if (is_tinymce) { // Save the cursor location before the update, then restore it @@ -504,24 +538,24 @@ class DocBlockWidget extends WidgetType { mathJaxTypeset(contents_div); // Indicate the update was successful. TODO: but, contents are still - // pending... + // pending if it contains math... return true; } ignoreEvent(event: Event) { // Avoid handling other events, since this causes // [weird problems with event routing](https://discuss.codemirror.net/t/how-to-get-focusin-events-on-a-custom-widget-decoration/6792). - if (event.type === "focusin" || event.type === "input") { - return false; - } else { - return true; - } + // `focusout` is also let through: `DocBlockPlugin`'s `focusout` handler + // needs it to turn off the indent's `contenteditable` once it loses + // focus (see the inline `onmousedown` handler above, which turns it + // on). + return event.type !== "focusin" && event.type !== "focusout"; } // Per the [docs](https://codemirror.net/docs/ref/#view.WidgetType.destroy), // "This is called when the an instance of the widget is removed from the // editor view." - destroy(dom: HTMLElement): void { + destroy(dom: HTMLElement) { const [contents_div, is_tinymce] = get_contents(dom); // Forget about any typeset math in this node. window.MathJax?.typesetClear?.([contents_div]); @@ -538,13 +572,6 @@ class DocBlockWidget extends WidgetType { } } -// Native DOM sanitizer. -const sanitize_html = (html: string) => { - const div = document.createElement("div"); - div.textContent = html; - return div.innerHTML; -}; - // Typeset the provided node; taken from the // [MathJax docs](https://docs.mathjax.org/en/latest/web/typeset.html#handling-asynchronous-typesetting). export const mathJaxTypeset = async ( @@ -755,6 +782,10 @@ const on_dirty = ( // following `Dirty` events are genuine. ignoreTinyMceDirty = false; await mathJaxTypeset(contents_div); + // When editing large doc blocks, they may be deleted then re-created by + // CodeMirror, which causes unexpected scrolling. To avoid this, save + // then restore the scroll after updating CodeMirror. + const currentScrollTop = current_view.scrollDOM.scrollTop; current_view.dispatch({ effects: [ updateDocBlock.of({ @@ -765,9 +796,208 @@ const on_dirty = ( }), ], }); + requestAnimationFrame( + () => (current_view.scrollDOM.scrollTop = currentScrollTop), + ); + }); +}; + +// Keyboard navigation between code and doc blocks +// ----------------------------------------------- +// +// Doc blocks are `Decoration.replace` widgets drawn over empty lines in the +// document, so CodeMirror's default cursor movement treats them as an atomic +// region and arrow keys skip over them to the next code block. The keymap below +// intercepts the arrow keys and, when the cursor would move into a doc block, +// dispatches a CodeMirror selection into that block's range instead. That +// selection change is then picked up by `DocBlockPlugin.update`, which focuses +// the block's contents div (the `focusin` handler promotes it to TinyMCE). This +// keeps a single focus path -- the same one used for mouse clicks and +// IDE-driven cursor sync. +// +// Given a doc position `pos`, return the range (`from`/`to`) of the doc block +// that starts exactly at `pos`, or `null` if there isn't one. Doc blocks can +// sit back-to-back (sharing a boundary position with a neighboring doc block), +// so this looks for an exact match on `from` rather than any block that merely +// touches `pos` -- otherwise, at a shared boundary, the block ending at `pos` +// could be returned instead of the one starting there. +const doc_block_starting_at = ( + view: EditorView, + pos: number, +): { from: number; to: number } | null => { + let found: { from: number; to: number } | null = null; + view.state.field(docBlockField).between(pos, pos, (from, to, _deco) => { + if (from === pos) { + found = { from, to }; + return false; + } }); + return found; }; +// Same as `doc_block_starting_at`, but looks for a doc block that ends exactly +// at `pos`. +const doc_block_ending_at = ( + view: EditorView, + pos: number, +): { from: number; to: number } | null => { + let found: { from: number; to: number } | null = null; + view.state.field(docBlockField).between(pos, pos, (from, to, _deco) => { + if (to === pos) { + found = { from, to }; + return false; + } + }); + return found; +}; + +// Move the CodeMirror selection to `pos` (an edge of a doc block range). The +// `DocBlockPlugin.update` handler reacts to the resulting selection change by +// focusing the block. Returns `true` so the keymap reports the key as handled. +const select_doc_block_edge = (view: EditorView, pos: number): boolean => { + view.dispatch({ selection: { anchor: pos } }); + return true; +}; + +// A keymap (registered at high precedence) that moves the selection into an +// adjacent doc block on arrow-key navigation. Entering from above (ArrowDown, +// ArrowRight) lands the selection at the block's start; entering from below +// (ArrowUp, ArrowLeft) lands it at the block's end. +export const docBlockNavKeymap = keymap.of([ + { + // Down arrow at the bottom of a code block: enter the doc block below, + // caret at its start. Look right after the current line's contents, + // which is where a following doc block's decoration would begin. A + // line's `.to` is the position of (before) its own trailing newline; + // the doc block placeholder that follows starts one position later, + // right after that newline -- hence `+ 1` (see the matching + // `main.head + 1` in the `ArrowRight` handler below, which lands on the + // same position). Chaining from one doc block into the next (once focus + // has actually entered a doc block) happens outside CodeMirror entirely + // -- see `DocBlockPlugin`'s `focusin` handler -- so this keymap only + // ever needs to handle the first entry from a code line; a `main.head` + // that happens to equal a doc block's `to` (this doc block's own + // placeholder boundary) is just the following code line's start, not a + // sign we're "already chained" out of it. + key: "ArrowDown", + run: (view) => { + const { main } = view.state.selection; + const search_pos = view.state.doc.lineAt(main.head).to + 1; + const range = doc_block_starting_at(view, search_pos); + return range !== null + ? select_doc_block_edge(view, range.from) + : false; + }, + }, + { + // Up arrow at the top of a code block: enter the doc block above, caret + // at its end. Look right before the current line's contents, which is + // where a preceding doc block's decoration would end (see the + // `ArrowDown` comment above for why no "chained" check is needed here + // either). + key: "ArrowUp", + run: (view) => { + const { main } = view.state.selection; + const search_pos = view.state.doc.lineAt(main.head).from; + const range = doc_block_ending_at(view, search_pos); + return range !== null + ? select_doc_block_edge(view, range.to) + : false; + }, + }, + { + // Right arrow at the end of a line: if a doc block follows, enter it + // with the caret at its start. + key: "ArrowRight", + run: (view) => { + const { main } = view.state.selection; + if (!main.empty) { + return false; + } + const line = view.state.doc.lineAt(main.head); + if (main.head !== line.to) { + return false; + } + const range = doc_block_starting_at(view, main.head + 1); + return range !== null + ? select_doc_block_edge(view, range.from) + : false; + }, + }, + { + // Left arrow next to a doc block. CodeMirror's default cursor motion + // treats a doc block's `Decoration.replace` widget as atomic, so a + // single ArrowLeft press from the position right after the following + // code block's first line start (`line.from + 1`) jumps straight past + // that line's start and into the doc block, skipping the "beginning of + // the code block" stop entirely. Intercept only that specific press: + // land the cursor at the line's start instead. Every other position on + // the line (including the start itself, on a subsequent press) falls + // through to normal handling below. + key: "ArrowLeft", + run: (view) => { + const { main } = view.state.selection; + if (!main.empty) { + return false; + } + const line = view.state.doc.lineAt(main.head); + if (main.head === line.from + 1) { + // One character away from the line's start. If a doc block + // ends exactly at this line's start, the default motion would + // jump straight into it; land the cursor at the line's start + // instead, so a further ArrowLeft press is needed to enter the + // doc block. + if (doc_block_ending_at(view, line.from) !== null) { + view.dispatch({ + selection: { anchor: line.from }, + annotations: stayInCodeBlockAnnotation.of(true), + }); + return true; + } + return false; + } + if (main.head !== line.from) { + return false; + } + const range = doc_block_ending_at(view, main.head); + return range !== null + ? select_doc_block_edge(view, range.to) + : false; + }, + }, + { + // Home on a code line: same atomic-widget problem as ArrowLeft above, + // but with no "second press" case to fall through to -- Home always + // means "stay on this line," so if a doc block ends exactly at the + // line's start, always stop the cursor there ourselves instead of + // letting the default motion (or `DocBlockPlugin.update`) treat it as + // entry into that doc block. This includes the case where the cursor + // is already at the line's start (a second, redundant Home press): + // even though the selection doesn't move, we still need to dispatch + // with `stayInCodeBlockAnnotation` so `DocBlockPlugin.update` doesn't + // treat the (unchanged) selection as entry into the preceding doc + // block -- falling through to `false` here would let the default Home + // command dispatch a plain selection update instead, without that + // annotation. + key: "Home", + run: (view) => { + const { main } = view.state.selection; + if (!main.empty) { + return false; + } + const line = view.state.doc.lineAt(main.head); + if (doc_block_ending_at(view, line.from) !== null) { + view.dispatch({ + selection: { anchor: line.from }, + annotations: stayInCodeBlockAnnotation.of(true), + }); + return true; + } + return false; + }, + }, +]); + // Handle cursor movement and mouse selection in a doc block. export const DocBlockPlugin = ViewPlugin.fromClass( class { @@ -779,6 +1009,30 @@ export const DocBlockPlugin = ViewPlugin.fromClass( // when the editor isn't focused, highlight the relevant line or // something similar. if (update.selectionSet && update.view.hasFocus) { + // If focus is currently in a doc block's indent (made editable + // by the inline `onmousedown` handler in + // `DocBlockWidget.toDOM`), don't steal it away into the + // contents div. + if ( + (document.activeElement as HTMLElement | null)?.closest( + ".CodeChat-doc-indent", + ) + ) { + return; + } + // If one of this update's transactions deliberately stopped the + // cursor at a code block's start (see + // `stayInCodeBlockAnnotation`), don't treat the resulting + // selection -- which sits at the same position as the preceding + // doc block's `to` -- as entry into that doc block. + if ( + update.transactions.some( + (tr) => + tr.annotation(stayInCodeBlockAnnotation) === true, + ) + ) { + return; + } // See if the new main selection falls within a doc block. const main_selection = update.state.selection.main; update.state @@ -811,10 +1065,64 @@ export const DocBlockPlugin = ViewPlugin.fromClass( return; } - // TODO: currently, posToDom never gives us a doc - // block, even when the from/to is correct. So, we - // never get here. - (dom.childNodes[1] as HTMLElement).focus(); + // Focus the contents div. This fires the `focusin` + // handler, which promotes the block to TinyMCE. + const contents = dom.childNodes[1] as HTMLElement; + contents.focus(); + + // Place the caret at the natural edge: when the + // selection landed at the block's start (entered + // from above), put the caret at the start; when it + // landed at the end (entered from below), put it at + // the end. Once TinyMCE initializes it preserves + // this selection, so the edge placement carries + // over. + const at_end = main_selection.head >= to; + const range = document.createRange(); + // Walk to the first/last actual text node under + // `contents`, rather than using + // `selectNodeContents` + `collapse` (which anchors + // the selection on `contents` itself, at a + // childNodes-index boundary). `saveSelection` + // (called later, when this doc block is promoted to + // TinyMCE) walks up from + // `window.getSelection().anchorNode` looking for an + // *ancestor* with the `CodeChat-doc-contents` + // class; if the anchor node already *is* that div, + // the walk's loop body never runs and it returns an + // empty `selection_path`, silently dropping this + // edge placement and leaving the caret wherever + // TinyMCE's own init happens to put it (its start). + // Anchoring on a text node instead keeps the walk + // -- and thus the edge placement -- intact. + let edge_node: Node = contents; + while ( + at_end + ? edge_node.lastChild + : edge_node.firstChild + ) { + edge_node = at_end + ? edge_node.lastChild! + : edge_node.firstChild!; + } + if (edge_node.nodeType === Node.TEXT_NODE) { + const offset = at_end + ? (edge_node.textContent?.length ?? 0) + : 0; + range.setStart(edge_node, offset); + range.setEnd(edge_node, offset); + } else { + // No text node found (e.g. an empty doc block); + // fall back to the previous, element-anchored + // behavior. + range.selectNodeContents(contents); + // `collapse(true)` -> start, `collapse(false)` + // -> end. + range.collapse(!at_end); + } + const sel = window.getSelection(); + sel?.removeAllRanges(); + sel?.addRange(range); }, ); } @@ -889,6 +1197,18 @@ export const DocBlockPlugin = ViewPlugin.fromClass( if (!contents_div.isConnected) { return; } + // Note whether this doc block still genuinely has focus + // before any of the DOM surgery below runs (which + // removes `contents_div` from the document, making + // `document.activeElement` an unreliable way to answer + // this question afterwards). If the user has since + // clicked or navigated elsewhere while this promotion + // was in flight, don't steal focus back to this (now + // stale) doc block once the promotion finishes -- see + // the check below. + const still_focused = target.contains( + document.activeElement, + ); // Create the TinyMCE instance if necessary. Note the // use of `==` here to check for `null` (TinyMCE is // loaded, but no instance exists) and `undefined` @@ -1074,11 +1394,22 @@ export const DocBlockPlugin = ViewPlugin.fromClass( await mathJaxTypeset(tinymce_div); // This process causes TinyMCE to lose focus. Restore - // that. However, this causes TinyMCE to lose the - // selection, which the next bit of code then restores. - // When the doc block is longer than a screen, omitting - // the `preventScroll` parameter causes this to scroll - // to the top of the doc block, which is incorrect. + // that -- but only if focus was still genuinely in this + // doc block just before the DOM surgery above began + // (see `still_focused`). Unconditionally focusing here + // would otherwise steal focus back to this (now stale) + // doc block even after the user clicked or navigated + // elsewhere while this promotion was in flight. + // Restoring the selection is skipped too, since it's + // meaningless once focus has moved on. + if (!still_focused) { + return; + } + // However, this causes TinyMCE to lose the selection, + // which the next bit of code then restores. When the + // doc block is longer than a screen, omitting the + // `preventScroll` parameter causes this to scroll to + // the top of the doc block, which is incorrect. tinymce_div.focus({ preventScroll: true }); // Copy the selection over to TinyMCE by indexing the @@ -1088,6 +1419,27 @@ export const DocBlockPlugin = ViewPlugin.fromClass( } return false; }, + + // The indent of a doc block is only editable while it's being + // clicked on/focused; otherwise, it's plain (uneditable) text. This + // keeps it out of the keyboard/IDE-driven navigation path (see the + // "Keyboard navigation" section above), which only ever focuses the + // contents div. Turning it editable on click is handled by an + // inline `onmousedown` attribute in `DocBlockWidget.toDOM` rather + // than here -- see the comment there for why a `ViewPlugin` + // `eventHandlers.mousedown` handler doesn't work for this. + // + // Once the indent loses focus, make it uneditable again. + focusout: (event: FocusEvent, _view: EditorView) => { + const indent_div = (event.target as HTMLElement)?.closest( + ".CodeChat-doc-indent", + ) as HTMLDivElement | null; + if (indent_div === null) { + return false; + } + indent_div.contentEditable = "false"; + return false; + }, }, }, ); @@ -1297,6 +1649,10 @@ export const CodeMirror_load = async ( { extensions: [ DocBlockPlugin, + // Move focus into adjacent doc blocks on arrow-key + // navigation. High precedence so it runs before the default + // arrow-key commands in `basicSetup`. + Prec.high(docBlockNavKeymap), parser, basicSetup, EditorView.lineWrapping, @@ -1408,7 +1764,7 @@ export const scroll_to_line = ( } // If a scroll position is provided, use it; otherwise, scroll the // cursor into the current view. - if (scroll_line == undefined) { + if (scroll_line === undefined) { dispatch_data.scrollIntoView = true; } } @@ -1422,6 +1778,24 @@ export const scroll_to_line = ( // Run it. current_view?.dispatch(dispatch_data); + + // Restore the previous horizontal scroll position, overriding whatever + // `scrollIntoView` set. Defer to the next frame so this runs after + // CodeMirror has applied its own scroll from the transaction above. + if (scroll_line !== undefined) { + // With line wrapping enabled, the only source of horizontal scroll is a + // doc block containing a long, non-wrapping line. CodeMirror's + // `scrollIntoView` can't measure a position inside such a block + // reliably and pins `scrollLeft` to its maximum regardless of the `x` + // option. We only want to scroll vertically, so capture the horizontal + // position now and restore it after the dispatch. + const prev_scroll_left = current_view?.scrollDOM.scrollLeft; + requestAnimationFrame(() => { + if (current_view) { + current_view.scrollDOM.scrollLeft = prev_scroll_left; + } + }); + } }; // Apply a `StringDiff` to the before string to produce the after string. diff --git a/client/src/css/CodeChatEditor.css b/client/src/css/CodeChatEditor.css index 7f284f05..73d557cb 100644 --- a/client/src/css/CodeChatEditor.css +++ b/client/src/css/CodeChatEditor.css @@ -138,6 +138,9 @@ body { * `
` contains the \ */ display: flex; padding: 0px 2px 0px 6px; + /* Establish a positioning context for an empty `.CodeChat-doc-indent`; + see below. */ + position: relative; } /* Preserve whitespace in the indent of a doc block. */ @@ -149,6 +152,33 @@ body { tab-size: 4; } +/* An empty indent would otherwise collapse to a zero-size element, which + isn't reliably clickable (a real mousedown/click can't hit-test a + too-small target -- the browser resolves the click point to whatever + sits behind/beside it instead) -- so it could never be focused to become + editable (see the inline `onmousedown` handler in `DocBlockWidget.toDOM` + and the `focusout` handler in `DocBlockPlugin`, which toggle + `contenteditable` on and off). Give it a nonzero, clickable size via + `position: absolute` rather than sizing it in normal flow (e.g. + `min-width`): per the + [Flexbox spec](https://www.w3.org/TR/css-flexbox-1/#abspos-items), an + absolutely-positioned flex item is removed from flex layout entirely, so + this can't shift `.CodeChat-doc-contents`'s horizontal start away from its + natural position -- which matters because the browser's native + caret-boundary walk (used for arrow-key navigation between adjacent doc + blocks; see `docBlockNavKeymap` in `CodeMirror-integration.mts`) tracks + the caret's horizontal position across lines, and a shifted contents + start throws that off. Position it at the indent's usual (here, zero) + offset from the block's left padding, so it visually and functionally + sits where the (empty) indent belongs. */ +.CodeChat-doc-indent:empty { + position: absolute; + left: 0; + top: 0; + width: 1ch; + height: 100%; +} + /* Reset what CodeMirror messes up for doc blocks. */ .CodeChat-doc-contents { font-family: inherit; @@ -163,7 +193,7 @@ body { attribute is only visible briefly, but this eliminated that visual flicker. */ .CodeChat-doc-contents.mce-edit-focus, .CodeChat-doc-contents:focus-visible { - outline-width: 0px; + outline: 0px; } /* Used to hide the TinyMCE editor instance when it's not in use. */ diff --git a/extensions/VSCode/Cargo.lock b/extensions/VSCode/Cargo.lock index 06521437..06f4234c 100644 --- a/extensions/VSCode/Cargo.lock +++ b/extensions/VSCode/Cargo.lock @@ -72,7 +72,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand 0.10.1", + "rand 0.10.2", "sha1", "smallvec", "tokio", @@ -302,14 +302,13 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "ammonia" -version = "4.1.2" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e913097e1a2124b46746c980134e8c954bc17a6a59bb3fde96f088d126dde6" +checksum = "68b9d3370580a12f4b7a10fdcc18b28942c083ba570e3d954fe59d10951b85a2" dependencies = [ - "cssparser 0.35.0", - "html5ever 0.35.0", + "cssparser 0.37.0", + "html5ever", "maplit", - "tendril 0.4.3", "url", ] @@ -380,9 +379,9 @@ checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "arc-swap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" +checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" dependencies = [ "rustversion", ] @@ -403,9 +402,9 @@ dependencies = [ [[package]] name = "assertables" -version = "9.9.0" +version = "10.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "627b0b35c347252505ec6c078827dfcecc4e9dcfa931c54c54066f9245ac752b" +checksum = "b3c16d80246a076246d8b525d9f404543e90fe0818636cd89c249c2a4bee3bb1" dependencies = [ "regex", "walkdir", @@ -471,15 +470,6 @@ dependencies = [ "wyz", ] -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - [[package]] name = "block-buffer" version = "0.12.1" @@ -586,9 +576,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.65" +version = "1.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" dependencies = [ "find-msvc-tools", "jobserver", @@ -609,7 +599,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" dependencies = [ "cfg-if", - "cpufeatures 0.3.0", + "cpufeatures", "rand_core 0.10.1", ] @@ -683,7 +673,7 @@ dependencies = [ [[package]] name = "codechat-editor-server" -version = "0.1.59" +version = "0.1.60" dependencies = [ "actix-files", "actix-http", @@ -702,7 +692,7 @@ dependencies = [ "dunce", "futures-util", "htmd", - "html5ever 0.39.0", + "html5ever", "htmlize", "imara-diff", "indoc", @@ -721,7 +711,7 @@ dependencies = [ "pest_derive", "phf 0.14.0", "pulldown-cmark 0.13.4", - "rand 0.10.1", + "rand 0.10.2", "regex", "serde", "serde_json", @@ -741,7 +731,7 @@ dependencies = [ [[package]] name = "codechat-editor-vscode-extension" -version = "0.1.59" +version = "0.1.60" dependencies = [ "codechat-editor-server", "log", @@ -867,15 +857,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "417bef24afe1460300965a25ff4a24b8b45ad011948302ec221e8a0a81eb2c79" -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - [[package]] name = "cpufeatures" version = "0.3.0" @@ -896,9 +877,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -906,28 +887,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.7" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crypto-common" @@ -953,14 +924,12 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.35.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e901edd733a1472f944a45116df3f846f54d37e67e68640ac8bb69689aca2aa" +checksum = "8c9cdaae01d5ed7882b04d795e7f752f46ff52d2fa3b50a20d28c464510bba98" dependencies = [ - "cssparser-macros", "dtoa-short", "itoa", - "phf 0.11.3", "smallvec", ] @@ -985,9 +954,9 @@ dependencies = [ [[package]] name = "ctor" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01334b89b69ff726750c5ce5073fc8bd860e99aa9a8fc5ca11b04730e3aee97a" +checksum = "fb22e947478ccf9dc44d8922042c677a63fbb88f2cb468521d1145816e5087cb" [[package]] name = "ctutils" @@ -1067,25 +1036,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer 0.10.4", - "crypto-common 0.1.7", -] - [[package]] name = "digest" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ - "block-buffer 0.12.1", + "block-buffer", "const-oid", - "crypto-common 0.2.2", + "crypto-common", "ctutils", ] @@ -1243,7 +1202,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.9", ] [[package]] @@ -1288,16 +1247,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - [[package]] name = "futures" version = "0.3.32" @@ -1386,16 +1335,6 @@ dependencies = [ "slab", ] -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "getrandom" version = "0.2.17" @@ -1521,7 +1460,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" dependencies = [ - "digest 0.11.3", + "digest", ] [[package]] @@ -1529,22 +1468,11 @@ name = "htmd" version = "0.5.4" source = "git+https://github.com/bjones1/htmd.git?branch=dom-interface#deafeb4b579530a94314828218cfbda79c615ef8" dependencies = [ - "html5ever 0.39.0", + "html5ever", "markup5ever_rcdom", "phf 0.13.1", ] -[[package]] -name = "html5ever" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55d958c2f74b664487a2035fe1dadb032c48718a03b63f3ab0b8537db8549ed4" -dependencies = [ - "log", - "markup5ever 0.35.0", - "match_token", -] - [[package]] name = "html5ever" version = "0.39.0" @@ -1552,7 +1480,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8" dependencies = [ "log", - "markup5ever 0.39.0", + "markup5ever", ] [[package]] @@ -1596,15 +1524,15 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" +checksum = "15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15" [[package]] name = "hybrid-array" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" dependencies = [ "typenum", ] @@ -1738,9 +1666,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b915661dd01db3f05050265b2477bcc6527b3792388e2749b41623cc592be67d" +checksum = "fe112b004901c62c2faa11f4f75e9864e0cc5af8da71c9115d184a3aa888749f" dependencies = [ "crossbeam-deque", "globset", @@ -1791,9 +1719,9 @@ dependencies = [ [[package]] name = "inotify" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533e68a5842e734946fe159fb03fc9bbbb254f590dd0d8ad321ae5ff7beca2c1" +checksum = "dd854a95a4ac672fed8c054136039fd32c22cf039ff09ead7280afe920486483" dependencies = [ "bitflags", "inotify-sys", @@ -1802,9 +1730,9 @@ dependencies = [ [[package]] name = "inotify-sys" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +checksum = "c033f80b2c113cdf91ab7a33faa9cbc014726dcad99880c8609af2a370edf37d" dependencies = [ "libc", ] @@ -1890,11 +1818,11 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] @@ -1911,9 +1839,9 @@ dependencies = [ [[package]] name = "json-escape-simd" -version = "3.0.2" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e770254dd7802184595b1d30da2a15cb72569e2aca2b177aef8d22eac8a693" +checksum = "2a18a0eb3c0a783620d2ae8cdda9590aae18b1608964ee9c7c43162562786424" [[package]] name = "kqueue" @@ -1965,9 +1893,9 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" dependencies = [ "libc", ] @@ -2094,29 +2022,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - [[package]] name = "maplit" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" -[[package]] -name = "markup5ever" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311fe69c934650f8f19652b3946075f0fc41ad8757dbb68f1ca14e7900ecc1c3" -dependencies = [ - "log", - "tendril 0.4.3", - "web_atoms 0.1.3", -] - [[package]] name = "markup5ever" version = "0.39.0" @@ -2124,8 +2035,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de" dependencies = [ "log", - "tendril 0.5.0", - "web_atoms 0.2.5", + "tendril", + "web_atoms", ] [[package]] @@ -2134,23 +2045,12 @@ version = "0.39.0+unofficial" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ac010f19d6c4af81eeb4018a39d7a115de9d285af45c126a4ac02e6fc5716b7" dependencies = [ - "html5ever 0.39.0", - "markup5ever 0.39.0", - "tendril 0.5.0", + "html5ever", + "markup5ever", + "tendril", "xml5ever", ] -[[package]] -name = "match_token" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - [[package]] name = "matchers" version = "0.2.0" @@ -2173,14 +2073,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" dependencies = [ "cfg-if", - "digest 0.11.3", + "digest", ] [[package]] name = "memchr" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "mime" @@ -2240,6 +2140,15 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", +] + [[package]] name = "minreq" version = "3.0.0" @@ -2266,9 +2175,9 @@ checksum = "9bb517913cfcfb9eeda59f36020269075a152701a01606c612f547e4890be399" [[package]] name = "napi" -version = "3.9.4" +version = "3.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41bda2ac390efb5e8d22025d925ccc3f3807d8c1bea6d19b36127247c4b8f83" +checksum = "0c71997d6f7ad4a756966e452426848ac27d3b37a295302d63afbbcce0270f93" dependencies = [ "bitflags", "ctor", @@ -2288,9 +2197,9 @@ checksum = "c9c366d2c8c60b86fa632df75f745509b52f9128f91a6bad4c796e44abb505e1" [[package]] name = "napi-derive" -version = "3.5.7" +version = "3.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61d66f70256ad5aef58659966064471d0ad90e2897bc36a5a5e0389c85aabc1e" +checksum = "d4ba572deef53e2c386759a8c2014175a62679d74ff83adc205c8bc0e0285727" dependencies = [ "convert_case 0.11.0", "ctor", @@ -2302,9 +2211,9 @@ dependencies = [ [[package]] name = "napi-derive-backend" -version = "5.0.5" +version = "5.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b4b08f15eed7a2a20c3f4c6314013fc3ac890a3afa9892b594485299ebdb2d" +checksum = "ddd961eb2aa8965e3f29722d754f3a86907eb1984e2fbcbe3fe87b9a02d6bfba" dependencies = [ "convert_case 0.11.0", "proc-macro2", @@ -2403,9 +2312,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" dependencies = [ "num-integer", "num-traits", @@ -2519,11 +2428,11 @@ checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" [[package]] name = "oxc-browserslist" -version = "3.0.6" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b87743c2f6963036971ca587539cd9235693d953dc018a734014241afb20d5b" +checksum = "373741e2febe6df186995b668f295e46fd402ee12f312ea2fda8b3b6312c0885" dependencies = [ - "flate2", + "miniz_oxide 0.9.1", "postcard", "rustc-hash", "serde", @@ -2957,9 +2866,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.6" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +checksum = "47627dd7305c6a2d6c8c6bcd24c5a4c17dbbf425f4f9c5313e724b38fc9782e9" dependencies = [ "memchr", "ucd-trie", @@ -2967,9 +2876,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.6" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" +checksum = "4b4254325ecad416ab689e27ba51da03ba01a9632bc6e108f5fe7c3c4ad29d58" dependencies = [ "pest", "pest_generator", @@ -2977,9 +2886,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.6" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" +checksum = "6c4c0e91ead7a8f7acecbca6f003fc2e8282b1dbe2dd9c9d2f16aba42995e0a7" dependencies = [ "pest", "pest_meta", @@ -2990,12 +2899,11 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.6" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" +checksum = "f9744bc48116fee06334924bb5f2bad41eed5e89bd26e29b0b799f9a3f82c210" dependencies = [ "pest", - "sha2 0.10.9", ] [[package]] @@ -3183,8 +3091,8 @@ dependencies = [ "hmac", "md-5", "memchr", - "rand 0.10.1", - "sha2 0.11.0", + "rand 0.10.2", + "sha2", "stringprep", ] @@ -3363,9 +3271,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" dependencies = [ "chacha20", "getrandom 0.4.3", @@ -3507,9 +3415,9 @@ dependencies = [ [[package]] name = "rustc-hash" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustc_version" @@ -3535,9 +3443,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "ryu" @@ -3678,19 +3586,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" dependencies = [ "cfg-if", - "cpufeatures 0.3.0", - "digest 0.11.3", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "digest 0.10.7", + "cpufeatures", + "digest", ] [[package]] @@ -3700,8 +3597,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" dependencies = [ "cfg-if", - "cpufeatures 0.3.0", - "digest 0.11.3", + "cpufeatures", + "digest", ] [[package]] @@ -3816,19 +3713,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "string_cache" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" -dependencies = [ - "new_debug_unreachable", - "parking_lot", - "phf_shared 0.11.3", - "precomputed-hash", - "serde", -] - [[package]] name = "string_cache" version = "0.9.0" @@ -3842,18 +3726,6 @@ dependencies = [ "serde", ] -[[package]] -name = "string_cache_codegen" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", -] - [[package]] name = "string_cache_codegen" version = "0.6.1" @@ -3936,23 +3808,11 @@ dependencies = [ [[package]] name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "tendril" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4790fc369d5a530f4b544b094e31388b9b3a37c0f4652ade4505945f5660d24" +checksum = "5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08" dependencies = [ "new_debug_unreachable", - "utf-8", ] [[package]] @@ -4031,9 +3891,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.51" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c17d80feb7334b40c484e45ed1a5273dfd8bfda537c3be2e74a06a6686f327" +checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" dependencies = [ "deranged", "num-conv", @@ -4051,9 +3911,9 @@ checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.30" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcef1a61bdb119096e153208ec5cbec23944ce8bca13be5c7f60c634f7403935" +checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f" dependencies = [ "num-conv", "time-core", @@ -4131,7 +3991,7 @@ dependencies = [ "pin-project-lite", "postgres-protocol", "postgres-types", - "rand 0.10.1", + "rand 0.10.2", "socket2 0.6.4", "tokio", "tokio-util", @@ -4353,12 +4213,6 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -4509,18 +4363,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "web_atoms" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414" -dependencies = [ - "phf 0.11.3", - "phf_codegen 0.11.3", - "string_cache 0.8.9", - "string_cache_codegen 0.5.4", -] - [[package]] name = "web_atoms" version = "0.2.5" @@ -4529,8 +4371,8 @@ checksum = "075474b12bcb3d2e3d4546580e9de478eeeead668a1761e2a8860c836b7ef297" dependencies = [ "phf 0.13.1", "phf_codegen 0.13.1", - "string_cache 0.9.0", - "string_cache_codegen 0.6.1", + "string_cache", + "string_cache_codegen", ] [[package]] @@ -4887,7 +4729,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ab627f34ff61b80d756180d556f9c68801d836d271b3b8c094504ceca69d221" dependencies = [ "log", - "markup5ever 0.39.0", + "markup5ever", ] [[package]] @@ -4915,18 +4757,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.52" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" +checksum = "75726053136156d419e285b9b7eddaaea9e3fea6ce32eed44a89901f0bd98de1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.52" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +checksum = "4714fd92cf900833d49538023a9b3915155210801d1c1169eba513b2addefd71" dependencies = [ "proc-macro2", "quote", diff --git a/extensions/VSCode/Cargo.toml b/extensions/VSCode/Cargo.toml index f4e1b0aa..2e3f3481 100644 --- a/extensions/VSCode/Cargo.toml +++ b/extensions/VSCode/Cargo.toml @@ -32,7 +32,7 @@ license = "GPL-3.0-only" name = "codechat-editor-vscode-extension" readme = "../README.md" repository = "https://github.com/bjones1/CodeChat_Editor" -version = "0.1.59" +version = "0.1.60" [lib] crate-type = ["cdylib"] diff --git a/extensions/VSCode/package.json b/extensions/VSCode/package.json index f08d3c4f..fd37de7d 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.1.59", + "version": "0.1.60", "activationEvents": [ "onCommand:extension.codeChatEditorActivate", "onCommand:extension.codeChatEditorDeactivate" @@ -80,28 +80,28 @@ "escape-html": "^1.0.3" }, "devDependencies": { - "@emnapi/core": "^1.11.1", - "@emnapi/runtime": "^1.11.1", + "@emnapi/core": "^1.11.2", + "@emnapi/runtime": "^1.11.2", "@eslint/js": "^10.0.1", "@napi-rs/cli": "^3.7.2", "@tybys/wasm-util": "^0.10.3", "@types/escape-html": "^1.0.4", "@types/node": "^24.13.2", "@types/vscode": "1.61.0", - "@typescript-eslint/eslint-plugin": "^8.62.0", - "@typescript-eslint/parser": "^8.62.0", + "@typescript-eslint/eslint-plugin": "^8.63.0", + "@typescript-eslint/parser": "^8.63.0", "@vscode/vsce": "^3.9.2", "chalk": "^5.6.2", "esbuild": "^0.28.1", - "eslint": "^10.5.0", + "eslint": "^10.6.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-import": "^2.32.0", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^5.5.6", "npm-run-all2": "^9.0.2", - "prettier": "^3.8.4", + "prettier": "^3.9.4", "typescript": "^6.0.3", - "typescript-eslint": "^8.62.0" + "typescript-eslint": "^8.63.0" }, "optionalDependencies": { "bufferutil": "^4.1.0" diff --git a/extensions/VSCode/pnpm-lock.yaml b/extensions/VSCode/pnpm-lock.yaml index c45ee8ab..c50071e7 100644 --- a/extensions/VSCode/pnpm-lock.yaml +++ b/extensions/VSCode/pnpm-lock.yaml @@ -13,17 +13,17 @@ importers: version: 1.0.3 devDependencies: '@emnapi/core': - specifier: ^1.11.1 - version: 1.11.1 + specifier: ^1.11.2 + version: 1.11.2 '@emnapi/runtime': - specifier: ^1.11.1 - version: 1.11.1 + specifier: ^1.11.2 + version: 1.11.2 '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.5.0) + version: 10.0.1(eslint@10.6.0) '@napi-rs/cli': specifier: ^3.7.2 - version: 3.7.2(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.13.2) + version: 3.7.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@24.13.2) '@tybys/wasm-util': specifier: ^0.10.3 version: 0.10.3 @@ -37,11 +37,11 @@ importers: specifier: 1.61.0 version: 1.61.0 '@typescript-eslint/eslint-plugin': - specifier: ^8.62.0 - version: 8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3))(eslint@10.5.0)(typescript@6.0.3) + specifier: ^8.63.0 + version: 8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3))(eslint@10.6.0)(typescript@6.0.3) '@typescript-eslint/parser': - specifier: ^8.62.0 - version: 8.62.0(eslint@10.5.0)(typescript@6.0.3) + specifier: ^8.63.0 + version: 8.63.0(eslint@10.6.0)(typescript@6.0.3) '@vscode/vsce': specifier: ^3.9.2 version: 3.9.2 @@ -52,32 +52,32 @@ importers: specifier: ^0.28.1 version: 0.28.1 eslint: - specifier: ^10.5.0 - version: 10.5.0 + specifier: ^10.6.0 + version: 10.6.0 eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@10.5.0) + version: 10.1.8(eslint@10.6.0) eslint-plugin-import: specifier: ^2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3))(eslint@10.5.0) + version: 2.32.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3))(eslint@10.6.0) eslint-plugin-node: specifier: ^11.1.0 - version: 11.1.0(eslint@10.5.0) + version: 11.1.0(eslint@10.6.0) eslint-plugin-prettier: specifier: ^5.5.6 - version: 5.5.6(eslint-config-prettier@10.1.8(eslint@10.5.0))(eslint@10.5.0)(prettier@3.8.4) + version: 5.5.6(eslint-config-prettier@10.1.8(eslint@10.6.0))(eslint@10.6.0)(prettier@3.9.4) npm-run-all2: specifier: ^9.0.2 version: 9.0.2 prettier: - specifier: ^3.8.4 - version: 3.8.4 + specifier: ^3.9.4 + version: 3.9.4 typescript: specifier: ^6.0.3 version: 6.0.3 typescript-eslint: - specifier: ^8.62.0 - version: 8.62.0(eslint@10.5.0)(typescript@6.0.3) + specifier: ^8.63.0 + version: 8.63.0(eslint@10.6.0)(typescript@6.0.3) optionalDependencies: bufferutil: specifier: ^4.1.0 @@ -123,16 +123,16 @@ packages: resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==} engines: {node: '>=20.0.0'} - '@azure/msal-browser@5.15.0': - resolution: {integrity: sha512-2NYT6v+eeQn8kmNddr9LnbXSvXbVELpmFMmfFvtRxD7I/5+5GlkMlncApeuRFj+mY6C9syOwQip1a0Y+TIbyiA==} + '@azure/msal-browser@5.16.0': + resolution: {integrity: sha512-Wc75FGnQgYpsm5jsOqn1H8AXsh8vXruA6vwip1nhjrJxwby7juxKAIVLr7csepmHiwdZGr6EwI5BlSc3PizEtQ==} engines: {node: '>=0.8.0'} - '@azure/msal-common@16.10.0': - resolution: {integrity: sha512-iYtjpanlv6963Jprs0MvzIap07V+QhultjQctfbEDQCflsDAEeO3R7XnVA5gk30fhoBFLdgJT7VqO0TGsEsN9w==} + '@azure/msal-common@16.11.0': + resolution: {integrity: sha512-UikJOtMwkFpZNzTH6Dqk8UTUPbow15zH3e0UjGYZy69lYENW/S05gMLhbxI2eonz66uALhIljvhsSMEb6+O30g==} engines: {node: '>=0.8.0'} - '@azure/msal-node@5.3.0': - resolution: {integrity: sha512-fXtJX811pX8y8QlrQqBSH6+plvWyKZDI0IxkheAcyAw9OtcpXyFivmTC7eGUqutLWaDlKXuQ3yOESD4zAmkjHg==} + '@azure/msal-node@5.3.1': + resolution: {integrity: sha512-sqqv3L1UOI4KDXonNtbxPYUgbSWVXqxvmmb6BUw9n4P/UXgG+cVur3dLWQN4Cz7qQ+UJROCCxMXlksm7gIq0Sw==} engines: {node: '>=20'} '@babel/code-frame@7.29.7': @@ -143,11 +143,11 @@ packages: resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@emnapi/core@1.11.1': - resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} + '@emnapi/core@1.11.2': + resolution: {integrity: sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==} - '@emnapi/runtime@1.11.1': - resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + '@emnapi/runtime@1.11.2': + resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} '@emnapi/wasi-threads@1.2.2': resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} @@ -907,8 +907,8 @@ packages: resolution: {integrity: sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==} engines: {node: '>= 20'} - '@octokit/request@10.0.10': - resolution: {integrity: sha512-KxNC2pTqqhszMNrf12ZRd4PonRgyJdsM4F/jySiddQK+DsRcfBtUvqn8t7UsyZhnRJHvX46OohDt5N3VqIWC2w==} + '@octokit/request@10.0.11': + resolution: {integrity: sha512-+s7HUxjfFqOMS9VlIwDffq0MikjSAK0gSpG73W+meAvVAvX4MBrHYTK5Bj3Uot55qFT4gzUtfzE4mGWY4Br8/Q==} engines: {node: '>= 20'} '@octokit/rest@22.0.1': @@ -1019,63 +1019,63 @@ packages: '@types/vscode@1.61.0': resolution: {integrity: sha512-9k5Nwq45hkRwdfCFY+eKXeQQSbPoA114mF7U/4uJXRBJeGIO7MuJdhF1PnaDN+lllL9iKGQtd6FFXShBXMNaFg==} - '@typescript-eslint/eslint-plugin@8.62.0': - resolution: {integrity: sha512-o+mpz7EYiMzXoySXiKmzlabIvTVqUuK5yLrAedRPRDA0IpPFMUV1IXt6OqljIxX/kumN6EjUYp41Hqelh6p/Dw==} + '@typescript-eslint/eslint-plugin@8.63.0': + resolution: {integrity: sha512-rvwSgqT+DHpWdzfSzPatRLm02a0GlESt++9iy3hLCDY4BgkaLcl8LBi9Yh7XGFBpwcBE/K3024QuXWTpbz4FfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.62.0 + '@typescript-eslint/parser': ^8.63.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.62.0': - resolution: {integrity: sha512-dzHeT2gySzZtLDsuqxU9AkYgIsQoHAHtRBpOqM+Ofzx1Bwrd2RcCjQJ+6iQbsHOIR6NS33bF2W1k3blN1zLDrA==} + '@typescript-eslint/parser@8.63.0': + resolution: {integrity: sha512-gwh4gvvlaVDKKxyfxMG+Gnu1u9X0OQBwyGLkbwB65dIzBKnxeRiJlNFqlI3zwVhNXJIs6qV7mlFCn/BIajlVig==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.62.0': - resolution: {integrity: sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==} + '@typescript-eslint/project-service@8.63.0': + resolution: {integrity: sha512-e5dh0/UI0ok53AlZ5wRkXCB32z/f2jUZqPR/ygAw5WYaSw8j9EoJWlS7wQjr/dmOaqWjnPIn2m+HhVPCMWGZVQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.62.0': - resolution: {integrity: sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==} + '@typescript-eslint/scope-manager@8.63.0': + resolution: {integrity: sha512-uUyfMWCnDSN8bCpcrY8nGP2BLkQ9Xn0GsipcONcpIDWhwhO4ZSyHvyS14U3X75mzxWxL3I2UZIrenTzdzcJO8A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.62.0': - resolution: {integrity: sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==} + '@typescript-eslint/tsconfig-utils@8.63.0': + resolution: {integrity: sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.62.0': - resolution: {integrity: sha512-+g5O3j0w2ldzC86Pv6fvbO/xhAonbJFIdf/MKQ1d30gndlsVzUOE83ldfSE15Qrl9fhFjK6AovHs5Wpp6vx86w==} + '@typescript-eslint/type-utils@8.63.0': + resolution: {integrity: sha512-Nzzh/OGxVCOjObjaj1CQF2RUasyYy2Jfuh+zZ3PjLzG2fYRriAiZLib9UKtO+CpQAS3YHiAS+ckZDclwqI1TPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.62.0': - resolution: {integrity: sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==} + '@typescript-eslint/types@8.63.0': + resolution: {integrity: sha512-xyLtl9DUBBFrcJS4x2pIqGLH68/tC2uOa4Z7pUteW09D3bXnnXUom4dyPikzWgB7llmIc1zoeI3aoUdC4rPK/Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.62.0': - resolution: {integrity: sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==} + '@typescript-eslint/typescript-estree@8.63.0': + resolution: {integrity: sha512-ygBkU+B7ex5UI/gKhaqexWev79uISfIv7XQCRNYO/jmD8rGLPyWLAb3KMRT6nd8Gt9bmUBi9+iX6tBdYfOY81Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.62.0': - resolution: {integrity: sha512-82r66fi9zYwZ+mTq3vKgwjbZ1PVk/DJzrXFLpG6RnBbdvH8TEGVHIs9H4d2drhkOzf0syZuD/OZvvlu6GDbP4g==} + '@typescript-eslint/utils@8.63.0': + resolution: {integrity: sha512-fUKaeAvrTuQg/Tgt3nliAUSZHJM6DlCcfyEmxCvlX8kieWSStBX+5O5Fnidtc3i2JrH+9c/GL4RY2iasd/GPTA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.62.0': - resolution: {integrity: sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==} + '@typescript-eslint/visitor-keys@8.63.0': + resolution: {integrity: sha512-UexrHGnGTpbuQHct2ExOc2ZcFbGUS9FOesCxxqdBGcpI1BxYu/LZ6U8Aq6/72XtF/qRBk9nhuGHFJIXXMhPMdw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typespec/ts-http-runtime@0.3.6': @@ -1249,8 +1249,8 @@ packages: brace-expansion@1.1.15: resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==} - brace-expansion@5.0.6: - resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + brace-expansion@5.0.7: + resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==} engines: {node: 18 || 20 || >=22} braces@3.0.3: @@ -1452,8 +1452,8 @@ packages: resolution: {integrity: sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==} engines: {ecmascript: '>= es5', node: '>=4'} - emnapi@1.11.1: - resolution: {integrity: sha512-kSRjhIcxjMFsBqk7ORvoc9aA5SBKDmecrtF5RMcmOTao0kD/zamaxsuTxMI8C1//wGUuvE7a+19pCE7AEhGVnA==} + emnapi@1.11.2: + resolution: {integrity: sha512-iMt/XQc69fFn2EvcU6tm14HmXKwyy0lnABugsQlqp6xFuZIUuO+ONVSg2mz+MTVF8WbC+bic65AvRXdoldALKg==} peerDependencies: node-addon-api: '>= 6.1.0' peerDependenciesMeta: @@ -1513,12 +1513,12 @@ packages: resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} engines: {node: '>= 0.4'} - es-to-primitive@1.3.1: - resolution: {integrity: sha512-CxN9N56HYfd2m/acc/NOFrZQsN9kU4eh+2kk6A707Kz1krH8tKmfrs5RnftB8WNX80T0NS7vSQsDOlg23diR2g==} + es-to-primitive@1.3.4: + resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==} engines: {node: '>= 0.4'} - es-toolkit@1.48.1: - resolution: {integrity: sha512-wfnXlwd5I75eXRtdD2vuEs50xHHESECDsGD7yiQnfFVNoa5522NwXEbmgo98LfiukSQHs+mBM7/YG3qKJB9/mQ==} + es-toolkit@1.49.0: + resolution: {integrity: sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==} esbuild@0.28.1: resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} @@ -1541,8 +1541,8 @@ packages: eslint-import-resolver-node@0.3.10: resolution: {integrity: sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==} - eslint-module-utils@2.13.0: - resolution: {integrity: sha512-bLohSkT6469rRs8czj0tLTD8vaeIS/whvPRJVjDr7IuoTT1k5DYDERlNycjDj/HkOlvQdYurmfZ/g3fG5bgeLQ==} + eslint-module-utils@2.14.0: + resolution: {integrity: sha512-W2WCRZ9Dqntd+2u8jJcVMV2PKulc6RdLgUUoh/yQr3uB6lo/ZOeGx11sv60/8S4QFFKNslAlWhr9u0Ef7ZW6Ig==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -1618,8 +1618,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.5.0: - resolution: {integrity: sha512-1y+7C+vi12bUK1IpZeaV3gsH9fHLBmPvYmPx42pvT/E9yG0IC8g3PUZZgp0+JLJl7ZDK0flc2gc+Aw9dpCvIsQ==} + eslint@10.6.0: + resolution: {integrity: sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -1674,8 +1674,8 @@ packages: fast-string-width@3.0.2: resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} + fast-uri@3.1.3: + resolution: {integrity: sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==} fast-wrap-ansi@0.2.2: resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} @@ -1722,8 +1722,8 @@ packages: fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - fs-extra@11.3.5: - resolution: {integrity: sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==} + fs-extra@11.3.6: + resolution: {integrity: sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==} engines: {node: '>=14.14'} function-bind@1.1.2: @@ -1832,8 +1832,8 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} ieee754@1.2.1: @@ -2004,8 +2004,8 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@4.2.0: - resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} + js-yaml@4.3.0: + resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} hasBin: true json-buffer@3.0.1: @@ -2066,8 +2066,8 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - linkify-it@5.0.1: - resolution: {integrity: sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==} + linkify-it@5.0.2: + resolution: {integrity: sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==} locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} @@ -2111,8 +2111,8 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} - markdown-it@14.2.0: - resolution: {integrity: sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==} + markdown-it@14.3.0: + resolution: {integrity: sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==} hasBin: true math-intrinsics@1.1.0: @@ -2184,8 +2184,8 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - node-abi@3.92.0: - resolution: {integrity: sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==} + node-abi@3.94.0: + resolution: {integrity: sha512-W5ZNO5KRPB5TkYmGVD9F6YqhsglXJzE6etpbmT+f6EQElhiX/UTG551cnsRGvLG3fyZEg9HwaDmNmj5nwJ4z9g==} engines: {node: '>=10'} node-addon-api@4.3.0: @@ -2274,8 +2274,8 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-map@7.0.4: - resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} + p-map@7.0.5: + resolution: {integrity: sha512-e8vJF4XdVkzqqSHguEMz41mQO1wKwxKm5ENrUJQUu9kLDCtn83cxbyHZcszr4QC5zEA7WffRRC4gsTecC7J9oA==} engines: {node: '>=18'} parse-json@8.3.0: @@ -2323,8 +2323,8 @@ packages: resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} engines: {node: '>=12'} pidtree@1.0.0: @@ -2357,8 +2357,8 @@ packages: resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==} engines: {node: '>=6.0.0'} - prettier@3.8.4: - resolution: {integrity: sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==} + prettier@3.9.4: + resolution: {integrity: sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==} engines: {node: '>=14'} hasBin: true @@ -2612,8 +2612,8 @@ packages: resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} engines: {node: '>=10.0.0'} - tar-fs@2.1.4: - resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + tar-fs@2.1.5: + resolution: {integrity: sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==} tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} @@ -2691,8 +2691,8 @@ packages: typed-rest-client@1.8.11: resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} - typescript-eslint@8.62.0: - resolution: {integrity: sha512-8QxXi+ZACKX0kaqO4gY8kn0RSD9gFfaHDWwjqtEN48aWCBkX4MJaufWN+c3BzlrXLOxfywDL8CaoqUwcRq4j4Q==} + typescript-eslint@8.63.0: + resolution: {integrity: sha512-xgwXyzG4sK9ALkBxbyGkTMMOS+imnW65iPhxCQMK83KhxyoDNW7l+IDqEf9vMdoUidHpOoS967RCq4eMiTexwQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -2884,8 +2884,8 @@ snapshots: '@azure/core-tracing': 1.3.1 '@azure/core-util': 1.13.1 '@azure/logger': 1.3.0 - '@azure/msal-browser': 5.15.0 - '@azure/msal-node': 5.3.0 + '@azure/msal-browser': 5.16.0 + '@azure/msal-node': 5.3.1 open: 10.2.0 tslib: 2.8.1 transitivePeerDependencies: @@ -2898,15 +2898,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@azure/msal-browser@5.15.0': + '@azure/msal-browser@5.16.0': dependencies: - '@azure/msal-common': 16.10.0 + '@azure/msal-common': 16.11.0 - '@azure/msal-common@16.10.0': {} + '@azure/msal-common@16.11.0': {} - '@azure/msal-node@5.3.0': + '@azure/msal-node@5.3.1': dependencies: - '@azure/msal-common': 16.10.0 + '@azure/msal-common': 16.11.0 jsonwebtoken: 9.0.3 '@babel/code-frame@7.29.7': @@ -2917,12 +2917,12 @@ snapshots: '@babel/helper-validator-identifier@7.29.7': {} - '@emnapi/core@1.11.1': + '@emnapi/core@1.11.2': dependencies: '@emnapi/wasi-threads': 1.2.2 tslib: 2.8.1 - '@emnapi/runtime@1.11.1': + '@emnapi/runtime@1.11.2': dependencies: tslib: 2.8.1 @@ -3008,9 +3008,9 @@ snapshots: '@esbuild/win32-x64@0.28.1': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.5.0)': + '@eslint-community/eslint-utils@4.9.1(eslint@10.6.0)': dependencies: - eslint: 10.5.0 + eslint: 10.6.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -3031,9 +3031,9 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.5.0)': + '@eslint/js@10.0.1(eslint@10.6.0)': optionalDependencies: - eslint: 10.5.0 + eslint: 10.6.0 '@eslint/object-schema@3.0.5': {} @@ -3106,7 +3106,7 @@ snapshots: '@inquirer/external-editor@3.0.3(@types/node@24.13.2)': dependencies: chardet: 2.2.0 - iconv-lite: 0.7.2 + iconv-lite: 0.7.3 optionalDependencies: '@types/node': 24.13.2 @@ -3177,22 +3177,22 @@ snapshots: optionalDependencies: '@types/node': 24.13.2 - '@napi-rs/cli@3.7.2(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.13.2)': + '@napi-rs/cli@3.7.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@24.13.2)': dependencies: '@inquirer/prompts': 8.5.2(@types/node@24.13.2) - '@napi-rs/cross-toolchain': 1.0.3(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) - '@napi-rs/wasm-tools': 1.0.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + '@napi-rs/cross-toolchain': 1.0.3(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@napi-rs/wasm-tools': 1.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) '@octokit/rest': 22.0.1 clipanion: 4.0.0-rc.4(typanion@3.14.0) colorette: 2.0.20 - emnapi: 1.11.1 - es-toolkit: 1.48.1 - js-yaml: 4.2.0 + emnapi: 1.11.2 + es-toolkit: 1.49.0 + js-yaml: 4.3.0 obug: 2.1.3 semver: 7.8.5 typanion: 3.14.0 optionalDependencies: - '@emnapi/runtime': 1.11.1 + '@emnapi/runtime': 1.11.2 transitivePeerDependencies: - '@emnapi/core' - '@napi-rs/cross-toolchain-arm64-target-aarch64' @@ -3209,10 +3209,10 @@ snapshots: - node-addon-api - supports-color - '@napi-rs/cross-toolchain@1.0.3(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + '@napi-rs/cross-toolchain@1.0.3(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': dependencies: - '@napi-rs/lzma': 1.4.5(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) - '@napi-rs/tar': 1.1.0(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + '@napi-rs/lzma': 1.4.5(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) + '@napi-rs/tar': 1.1.0(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) debug: 4.4.3 transitivePeerDependencies: - '@emnapi/core' @@ -3258,9 +3258,9 @@ snapshots: '@napi-rs/lzma-linux-x64-musl@1.4.5': optional: true - '@napi-rs/lzma-wasm32-wasi@1.4.5(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + '@napi-rs/lzma-wasm32-wasi@1.4.5(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': dependencies: - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -3275,7 +3275,7 @@ snapshots: '@napi-rs/lzma-win32-x64-msvc@1.4.5': optional: true - '@napi-rs/lzma@1.4.5(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + '@napi-rs/lzma@1.4.5(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': optionalDependencies: '@napi-rs/lzma-android-arm-eabi': 1.4.5 '@napi-rs/lzma-android-arm64': 1.4.5 @@ -3290,7 +3290,7 @@ snapshots: '@napi-rs/lzma-linux-s390x-gnu': 1.4.5 '@napi-rs/lzma-linux-x64-gnu': 1.4.5 '@napi-rs/lzma-linux-x64-musl': 1.4.5 - '@napi-rs/lzma-wasm32-wasi': 1.4.5(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + '@napi-rs/lzma-wasm32-wasi': 1.4.5(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) '@napi-rs/lzma-win32-arm64-msvc': 1.4.5 '@napi-rs/lzma-win32-ia32-msvc': 1.4.5 '@napi-rs/lzma-win32-x64-msvc': 1.4.5 @@ -3334,9 +3334,9 @@ snapshots: '@napi-rs/tar-linux-x64-musl@1.1.0': optional: true - '@napi-rs/tar-wasm32-wasi@1.1.0(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + '@napi-rs/tar-wasm32-wasi@1.1.0(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': dependencies: - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -3351,7 +3351,7 @@ snapshots: '@napi-rs/tar-win32-x64-msvc@1.1.0': optional: true - '@napi-rs/tar@1.1.0(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + '@napi-rs/tar@1.1.0(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': optionalDependencies: '@napi-rs/tar-android-arm-eabi': 1.1.0 '@napi-rs/tar-android-arm64': 1.1.0 @@ -3365,7 +3365,7 @@ snapshots: '@napi-rs/tar-linux-s390x-gnu': 1.1.0 '@napi-rs/tar-linux-x64-gnu': 1.1.0 '@napi-rs/tar-linux-x64-musl': 1.1.0 - '@napi-rs/tar-wasm32-wasi': 1.1.0(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + '@napi-rs/tar-wasm32-wasi': 1.1.0(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) '@napi-rs/tar-win32-arm64-msvc': 1.1.0 '@napi-rs/tar-win32-ia32-msvc': 1.1.0 '@napi-rs/tar-win32-x64-msvc': 1.1.0 @@ -3373,10 +3373,10 @@ snapshots: - '@emnapi/core' - '@emnapi/runtime' - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': dependencies: - '@emnapi/core': 1.11.1 - '@emnapi/runtime': 1.11.1 + '@emnapi/core': 1.11.2 + '@emnapi/runtime': 1.11.2 '@tybys/wasm-util': 0.10.3 optional: true @@ -3407,9 +3407,9 @@ snapshots: '@napi-rs/wasm-tools-linux-x64-musl@1.0.1': optional: true - '@napi-rs/wasm-tools-wasm32-wasi@1.0.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + '@napi-rs/wasm-tools-wasm32-wasi@1.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': dependencies: - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -3424,7 +3424,7 @@ snapshots: '@napi-rs/wasm-tools-win32-x64-msvc@1.0.1': optional: true - '@napi-rs/wasm-tools@1.0.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + '@napi-rs/wasm-tools@1.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': optionalDependencies: '@napi-rs/wasm-tools-android-arm-eabi': 1.0.1 '@napi-rs/wasm-tools-android-arm64': 1.0.1 @@ -3435,7 +3435,7 @@ snapshots: '@napi-rs/wasm-tools-linux-arm64-musl': 1.0.1 '@napi-rs/wasm-tools-linux-x64-gnu': 1.0.1 '@napi-rs/wasm-tools-linux-x64-musl': 1.0.1 - '@napi-rs/wasm-tools-wasm32-wasi': 1.0.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + '@napi-rs/wasm-tools-wasm32-wasi': 1.0.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) '@napi-rs/wasm-tools-win32-arm64-msvc': 1.0.1 '@napi-rs/wasm-tools-win32-ia32-msvc': 1.0.1 '@napi-rs/wasm-tools-win32-x64-msvc': 1.0.1 @@ -3461,7 +3461,7 @@ snapshots: dependencies: '@octokit/auth-token': 6.0.0 '@octokit/graphql': 9.0.3 - '@octokit/request': 10.0.10 + '@octokit/request': 10.0.11 '@octokit/request-error': 7.1.0 '@octokit/types': 16.0.0 before-after-hook: 4.0.0 @@ -3474,7 +3474,7 @@ snapshots: '@octokit/graphql@9.0.3': dependencies: - '@octokit/request': 10.0.10 + '@octokit/request': 10.0.11 '@octokit/types': 16.0.0 universal-user-agent: 7.0.3 @@ -3498,7 +3498,7 @@ snapshots: dependencies: '@octokit/types': 16.0.0 - '@octokit/request@10.0.10': + '@octokit/request@10.0.11': dependencies: '@octokit/endpoint': 11.0.3 '@octokit/request-error': 7.1.0 @@ -3571,7 +3571,7 @@ snapshots: '@secretlint/source-creator': 10.2.2 '@secretlint/types': 10.2.2 debug: 4.4.3 - p-map: 7.0.4 + p-map: 7.0.5 transitivePeerDependencies: - supports-color @@ -3609,7 +3609,7 @@ snapshots: '@textlint/types': 15.7.1 chalk: 4.1.2 debug: 4.4.3 - js-yaml: 4.2.0 + js-yaml: 4.3.0 lodash: 4.18.1 pluralize: 2.0.0 string-width: 4.2.3 @@ -3651,15 +3651,15 @@ snapshots: '@types/vscode@1.61.0': {} - '@typescript-eslint/eslint-plugin@8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3))(eslint@10.5.0)(typescript@6.0.3)': + '@typescript-eslint/eslint-plugin@8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3))(eslint@10.6.0)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.62.0(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.62.0 - '@typescript-eslint/type-utils': 8.62.0(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.0(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.62.0 - eslint: 10.5.0 + '@typescript-eslint/parser': 8.63.0(eslint@10.6.0)(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.63.0 + '@typescript-eslint/type-utils': 8.63.0(eslint@10.6.0)(typescript@6.0.3) + '@typescript-eslint/utils': 8.63.0(eslint@10.6.0)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.63.0 + eslint: 10.6.0 ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@6.0.3) @@ -3667,56 +3667,56 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3)': + '@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/scope-manager': 8.62.0 - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.62.0 + '@typescript-eslint/scope-manager': 8.63.0 + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.63.0 debug: 4.4.3 - eslint: 10.5.0 + eslint: 10.6.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.62.0(typescript@6.0.3)': + '@typescript-eslint/project-service@8.63.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.62.0(typescript@6.0.3) - '@typescript-eslint/types': 8.62.0 + '@typescript-eslint/tsconfig-utils': 8.63.0(typescript@6.0.3) + '@typescript-eslint/types': 8.63.0 debug: 4.4.3 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.62.0': + '@typescript-eslint/scope-manager@8.63.0': dependencies: - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/visitor-keys': 8.62.0 + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/visitor-keys': 8.63.0 - '@typescript-eslint/tsconfig-utils@8.62.0(typescript@6.0.3)': + '@typescript-eslint/tsconfig-utils@8.63.0(typescript@6.0.3)': dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.62.0(eslint@10.5.0)(typescript@6.0.3)': + '@typescript-eslint/type-utils@8.63.0(eslint@10.6.0)(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.0(eslint@10.5.0)(typescript@6.0.3) + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.63.0(eslint@10.6.0)(typescript@6.0.3) debug: 4.4.3 - eslint: 10.5.0 + eslint: 10.6.0 ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.62.0': {} + '@typescript-eslint/types@8.63.0': {} - '@typescript-eslint/typescript-estree@8.62.0(typescript@6.0.3)': + '@typescript-eslint/typescript-estree@8.63.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.62.0(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.62.0(typescript@6.0.3) - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/visitor-keys': 8.62.0 + '@typescript-eslint/project-service': 8.63.0(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.63.0(typescript@6.0.3) + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/visitor-keys': 8.63.0 debug: 4.4.3 minimatch: 10.2.5 semver: 7.8.5 @@ -3726,20 +3726,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.62.0(eslint@10.5.0)(typescript@6.0.3)': + '@typescript-eslint/utils@8.63.0(eslint@10.6.0)(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0) - '@typescript-eslint/scope-manager': 8.62.0 - '@typescript-eslint/types': 8.62.0 - '@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3) - eslint: 10.5.0 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0) + '@typescript-eslint/scope-manager': 8.63.0 + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3) + eslint: 10.6.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.62.0': + '@typescript-eslint/visitor-keys@8.63.0': dependencies: - '@typescript-eslint/types': 8.62.0 + '@typescript-eslint/types': 8.63.0 eslint-visitor-keys: 5.0.1 '@typespec/ts-http-runtime@0.3.6': @@ -3807,7 +3807,7 @@ snapshots: hosted-git-info: 4.1.0 jsonc-parser: 3.3.1 leven: 3.1.0 - markdown-it: 14.2.0 + markdown-it: 14.3.0 mime: 1.6.0 minimatch: 10.2.5 parse-semver: 1.1.1 @@ -3843,7 +3843,7 @@ snapshots: ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 + fast-uri: 3.1.3 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -3957,7 +3957,7 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@5.0.6: + brace-expansion@5.0.7: dependencies: balanced-match: 4.0.4 @@ -4176,7 +4176,7 @@ snapshots: dependencies: version-range: 4.15.0 - emnapi@1.11.1: {} + emnapi@1.11.2: {} emoji-regex@8.0.0: {} @@ -4219,7 +4219,7 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.2 es-set-tostringtag: 2.1.0 - es-to-primitive: 1.3.1 + es-to-primitive: 1.3.4 function.prototype.name: 1.2.0 get-intrinsic: 1.3.0 get-proto: 1.0.1 @@ -4281,15 +4281,16 @@ snapshots: dependencies: hasown: 2.0.4 - es-to-primitive@1.3.1: + es-to-primitive@1.3.4: dependencies: es-abstract-get: 1.0.0 + es-define-property: 1.0.1 es-errors: 1.3.0 is-callable: 1.2.7 is-date-object: 1.1.0 is-symbol: 1.1.1 - es-toolkit@1.48.1: {} + es-toolkit@1.49.0: {} esbuild@0.28.1: optionalDependencies: @@ -4324,9 +4325,9 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.8(eslint@10.5.0): + eslint-config-prettier@10.1.8(eslint@10.6.0): dependencies: - eslint: 10.5.0 + eslint: 10.6.0 eslint-import-resolver-node@0.3.10: dependencies: @@ -4336,23 +4337,23 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.13.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.5.0): + eslint-module-utils@2.14.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.6.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.62.0(eslint@10.5.0)(typescript@6.0.3) - eslint: 10.5.0 + '@typescript-eslint/parser': 8.63.0(eslint@10.6.0)(typescript@6.0.3) + eslint: 10.6.0 eslint-import-resolver-node: 0.3.10 transitivePeerDependencies: - supports-color - eslint-plugin-es@3.0.1(eslint@10.5.0): + eslint-plugin-es@3.0.1(eslint@10.6.0): dependencies: - eslint: 10.5.0 + eslint: 10.6.0 eslint-utils: 2.1.0 regexpp: 3.2.0 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3))(eslint@10.5.0): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3))(eslint@10.6.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -4361,9 +4362,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 10.5.0 + eslint: 10.6.0 eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.5.0) + eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.6.0) hasown: 2.0.4 is-core-module: 2.16.2 is-glob: 4.0.3 @@ -4375,30 +4376,30 @@ snapshots: string.prototype.trimend: 1.0.10 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.62.0(eslint@10.5.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.63.0(eslint@10.6.0)(typescript@6.0.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-node@11.1.0(eslint@10.5.0): + eslint-plugin-node@11.1.0(eslint@10.6.0): dependencies: - eslint: 10.5.0 - eslint-plugin-es: 3.0.1(eslint@10.5.0) + eslint: 10.6.0 + eslint-plugin-es: 3.0.1(eslint@10.6.0) eslint-utils: 2.1.0 ignore: 5.3.2 minimatch: 3.1.5 resolve: 1.22.12 semver: 6.3.1 - eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@10.5.0))(eslint@10.5.0)(prettier@3.8.4): + eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@10.6.0))(eslint@10.6.0)(prettier@3.9.4): dependencies: - eslint: 10.5.0 - prettier: 3.8.4 + eslint: 10.6.0 + prettier: 3.9.4 prettier-linter-helpers: 1.0.1 synckit: 0.11.13 optionalDependencies: - eslint-config-prettier: 10.1.8(eslint@10.5.0) + eslint-config-prettier: 10.1.8(eslint@10.6.0) eslint-scope@9.1.2: dependencies: @@ -4417,9 +4418,9 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.5.0: + eslint@10.6.0: dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.5.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.6.0) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.23.5 '@eslint/config-helpers': 0.6.0 @@ -4495,7 +4496,7 @@ snapshots: dependencies: fast-string-truncated-width: 3.0.3 - fast-uri@3.1.2: {} + fast-uri@3.1.3: {} fast-wrap-ansi@0.2.2: dependencies: @@ -4505,9 +4506,9 @@ snapshots: dependencies: reusify: 1.1.0 - fdir@6.5.0(picomatch@4.0.4): + fdir@6.5.0(picomatch@4.0.5): optionalDependencies: - picomatch: 4.0.4 + picomatch: 4.0.5 file-entry-cache@8.0.0: dependencies: @@ -4544,7 +4545,7 @@ snapshots: fs-constants@1.0.0: optional: true - fs-extra@11.3.5: + fs-extra@11.3.6: dependencies: graceful-fs: 4.2.11 jsonfile: 6.2.1 @@ -4682,7 +4683,7 @@ snapshots: dependencies: safer-buffer: 2.1.2 - iconv-lite@0.7.2: + iconv-lite@0.7.3: dependencies: safer-buffer: 2.1.2 @@ -4847,7 +4848,7 @@ snapshots: js-tokens@4.0.0: {} - js-yaml@4.2.0: + js-yaml@4.3.0: dependencies: argparse: 2.0.1 @@ -4918,7 +4919,7 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - linkify-it@5.0.1: + linkify-it@5.0.2: dependencies: uc.micro: 2.1.0 @@ -4952,11 +4953,11 @@ snapshots: dependencies: yallist: 4.0.0 - markdown-it@14.2.0: + markdown-it@14.3.0: dependencies: argparse: 2.0.1 entities: 4.5.0 - linkify-it: 5.0.1 + linkify-it: 5.0.2 mdurl: 2.0.0 punycode.js: 2.3.1 uc.micro: 2.1.0 @@ -4987,7 +4988,7 @@ snapshots: minimatch@10.2.5: dependencies: - brace-expansion: 5.0.6 + brace-expansion: 5.0.7 minimatch@3.1.5: dependencies: @@ -5011,7 +5012,7 @@ snapshots: natural-compare@1.4.0: {} - node-abi@3.92.0: + node-abi@3.94.0: dependencies: semver: 7.8.5 optional: true @@ -5032,7 +5033,7 @@ snapshots: node-sarif-builder@3.4.0: dependencies: '@types/sarif': 2.1.7 - fs-extra: 11.3.5 + fs-extra: 11.3.6 normalize-package-data@6.0.2: dependencies: @@ -5047,7 +5048,7 @@ snapshots: ansi-styles: 6.2.3 cross-spawn: 7.0.6 memorystream: 0.3.1 - picomatch: 4.0.4 + picomatch: 4.0.5 pidtree: 1.0.0 read-package-json-fast: 6.0.0 shell-quote: 1.9.0 @@ -5134,7 +5135,7 @@ snapshots: dependencies: p-limit: 3.1.0 - p-map@7.0.4: {} + p-map@7.0.5: {} parse-json@8.3.0: dependencies: @@ -5178,7 +5179,7 @@ snapshots: picomatch@2.3.2: {} - picomatch@4.0.4: {} + picomatch@4.0.5: {} pidtree@1.0.0: {} @@ -5196,11 +5197,11 @@ snapshots: minimist: 1.2.8 mkdirp-classic: 0.5.3 napi-build-utils: 2.0.0 - node-abi: 3.92.0 + node-abi: 3.94.0 pump: 3.0.4 rc: 1.2.8 simple-get: 4.0.1 - tar-fs: 2.1.4 + tar-fs: 2.1.5 tunnel-agent: 0.6.0 optional: true @@ -5210,7 +5211,7 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@3.8.4: {} + prettier@3.9.4: {} pump@3.0.4: dependencies: @@ -5232,7 +5233,7 @@ snapshots: rc-config-loader@4.1.4: dependencies: debug: 4.4.3 - js-yaml: 4.2.0 + js-yaml: 4.3.0 json5: 2.2.3 require-from-string: 2.0.2 transitivePeerDependencies: @@ -5533,7 +5534,7 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - tar-fs@2.1.4: + tar-fs@2.1.5: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 @@ -5563,8 +5564,8 @@ snapshots: tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 tmp@0.2.7: {} @@ -5639,13 +5640,13 @@ snapshots: tunnel: 0.0.6 underscore: 1.13.8 - typescript-eslint@8.62.0(eslint@10.5.0)(typescript@6.0.3): + typescript-eslint@8.63.0(eslint@10.6.0)(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.62.0(@typescript-eslint/parser@8.62.0(eslint@10.5.0)(typescript@6.0.3))(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/parser': 8.62.0(eslint@10.5.0)(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.62.0(typescript@6.0.3) - '@typescript-eslint/utils': 8.62.0(eslint@10.5.0)(typescript@6.0.3) - eslint: 10.5.0 + '@typescript-eslint/eslint-plugin': 8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.6.0)(typescript@6.0.3))(eslint@10.6.0)(typescript@6.0.3) + '@typescript-eslint/parser': 8.63.0(eslint@10.6.0)(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.63.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.63.0(eslint@10.6.0)(typescript@6.0.3) + eslint: 10.6.0 typescript: 6.0.3 transitivePeerDependencies: - supports-color diff --git a/server/Cargo.lock b/server/Cargo.lock index 0bc1974b..026bcaad 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -72,7 +72,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand 0.10.1", + "rand 0.10.2", "sha1 0.11.0", "smallvec", "tokio", @@ -302,14 +302,13 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "ammonia" -version = "4.1.2" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e913097e1a2124b46746c980134e8c954bc17a6a59bb3fde96f088d126dde6" +checksum = "68b9d3370580a12f4b7a10fdcc18b28942c083ba570e3d954fe59d10951b85a2" dependencies = [ - "cssparser 0.35.0", - "html5ever 0.35.0", + "cssparser 0.37.0", + "html5ever", "maplit", - "tendril 0.4.3", "url", ] @@ -380,9 +379,9 @@ checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "arc-swap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" +checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" dependencies = [ "rustversion", ] @@ -416,16 +415,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "assertables" -version = "9.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "627b0b35c347252505ec6c078827dfcecc4e9dcfa931c54c54066f9245ac752b" -dependencies = [ - "regex", - "walkdir", -] - [[package]] name = "assertables" version = "10.1.0" @@ -461,9 +450,9 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "aws-lc-rs" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00" +checksum = "4342d8937fc7e5dd9b1c60292261c0670c882a2cd1719cfc11b1af41731e32ad" dependencies = [ "aws-lc-sys", "zeroize", @@ -471,14 +460,15 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.41.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4" +checksum = "6d9ceb1da931507a12f4fccea479dccd00da1943e1b4ae72d8e502d707361444" dependencies = [ "cc", "cmake", "dunce", "fs_extra", + "pkg-config", ] [[package]] @@ -640,9 +630,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.65" +version = "1.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" dependencies = [ "find-msvc-tools", "jobserver", @@ -752,7 +742,7 @@ dependencies = [ [[package]] name = "codechat-editor-server" -version = "0.1.59" +version = "0.1.60" dependencies = [ "actix-files", "actix-http", @@ -766,7 +756,7 @@ dependencies = [ "anyhow", "assert_cmd", "assert_fs", - "assertables 10.1.0", + "assertables", "bytes", "chrono", "clap", @@ -775,7 +765,7 @@ dependencies = [ "futures", "futures-util", "htmd", - "html5ever 0.39.0", + "html5ever", "htmlize", "imara-diff", "indoc", @@ -796,7 +786,7 @@ dependencies = [ "predicates", "pretty_assertions", "pulldown-cmark 0.13.4", - "rand 0.10.1", + "rand 0.10.2", "regex", "serde", "serde_json", @@ -973,9 +963,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -983,18 +973,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crypto-common" @@ -1030,14 +1020,12 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.35.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e901edd733a1472f944a45116df3f846f54d37e67e68640ac8bb69689aca2aa" +checksum = "8c9cdaae01d5ed7882b04d795e7f752f46ff52d2fa3b50a20d28c464510bba98" dependencies = [ - "cssparser-macros", "dtoa-short", "itoa", - "phf 0.11.3", "smallvec", ] @@ -1351,7 +1339,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.9", "zlib-rs", ] @@ -1423,16 +1411,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - [[package]] name = "futures" version = "0.3.32" @@ -1551,11 +1529,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", - "js-sys", "libc", "r-efi 5.3.0", "wasip2", - "wasm-bindgen", ] [[package]] @@ -1565,9 +1541,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", "rand_core 0.10.1", + "wasm-bindgen", ] [[package]] @@ -1668,22 +1646,11 @@ name = "htmd" version = "0.5.4" source = "git+https://github.com/bjones1/htmd.git?branch=dom-interface#deafeb4b579530a94314828218cfbda79c615ef8" dependencies = [ - "html5ever 0.39.0", + "html5ever", "markup5ever_rcdom", "phf 0.13.1", ] -[[package]] -name = "html5ever" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55d958c2f74b664487a2035fe1dadb032c48718a03b63f3ab0b8537db8549ed4" -dependencies = [ - "log", - "markup5ever 0.35.0", - "match_token", -] - [[package]] name = "html5ever" version = "0.39.0" @@ -1691,7 +1658,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8" dependencies = [ "log", - "markup5ever 0.39.0", + "markup5ever", ] [[package]] @@ -1768,15 +1735,15 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" +checksum = "15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15" [[package]] name = "hybrid-array" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" dependencies = [ "typenum", ] @@ -1968,9 +1935,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b915661dd01db3f05050265b2477bcc6527b3792388e2749b41623cc592be67d" +checksum = "fe112b004901c62c2faa11f4f75e9864e0cc5af8da71c9115d184a3aa888749f" dependencies = [ "crossbeam-deque", "globset", @@ -2021,9 +1988,9 @@ dependencies = [ [[package]] name = "inotify" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533e68a5842e734946fe159fb03fc9bbbb254f590dd0d8ad321ae5ff7beca2c1" +checksum = "dd854a95a4ac672fed8c054136039fd32c22cf039ff09ead7280afe920486483" dependencies = [ "bitflags", "inotify-sys", @@ -2032,9 +1999,9 @@ dependencies = [ [[package]] name = "inotify-sys" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +checksum = "c033f80b2c113cdf91ab7a33faa9cbc014726dcad99880c8609af2a370edf37d" dependencies = [ "libc", ] @@ -2126,11 +2093,11 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] @@ -2147,9 +2114,9 @@ dependencies = [ [[package]] name = "json-escape-simd" -version = "3.0.2" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e770254dd7802184595b1d30da2a15cb72569e2aca2b177aef8d22eac8a693" +checksum = "2a18a0eb3c0a783620d2ae8cdda9590aae18b1608964ee9c7c43162562786424" [[package]] name = "konst" @@ -2206,9 +2173,9 @@ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libredox" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" dependencies = [ "libc", ] @@ -2341,29 +2308,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - [[package]] name = "maplit" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" -[[package]] -name = "markup5ever" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311fe69c934650f8f19652b3946075f0fc41ad8757dbb68f1ca14e7900ecc1c3" -dependencies = [ - "log", - "tendril 0.4.3", - "web_atoms 0.1.3", -] - [[package]] name = "markup5ever" version = "0.39.0" @@ -2371,8 +2321,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de" dependencies = [ "log", - "tendril 0.5.0", - "web_atoms 0.2.5", + "tendril", + "web_atoms", ] [[package]] @@ -2381,23 +2331,12 @@ version = "0.39.0+unofficial" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ac010f19d6c4af81eeb4018a39d7a115de9d285af45c126a4ac02e6fc5716b7" dependencies = [ - "html5ever 0.39.0", - "markup5ever 0.39.0", - "tendril 0.5.0", + "html5ever", + "markup5ever", + "tendril", "xml5ever", ] -[[package]] -name = "match_token" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", -] - [[package]] name = "matchers" version = "0.2.0" @@ -2425,9 +2364,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "mime" @@ -2487,6 +2426,15 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", +] + [[package]] name = "minreq" version = "3.0.0" @@ -2586,9 +2534,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" dependencies = [ "num-integer", "num-traits", @@ -2714,11 +2662,11 @@ checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" [[package]] name = "oxc-browserslist" -version = "3.0.6" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b87743c2f6963036971ca587539cd9235693d953dc018a734014241afb20d5b" +checksum = "373741e2febe6df186995b668f295e46fd402ee12f312ea2fda8b3b6312c0885" dependencies = [ - "flate2", + "miniz_oxide 0.9.1", "postcard", "rustc-hash", "serde", @@ -3158,9 +3106,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.6" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +checksum = "47627dd7305c6a2d6c8c6bcd24c5a4c17dbbf425f4f9c5313e724b38fc9782e9" dependencies = [ "memchr", "ucd-trie", @@ -3168,9 +3116,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.6" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" +checksum = "4b4254325ecad416ab689e27ba51da03ba01a9632bc6e108f5fe7c3c4ad29d58" dependencies = [ "pest", "pest_generator", @@ -3178,9 +3126,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.6" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" +checksum = "6c4c0e91ead7a8f7acecbca6f003fc2e8282b1dbe2dd9c9d2f16aba42995e0a7" dependencies = [ "pest", "pest_meta", @@ -3191,12 +3139,11 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.6" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" +checksum = "f9744bc48116fee06334924bb5f2bad41eed5e89bd26e29b0b799f9a3f82c210" dependencies = [ "pest", - "sha2 0.10.9", ] [[package]] @@ -3384,8 +3331,8 @@ dependencies = [ "hmac", "md-5", "memchr", - "rand 0.10.1", - "sha2 0.11.0", + "rand 0.10.2", + "sha2", "stringprep", ] @@ -3551,15 +3498,16 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.15" +version = "0.11.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" dependencies = [ "aws-lc-rs", "bytes", - "getrandom 0.3.4", + "getrandom 0.4.3", "lru-slab", - "rand 0.9.4", + "rand 0.10.2", + "rand_pcg", "ring", "rustc-hash", "rustls", @@ -3573,16 +3521,16 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" dependencies = [ "cfg_aliases", "libc", "once_cell", "socket2 0.6.4", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -3633,9 +3581,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" dependencies = [ "chacha20", "getrandom 0.4.3", @@ -3673,6 +3621,15 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + [[package]] name = "rayon" version = "1.12.0" @@ -3842,9 +3799,9 @@ dependencies = [ [[package]] name = "rustc-hash" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustc_version" @@ -3896,9 +3853,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ "web-time", "zeroize", @@ -3945,9 +3902,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "ryu" @@ -4147,17 +4104,6 @@ dependencies = [ "digest 0.11.3", ] -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "digest 0.10.7", -] - [[package]] name = "sha2" version = "0.11.0" @@ -4281,19 +4227,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "string_cache" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" -dependencies = [ - "new_debug_unreachable", - "parking_lot", - "phf_shared 0.11.3", - "precomputed-hash", - "serde", -] - [[package]] name = "string_cache" version = "0.9.0" @@ -4307,18 +4240,6 @@ dependencies = [ "serde", ] -[[package]] -name = "string_cache_codegen" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", -] - [[package]] name = "string_cache_codegen" version = "0.6.1" @@ -4436,23 +4357,11 @@ dependencies = [ [[package]] name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "tendril" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4790fc369d5a530f4b544b094e31388b9b3a37c0f4652ade4505945f5660d24" +checksum = "5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08" dependencies = [ "new_debug_unreachable", - "utf-8", ] [[package]] @@ -4475,7 +4384,7 @@ name = "test_utils" version = "0.1.0" dependencies = [ "assert_fs", - "assertables 9.9.0", + "assertables", "log", ] @@ -4492,9 +4401,9 @@ dependencies = [ [[package]] name = "thirtyfour" -version = "0.37.1" +version = "0.37.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c23ea3ddea759604ee20091e361347531cbdd5e4575435dc87e55ad7bcae5775" +checksum = "799b1de3a58f1ed82060fbee54cc27bc87523e35ade57d9c80bc88ffc1420044" dependencies = [ "arc-swap", "async-trait", @@ -4576,9 +4485,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.51" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c17d80feb7334b40c484e45ed1a5273dfd8bfda537c3be2e74a06a6686f327" +checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" dependencies = [ "deranged", "num-conv", @@ -4596,9 +4505,9 @@ checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.30" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcef1a61bdb119096e153208ec5cbec23944ce8bca13be5c7f60c634f7403935" +checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f" dependencies = [ "num-conv", "time-core", @@ -4676,7 +4585,7 @@ dependencies = [ "pin-project-lite", "postgres-protocol", "postgres-types", - "rand 0.10.1", + "rand 0.10.2", "socket2 0.6.4", "tokio", "tokio-util", @@ -5011,12 +4920,6 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -5218,18 +5121,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "web_atoms" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414" -dependencies = [ - "phf 0.11.3", - "phf_codegen 0.11.3", - "string_cache 0.8.9", - "string_cache_codegen 0.5.4", -] - [[package]] name = "web_atoms" version = "0.2.5" @@ -5238,8 +5129,8 @@ checksum = "075474b12bcb3d2e3d4546580e9de478eeeead668a1761e2a8860c836b7ef297" dependencies = [ "phf 0.13.1", "phf_codegen 0.13.1", - "string_cache 0.9.0", - "string_cache_codegen 0.6.1", + "string_cache", + "string_cache_codegen", ] [[package]] @@ -5615,7 +5506,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ab627f34ff61b80d756180d556f9c68801d836d271b3b8c094504ceca69d221" dependencies = [ "log", - "markup5ever 0.39.0", + "markup5ever", ] [[package]] @@ -5649,18 +5540,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.52" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" +checksum = "75726053136156d419e285b9b7eddaaea9e3fea6ce32eed44a89901f0bd98de1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.52" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +checksum = "4714fd92cf900833d49538023a9b3915155210801d1c1169eba513b2addefd71" dependencies = [ "proc-macro2", "quote", @@ -5743,9 +5634,9 @@ dependencies = [ [[package]] name = "zlib-rs" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "977347db8caa080403f6b6b7c1cda9479a8e869316f7e13a59b19076a40f94e3" +checksum = "5431d5661c32445236631278f27946e444ddafe4684cac70b185272d4f9c52d5" [[package]] name = "zmij" diff --git a/server/Cargo.toml b/server/Cargo.toml index 40fa9296..e759774f 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -32,7 +32,7 @@ license = "GPL-3.0-only" name = "codechat-editor-server" readme = "../README.md" repository = "https://github.com/bjones1/CodeChat_Editor" -version = "0.1.59" +version = "0.1.60" # This library allows other packages to use core CodeChat Editor features. [lib] diff --git a/server/src/ide/vscode/tests.rs b/server/src/ide/vscode/tests.rs index 87287db8..fab98e5b 100644 --- a/server/src/ide/vscode/tests.rs +++ b/server/src/ide/vscode/tests.rs @@ -110,7 +110,7 @@ async fn read_message( let msg_txt = loop { let msg = select! { data = ws_stream.next() => data.unwrap().unwrap(), - _ = sleep(Duration::from_secs(3) - now.elapsed().unwrap()) => panic!("Timeout waiting for message") + _ = sleep(Duration::from_secs(6) - now.elapsed().unwrap()) => panic!("Timeout waiting for message") }; match msg { Message::Close(_) => panic!("Unexpected close message."), diff --git a/server/src/processing.rs b/server/src/processing.rs index b8e4136e..bd960f4d 100644 --- a/server/src/processing.rs +++ b/server/src/processing.rs @@ -1000,6 +1000,8 @@ static AMMONIA_OPTIONS: LazyLock = LazyLock::new(|| { // checkboxes produced by pulldown-cmark) and `iframe` (embedded media // inserted via TinyMCE), neither of which Ammonia allows by default. b.add_tags(&["wc-mermaid", "graphviz-graph", "input", "iframe"]) + // Allow any element to be assigned an ID. + .add_generic_attributes(&["id"]) // This allows math produced by pulldown-cmark and updated by the // hydration code. .add_allowed_classes( diff --git a/server/src/processing/tests.rs b/server/src/processing/tests.rs index 3855f54e..7086cad3 100644 --- a/server/src/processing/tests.rs +++ b/server/src/processing/tests.rs @@ -783,6 +783,33 @@ fn test_source_to_codechat_for_web_1() { ] ))) ); + + // Test that minify functions correctly across multiple paragraphs separated + // by a code block. + assert_eq!( + source_to_codechat_for_web( + indoc!( + r#" + // 1 + "# + ), + &"cpp".to_string(), + 0.0, + false, + false + ), + Ok(TranslationResults::CodeChat(build_codechat_for_web( + "cpp", + "\n", + vec![build_codemirror_doc_block( + 0, + 1, + "", + "//", + r#"

1"# + ),] + ))) + ); } #[test] diff --git a/server/tests/fixtures/overall_1/test_client_updates/test.py b/server/tests/fixtures/overall_1/test_updates/test.py similarity index 100% rename from server/tests/fixtures/overall_1/test_client_updates/test.py rename to server/tests/fixtures/overall_1/test_updates/test.py diff --git a/server/tests/fixtures/overall_1/test_client_updates/toc.md b/server/tests/fixtures/overall_1/test_updates/toc.md similarity index 100% rename from server/tests/fixtures/overall_1/test_client_updates/toc.md rename to server/tests/fixtures/overall_1/test_updates/toc.md diff --git a/server/tests/fixtures/overall_4/test_arrow_key_navigation/test.py b/server/tests/fixtures/overall_4/test_arrow_key_navigation/test.py new file mode 100644 index 00000000..3b1386f5 --- /dev/null +++ b/server/tests/fixtures/overall_4/test_arrow_key_navigation/test.py @@ -0,0 +1,3 @@ +The contents of this file don't matter -- tests will supply the content, +instead of loading it from disk. However, it does need to exist for +`canonicalize` to find the correct path to this file. diff --git a/server/tests/fixtures/overall_4/test_arrow_key_navigation_multiline_doc_block/test.py b/server/tests/fixtures/overall_4/test_arrow_key_navigation_multiline_doc_block/test.py new file mode 100644 index 00000000..3b1386f5 --- /dev/null +++ b/server/tests/fixtures/overall_4/test_arrow_key_navigation_multiline_doc_block/test.py @@ -0,0 +1,3 @@ +The contents of this file don't matter -- tests will supply the content, +instead of loading it from disk. However, it does need to exist for +`canonicalize` to find the correct path to this file. diff --git a/server/tests/fixtures/overall_4/test_horizontal_scroll_preserved/test.py b/server/tests/fixtures/overall_4/test_horizontal_scroll_preserved/test.py new file mode 100644 index 00000000..3b1386f5 --- /dev/null +++ b/server/tests/fixtures/overall_4/test_horizontal_scroll_preserved/test.py @@ -0,0 +1,3 @@ +The contents of this file don't matter -- tests will supply the content, +instead of loading it from disk. However, it does need to exist for +`canonicalize` to find the correct path to this file. diff --git a/server/tests/fixtures/overall_5/test_cursor_home_from_code_after_doc_block/test.py b/server/tests/fixtures/overall_5/test_cursor_home_from_code_after_doc_block/test.py new file mode 100644 index 00000000..3b1386f5 --- /dev/null +++ b/server/tests/fixtures/overall_5/test_cursor_home_from_code_after_doc_block/test.py @@ -0,0 +1,3 @@ +The contents of this file don't matter -- tests will supply the content, +instead of loading it from disk. However, it does need to exist for +`canonicalize` to find the correct path to this file. diff --git a/server/tests/overall_1.rs b/server/tests/overall_1.rs index 4c6fc8a9..9b223351 100644 --- a/server/tests/overall_1.rs +++ b/server/tests/overall_1.rs @@ -19,6 +19,9 @@ /// These are functional tests of the overall system, performed by attaching a /// testing IDE to generate commands then observe results, along with a browser /// tester. +/// +/// To run this test, execute `cargo test --test overall_1 +/// ` in the `server/` directory. // Modules // ------- mod overall_common; @@ -38,8 +41,9 @@ use tokio::time::sleep; // ### Local use crate::overall_common::{ - CodeChatEditorServerLog, ExpectedMessages, TIMEOUT, assert_no_more_messages, get_version, - goto_line, optional_message, perform_loadfile, select_codechat_iframe, + CodeChatEditorServerLog, ExpectedMessages, TIMEOUT, assert_no_more_messages, beginning_of_line, + end_of_line, get_version, goto_line, optional_message, perform_loadfile, + select_codechat_iframe, }; use code_chat_editor::{ lexer::supported_languages::MARKDOWN_MODE, @@ -175,7 +179,11 @@ async fn test_server_core( client_id += MESSAGE_ID_INCREMENT; // Edit the indent. It should only allow spaces and tabs, rejecting other - // edits. + // edits. Click it first, since the indent is only editable while + // focused; see the inline `onmousedown` handler on + // `.CodeChat-doc-indent` in `CodeMirror-integration.mts`, which makes it + // editable on click. + doc_block_indent.click().await.unwrap(); doc_block_indent.send_keys(" 123").await.unwrap(); let msg = codechat_server.get_message_timeout(TIMEOUT).await.unwrap(); let client_version = get_version(&msg); @@ -236,7 +244,7 @@ async fn test_server_core( client_id += MESSAGE_ID_INCREMENT; // Moving left should move us back to the doc block. - code_line.send_keys(Key::Home + Key::Left).await.unwrap(); + beginning_of_line(&code_line, Key::Left).await.unwrap(); assert_eq!( codechat_server.get_message_timeout(TIMEOUT).await.unwrap(), EditorMessage { @@ -729,9 +737,9 @@ async fn test_client_core( Ok(()) } -make_test!(test_client_updates, test_client_updates_core); +make_test!(test_updates, test_updates_core); -async fn test_client_updates_core( +async fn test_updates_core( codechat_server: CodeChatEditorServerLog, driver: WebDriver, test_dir: PathBuf, @@ -784,10 +792,7 @@ async fn test_client_updates_core( client_id += MESSAGE_ID_INCREMENT; let doc_block_contents = driver.find(By::Css(contents_css)).await.unwrap(); - doc_block_contents - .send_keys(Key::End + " testing") - .await - .unwrap(); + end_of_line(&doc_block_contents, " testing").await.unwrap(); // Get the next message, which could be a cursor update followed by a text // update, or just the text update. @@ -865,7 +870,7 @@ async fn test_client_updates_core( // Add an indented comment. let code_line_css = ".CodeChat-CodeMirror .cm-line"; let code_line = driver.find(By::Css(code_line_css)).await.unwrap(); - code_line.send_keys(Key::Home + "# ").await.unwrap(); + beginning_of_line(&code_line, "# ").await.unwrap(); // This should edit the (new) third line of the file after word wrap: `def // foo():`. let msg = optional_message( diff --git a/server/tests/overall_2.rs b/server/tests/overall_2.rs index 2acd2322..69dce212 100644 --- a/server/tests/overall_2.rs +++ b/server/tests/overall_2.rs @@ -33,12 +33,13 @@ use std::path::PathBuf; use dunce::canonicalize; use indoc::indoc; use pretty_assertions::assert_eq; -use thirtyfour::{By, Key, WebDriver, error::WebDriverError}; +use thirtyfour::{By, WebDriver, error::WebDriverError, extensions::query::ElementQueryable}; // ### Local use crate::overall_common::{ - CodeChatEditorServerLog, TIMEOUT, assert_no_more_messages, click_element_top_left, get_version, - optional_message, perform_loadfile, select_codechat_iframe, + CodeChatEditorServerLog, TIMEOUT, assert_no_more_messages, beginning_of_document, + click_element_top_left, get_version, optional_message, perform_loadfile, + select_codechat_iframe, }; use code_chat_editor::{ processing::{ @@ -228,7 +229,7 @@ async fn test_5_core( assert_eq!(client_id, 7.0); // Refind it, since it's now switched with a TinyMCE editor. - let tinymce_contents = driver.find(By::Id("TinyMCE-inst")).await.unwrap(); + let tinymce_contents = driver.query(By::Id("TinyMCE-inst")).first().await.unwrap(); // Make an edit. tinymce_contents.send_keys("foo").await.unwrap(); @@ -403,39 +404,10 @@ async fn test_6_core( codechat_server.send_result(client_id, None).await.unwrap(); client_id += MESSAGE_ID_INCREMENT; - // Perform edits at beginning of document. Go to the beginning of the - // document, using an OS-specific key combo. On MacOS, Home, Command+Up, and - // Command+Home all fail. Here's a kludgy workaround: press the up arrow - // repeatedly. - // - // Background: On macOS, many standard navigation shortcuts (like Cmd + Up - // or Ctrl + Home) are intercepted at the OS or application-shell level - // rather than by the web browser's DOM.\ - // Because ChromeDriver simulates interactions by injecting DOM-level events - // (keyup/keydown), these injected events bypass macOS’s native Cocoa text - // system. As a result, the OS does not trigger the expected cursor or - // document jumps. - // - // Here is how the system handles these keys and how to work around the - // limitation: - // - // * The WebKit/Cocoa Bridge: On Mac, many text field interactions rely on - // macOS's global key bindings (managed by NSTextView in the Cocoa - // framework). - // * OS Interception: Shortcuts like Cmd + Up (beginning of document) and - // Ctrl + Home trigger OS-level text editing behaviors rather than pure - // JavaScript DOM events. - // * WebDriver Limitation: WebDriver strictly injects key events into the - // browser's JavaScript execution context. Since OS-level shortcuts are - // intercepted by the native application frame, send\_keys() in a testing - // script often fails to trigger the OS-level jump. - #[cfg(target_os = "macos")] - body_content.send_keys(Key::Up + Key::Up).await.unwrap(); - #[cfg(not(target_os = "macos"))] - body_content - .send_keys(Key::Control + Key::Home) - .await - .unwrap(); + // Perform edits at the beginning of the document. See + // `overall_common::beginning_of_document` for why this can't just be a + // plain OS-specific key combo on macOS. + beginning_of_document(&body_content, "").await.unwrap(); body_content.send_keys("a").await.unwrap(); // Sometimes, a cursor update gets sent before the edit. let msg = optional_message( diff --git a/server/tests/overall_3.rs b/server/tests/overall_3.rs index 1d5f943f..2e022f7e 100644 --- a/server/tests/overall_3.rs +++ b/server/tests/overall_3.rs @@ -37,8 +37,9 @@ use thirtyfour::{By, Key, WebDriver, error::WebDriverError, extensions::query::E // ### Local use crate::overall_common::{ - CodeChatEditorServerLog, TIMEOUT, assert_no_more_messages, click_element_top_left, get_version, - optional_message, perform_loadfile, select_codechat_iframe, + CodeChatEditorServerLog, TIMEOUT, assert_no_more_messages, beginning_of_document, + beginning_of_line, click_element_top_left, get_version, optional_message, perform_loadfile, + select_codechat_iframe, }; use code_chat_editor::{ processing::{ @@ -91,9 +92,15 @@ async fn test_7_core( select_codechat_iframe(&driver).await; // Focus the doc block. It should produce an update with only cursor/scroll - // info (no contents). + // info (no contents). Click on the contents specifically (rather than the + // whole doc block, which also contains the indent) so the click reliably + // lands inside the text regardless of the indent's width, which varies + // with its `contenteditable` state. let mut client_id = INITIAL_CLIENT_MESSAGE_ID; - let doc_block = driver.find(By::Css(".CodeChat-doc")).await.unwrap(); + let doc_block = driver + .find(By::Css(".CodeChat-doc-contents")) + .await + .unwrap(); click_element_top_left(&driver, &doc_block).await.unwrap(); assert_eq!( codechat_server.get_message_timeout(TIMEOUT).await.unwrap(), @@ -142,7 +149,7 @@ async fn test_7_core( make_test!(test_8, test_8_core); -// Test that Clients can insert a new paragraph. +// Test that Clients can insert a new paragraph; do so at the beginning of a doc block, in the middle of a doc block, and at the end of a doc block. async fn test_8_core( codechat_server: CodeChatEditorServerLog, driver: WebDriver, @@ -175,9 +182,15 @@ async fn test_8_core( select_codechat_iframe(&driver).await; // Focus the doc block. It should produce an update with only cursor/scroll - // info (no contents). + // info (no contents). Click on the contents specifically (rather than the + // whole doc block, which also contains the indent) so the click reliably + // lands inside the text regardless of the indent's width, which varies + // with its `contenteditable` state. let mut client_id = INITIAL_CLIENT_MESSAGE_ID; - let doc_block = driver.find(By::Css(".CodeChat-doc")).await.unwrap(); + let doc_block = driver + .find(By::Css(".CodeChat-doc-contents")) + .await + .unwrap(); click_element_top_left(&driver, &doc_block).await.unwrap(); assert_eq!( @@ -199,19 +212,7 @@ async fn test_8_core( // Refind it, since it's now switched with a TinyMCE editor. let tinymce_contents = driver.find(By::Id("TinyMCE-inst")).await.unwrap(); - // Move to the beginning of this line. Due to MacOS fun, avoid option+left - // arrow. TODO: the cursor movement doesn't seem to change the actual - // insertion point. Not sure why. - tinymce_contents - .send_keys(Key::Left + Key::Left) - .await - .unwrap(); - - // Uncomment for debug. - //use std::time::Duration; - //use tokio::time::sleep; - //sleep(Duration::from_hours(1)).await; - + beginning_of_line(&tinymce_contents, "").await.unwrap(); assert_eq!( codechat_server.get_message_timeout(TIMEOUT).await.unwrap(), EditorMessage { @@ -229,6 +230,8 @@ async fn test_8_core( client_id += MESSAGE_ID_INCREMENT; // Start a new paragraph. Wait for a re-translation as the line changes. + // The click above lands the cursor right at the start of "2" (the first + // paragraph), so this splits it into an empty paragraph followed by "2". tinymce_contents.send_keys(Key::Enter).await.unwrap(); let msg = optional_message( @@ -251,7 +254,7 @@ async fn test_8_core( id: client_id, message: EditorMessageContents::Update(UpdateMessageContents { file_path: path_str.clone(), - cursor_position: Some(CursorPosition::Line(1)), + cursor_position: Some(CursorPosition::Line(3)), scroll_position: Some(1.0), is_re_translation: false, contents: Some(CodeChatForWeb { @@ -260,9 +263,9 @@ async fn test_8_core( }, source: CodeMirrorDiffable::Diff(CodeMirrorDiff { doc: vec![StringDiff { - from: 10, + from: 0, to: None, - insert: "#\n# \u{a0}\n".to_string(), + insert: "# \u{a0}\n#\n".to_string(), },], doc_blocks: vec![], version, @@ -293,7 +296,7 @@ async fn test_8_core( id: client_id, message: EditorMessageContents::Update(UpdateMessageContents { file_path: path_str.clone(), - cursor_position: Some(CursorPosition::Line(1)), + cursor_position: Some(CursorPosition::Line(3)), scroll_position: Some(1.0), is_re_translation: false, contents: None, @@ -305,11 +308,11 @@ async fn test_8_core( // ### Insert a newline between two existing paragraphs // - // After the previous edit, the doc block contains three paragraphs. Move up - // to the first paragraph (producing a cursor-only update), then start a new - // paragraph between the first and second ones. Wait for a re-translation as - // the lines change. - tinymce_contents.send_keys(Key::Up + Key::Up).await.unwrap(); + // After the previous edit, the doc block contains three paragraphs (an + // empty one, "2", and "4"). Move up to the first (empty) paragraph + // (producing a cursor-only update), then start a new paragraph there. + // Wait for a re-translation as the lines change. + beginning_of_document(&tinymce_contents, "").await.unwrap(); tinymce_contents.send_keys(Key::Enter).await.unwrap(); // The cursor move produces an optional cursor-only update before the @@ -333,7 +336,7 @@ async fn test_8_core( id: client_id, message: EditorMessageContents::Update(UpdateMessageContents { file_path: path_str.clone(), - cursor_position: Some(CursorPosition::Line(3)), + cursor_position: Some(CursorPosition::Line(1)), scroll_position: Some(1.0), is_re_translation: false, contents: Some(CodeChatForWeb { @@ -342,7 +345,7 @@ async fn test_8_core( }, source: CodeMirrorDiffable::Diff(CodeMirrorDiff { doc: vec![StringDiff { - from: 0, + from: 6, to: None, insert: "# \u{a0}\n#\n".to_string(), },], @@ -375,7 +378,7 @@ async fn test_8_core( id: client_id, message: EditorMessageContents::Update(UpdateMessageContents { file_path: path_str.clone(), - cursor_position: Some(CursorPosition::Line(3)), + cursor_position: Some(CursorPosition::Line(1)), scroll_position: Some(1.0), is_re_translation: false, contents: None, @@ -503,10 +506,13 @@ async fn test_9_core( select_codechat_iframe(&driver).await; // Focus the doc block. It should produce an update with only cursor/scroll - // info (no contents). + // info (no contents). Click on the contents specifically (rather than the + // whole doc block, which also contains the indent) so the click reliably + // lands inside the text regardless of the indent's width, which varies + // with its `contenteditable` state. let mut client_id = INITIAL_CLIENT_MESSAGE_ID; let doc_block = driver - .query(By::Css(".CodeChat-doc")) + .query(By::Css(".CodeChat-doc-contents")) .first() .await .unwrap(); @@ -531,6 +537,27 @@ async fn test_9_core( // Refind it, since it's now switched with a TinyMCE editor. let tinymce_contents = driver.find(By::Id("TinyMCE-inst")).await.unwrap(); + // The click above doesn't necessarily land exactly at the start of the + // text (its position now depends on the contents div's layout, not the + // indent's), so explicitly move to the beginning of the line before + // editing. + beginning_of_line(&tinymce_contents, "").await.unwrap(); + assert_eq!( + codechat_server.get_message_timeout(TIMEOUT).await.unwrap(), + EditorMessage { + id: client_id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: path_str.clone(), + cursor_position: Some(CursorPosition::Line(1)), + scroll_position: Some(1.0), + is_re_translation: false, + contents: None, + }) + } + ); + codechat_server.send_result(client_id, None).await.unwrap(); + client_id += MESSAGE_ID_INCREMENT; + // Perform an edit tinymce_contents.send_keys("a").await.unwrap(); @@ -579,7 +606,9 @@ async fn test_9_core( codechat_server.send_result(client_id, None).await.unwrap(); client_id += MESSAGE_ID_INCREMENT; - // Focus on the code block. + // Focus on the code block. Both source lines are doc blocks (kept + // separate by their differing indents), so the only real `.cm-line` is + // the trailing blank line CodeMirror renders after them -- line 3. let cm_line = driver.query(By::Css(".cm-line")).first().await.unwrap(); cm_line.click().await.unwrap(); diff --git a/server/tests/overall_4.rs b/server/tests/overall_4.rs index 81defa41..404c48d2 100644 --- a/server/tests/overall_4.rs +++ b/server/tests/overall_4.rs @@ -33,14 +33,16 @@ use std::{path::PathBuf, time::Duration}; // ### Third-party use dunce::canonicalize; +use indoc::formatdoc; use pretty_assertions::assert_eq; -use thirtyfour::{By, WebDriver, error::WebDriverError}; +use thirtyfour::{By, Key, WebDriver, error::WebDriverError}; use tokio::time::sleep; // ### Local use crate::overall_common::{ - CodeChatEditorServerLog, TIMEOUT, assert_no_more_messages, click_element_top_left, - optional_message, perform_loadfile, select_codechat_iframe, + CodeChatEditorServerLog, TIMEOUT, assert_no_more_messages, beginning_of_line, + click_element_top_left, end_of_line, optional_message, perform_loadfile, + select_codechat_iframe, }; use code_chat_editor::{ processing::{CodeChatForWeb, CodeMirrorDiffable}, @@ -74,9 +76,9 @@ async fn test_xss_core( let path = canonicalize(test_dir.join("test.md")).unwrap(); let path_str = path.to_str().unwrap().to_string(); let version = 0.0; - // The malicious payload: an image whose `src` is guaranteed to fail loading, - // firing the `onerror` handler. If the handler were allowed through, it - // would log the `XSS` marker to the browser console. + // The malicious payload: an image whose `src` is guaranteed to fail + // loading, firing the `onerror` handler. If the handler were allowed + // through, it would log the `XSS` marker to the browser console. // // The `src` is an invalid `data:` URI so the failed load is resolved // entirely in the browser. (A relative `src` such as `x` would instead make @@ -103,15 +105,15 @@ async fn test_xss_core( // during this window. sleep(Duration::from_millis(500)).await; - // ### 1. The JavaScript must not have executed. + // ### 1\. The JavaScript must not have executed. // // Drain the browser console log. chromedriver records page-side `console.*` // output (and uncaught errors) in the `browser` buffer; if the `onerror` // handler had run, our `XSS` marker would appear here. Draining via the // wrapper (rather than `driver.get_log("browser")` directly) both forwards // each entry to Rust logging and hands the entries back for inspection. Do - // this right after rendering and before any further server call, which would - // otherwise drain the buffer first. + // this right after rendering and before any further server call, which + // would otherwise drain the buffer first. let entries = codechat_server.poll_log().await; for entry in &entries { assert!( @@ -121,7 +123,7 @@ async fn test_xss_core( ); } - // ### 2. The rendered DOM must not contain the malicious handler. + // ### 2\. The rendered DOM must not contain the malicious handler. // // The doc block should render the image with its `onerror` attribute // stripped, leaving a harmless ``. @@ -137,7 +139,7 @@ async fn test_xss_core( "Expected a sanitized tag in the rendered DOM: {rendered}" ); - // ### 3. Editing the document must write back sanitized source. + // ### 3\. Editing the document must write back sanitized source. // // Click into the doc block, then type a character. The Client converts the // (already sanitized) rendered HTML back to source and sends it to the IDE @@ -181,8 +183,8 @@ async fn test_xss_core( ) .await; - // The update must carry contents; pull the source out of the diff and verify - // the malicious handler is gone. + // The update must carry contents; pull the source out of the diff and + // verify the malicious handler is gone. let contents = match &msg.message { EditorMessageContents::Update(UpdateMessageContents { contents: Some(contents), @@ -208,8 +210,8 @@ async fn test_xss_core( client_id += MESSAGE_ID_INCREMENT; // Editing a doc block prompts the Server to send the Client a re-translated - // version of the document; the Client's acknowledgement comes back here as a - // `Result(Ok)` carrying the Server's ID. + // version of the document; the Client's acknowledgement comes back here as + // a `Result(Ok)` carrying the Server's ID. assert_eq!( codechat_server.get_message_timeout(TIMEOUT).await.unwrap(), EditorMessage { @@ -240,3 +242,570 @@ async fn test_xss_core( Ok(()) } + +make_test!( + test_horizontal_scroll_preserved, + test_horizontal_scroll_preserved_core +); + +// Regression test for +// [#113](https://github.com/bjones1/CodeChat_Editor/issues/113): when the IDE +// moves the cursor into a doc block containing a line too wide for the Client's +// viewport, the Client must scroll vertically to bring that line into view +// without disturbing the horizontal scroll position. Before the fix, +// CodeMirror's `scrollIntoView` pinned the horizontal scrollbar to its maximum. +// +// The test loads a doc block containing a few one-line paragraphs, a fenced +// code block with a very long, non-wrapping line, then more one-line +// paragraphs. It scrolls the CodeMirror scroller horizontally to a middle +// position, then simulates the IDE moving its cursor to each line in the doc +// block (as arrow-key presses in the IDE would), verifying after each move that +// the horizontal scroll position hasn't changed. +async fn test_horizontal_scroll_preserved_core( + codechat_server: CodeChatEditorServerLog, + driver: WebDriver, + test_dir: PathBuf, +) -> Result<(), WebDriverError> { + let path = canonicalize(test_dir.join("test.py")).unwrap(); + let path_str = path.to_str().unwrap().to_string(); + let ide_version = 0.0; + // A long, non-wrapping line: fenced code blocks render as `

`, which
+    // doesn't wrap, so this forces horizontal scrolling.
+    let long_line = "x".repeat(500);
+    let orig_text = formatdoc!(
+        "
+        # 1
+        #
+        # 2
+        #
+        # ```
+        # {long_line}
+        # ```
+        #
+        # 8
+        #
+        # 9
+        "
+    );
+    perform_loadfile(
+        &codechat_server,
+        &test_dir,
+        "test.py",
+        Some((orig_text, ide_version)),
+        false,
+        6.0,
+    )
+    .await;
+
+    // Target the iframe containing the Client.
+    select_codechat_iframe(&driver).await;
+
+    // Scroll the CodeMirror scroller horizontally to a middle position (not
+    // fully left or fully right).
+    let scroller_css = ".CodeChat-CodeMirror .cm-scroller";
+    driver
+        .execute(
+            &format!("document.querySelector('{scroller_css}').scrollLeft = 200;"),
+            Vec::new(),
+        )
+        .await
+        .unwrap();
+    let get_scroll_left = format!("return document.querySelector('{scroller_css}').scrollLeft;");
+    let scroll_left_before: f64 = driver
+        .execute(&get_scroll_left, Vec::new())
+        .await
+        .unwrap()
+        .convert()
+        .unwrap();
+    assert!(
+        scroll_left_before > 0.0,
+        "Failed to scroll the CodeMirror scroller horizontally before the test began."
+    );
+
+    // Simulate the IDE moving its cursor to each line of the doc block, as
+    // arrow-key presses in the IDE would produce. Check every line, including
+    // the fenced-code-block lines.
+    for line in 1..=11u32 {
+        let ide_id = codechat_server
+            .send_message_update_plain(path_str.clone(), None, Some(line), Some(line.into()))
+            .await
+            .unwrap();
+        // The Client acknowledges the Update with a Result(Ok).
+        assert_eq!(
+            codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
+            EditorMessage {
+                id: ide_id,
+                message: EditorMessageContents::Result(Ok(ResultOkTypes::Void))
+            }
+        );
+
+        let scroll_left_after: f64 = driver
+            .execute(&get_scroll_left, Vec::new())
+            .await
+            .unwrap()
+            .convert()
+            .unwrap();
+        assert_eq!(
+            scroll_left_after, scroll_left_before,
+            "Horizontal scroll changed after moving the cursor to line {line}."
+        );
+    }
+
+    assert_no_more_messages(&codechat_server).await;
+
+    Ok(())
+}
+
+make_test!(test_arrow_key_navigation, test_arrow_key_navigation_core);
+
+// Regression test replacing the old Client-only unit test (which drove
+// `docBlockNavKeymap` directly by calling `runScopeHandlers` on a bare
+// CodeMirror instance, with hand-built `doc`/`doc_blocks` data). That approach
+// never reflected real behavior: its synthetic `doc` string collapsed a code
+// line's own trailing newline with the following doc block's placeholder
+// newline (e.g. `"a\nb\n\nc"`, where offset 3 -- "b"'s own newline -- doubled
+// as doc block 1's placeholder). The real Server never produces this shape:
+// it always appends each doc block's placeholder newline(s) *in addition to*
+// the preceding code block's own trailing newline (see the comment above
+// `source.push_str(&"\n".repeat(doc_block.lines))` in
+// `processing.rs::source_to_codechat_for_web`).
+//
+// Against a real document, that one-character difference used to matter:
+// `docBlockNavKeymap`'s `ArrowDown` handler computed
+// `search_pos = lineAt(main.head).to`, which lands on the code line's own
+// newline -- one position *before* where the doc block actually starts -- so
+// the lookup never matched, the keymap reported the key unhandled, and
+// CodeMirror's default `ArrowDown` jumped straight over the (atomic) doc block
+// widgets to the next real code line instead. This was a real, reproducible
+// off-by-one bug the old synthetic test could never have caught; it's now
+// fixed by using `lineAt(main.head).to + 1`, matching the `main.head + 1`
+// already used by the analogous `ArrowRight` handler. `ArrowUp`'s
+// `search_pos = lineAt(main.head).from` never had this problem, since a doc
+// block's placeholder newline(s) sit immediately before the following code
+// line with nothing in between.
+//
+// Fixing the off-by-one also exposed a second, related bug: both handlers had
+// a "chained navigation" branch that checked whether `main.head` already sat
+// at a doc block boundary, to decide whether this was a continued chain
+// through consecutive doc blocks rather than a fresh entry from a code line.
+// But `main.head` sitting at a doc block's boundary is exactly what a fresh
+// arrival at the neighboring code line's edge looks like too (a doc block's
+// `to` is numerically identical to the following code line's `from`), so the
+// branch misfired on fresh entries, treating them as chained and skipping
+// straight past the intended doc block. In practice this branch was
+// unreachable for its intended purpose anyway: chaining between two
+// consecutive, already-focused doc blocks happens entirely outside CodeMirror
+// (via the browser's native contenteditable caret handling and
+// `DocBlockPlugin`'s `focusin` promotion -- see the comment further below),
+// so by the time a second consecutive doc-block-entering keypress could
+// occur, CodeMirror would no longer even have focus for `docBlockNavKeymap`
+// to run. Both handlers now just look at the fixed boundary position with no
+// "chained" special case.
+//
+// This test drives real keyboard input through WebDriver, so each
+// `ArrowDown`/`ArrowUp` goes wherever the browser's actual focus is -- exactly
+// as a user's keystrokes would -- rather than assuming CodeMirror stays
+// focused across every keypress the way the old test did. It uses the same
+// document shape as the old test: a code block (`a`, `b`), two consecutive
+// one-line doc blocks with different indents (so they remain separate blocks
+// -- see the merge rule in `lexer.rs`), then another code block (`c`).
+//
+// After each keypress, the test waits for the autosave timer to fire and
+// checks the `cursor_position` the Client reports back to the IDE. A doc
+// block's cursor is computed from `document.activeElement` client-side (see
+// `set_CodeMirror_positions` in `CodeMirror-integration.mts`) and sent to the
+// Server as a `DomLocation`, which the Server then translates into the
+// doc block's source line number before forwarding to the IDE (see the
+// comment on `CursorPosition::DomLocation` in `webserver.rs`) -- so a `Line`
+// value naming a doc block's line is proof that real DOM focus, not just
+// CodeMirror's internal selection, moved into that block.
+async fn test_arrow_key_navigation_core(
+    codechat_server: CodeChatEditorServerLog,
+    driver: WebDriver,
+    test_dir: PathBuf,
+) -> Result<(), WebDriverError> {
+    let path = canonicalize(test_dir.join("test.py")).unwrap();
+    let path_str = path.to_str().unwrap().to_string();
+    let ide_version = 0.0;
+    // Source lines, and the CodeMirror line each becomes on the Client:
+    // "a" -> 1, "b" -> 2, "# 3" (doc block 1, indent "") -> 3,
+    // " # 4" (doc block 2, indent " ") -> 4, "c" -> 5. The differing indent
+    // keeps the two doc blocks separate instead of merging into one.
+    let orig_text = "a\nb\n# 3\n # 4\nc\n".to_string();
+    perform_loadfile(
+        &codechat_server,
+        &test_dir,
+        "test.py",
+        Some((orig_text, ide_version)),
+        false,
+        6.0,
+    )
+    .await;
+
+    // Target the iframe containing the Client.
+    select_codechat_iframe(&driver).await;
+
+    let mut client_id = INITIAL_CLIENT_MESSAGE_ID;
+
+    // Wait for the autosave timer to report the current cursor position, and
+    // check it against the expected code line.
+    async fn assert_cursor_line(
+        codechat_server: &CodeChatEditorServerLog,
+        client_id: &mut f64,
+        path_str: &str,
+        line: u32,
+    ) {
+        assert_eq!(
+            codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
+            EditorMessage {
+                id: *client_id,
+                message: EditorMessageContents::Update(UpdateMessageContents {
+                    file_path: path_str.to_string(),
+                    cursor_position: Some(CursorPosition::Line(line)),
+                    scroll_position: Some(1.0),
+                    is_re_translation: false,
+                    contents: None,
+                })
+            }
+        );
+        codechat_server.send_result(*client_id, None).await.unwrap();
+        *client_id += MESSAGE_ID_INCREMENT;
+    }
+
+    // ### `ArrowDown` from a code line enters the doc block below it.
+    //
+    // Click near the start of line "b" (the last line of the top code
+    // block), then move to its end with `End`, which is the boundary
+    // `docBlockNavKeymap`'s `ArrowDown` handler looks for.
+    let code_lines = driver
+        .find_all(By::Css(".CodeChat-CodeMirror .cm-line"))
+        .await
+        .unwrap();
+    click_element_top_left(&driver, &code_lines[1])
+        .await
+        .unwrap();
+    assert_cursor_line(&codechat_server, &mut client_id, &path_str, 2).await;
+    end_of_line(&code_lines[1], "").await.unwrap();
+    assert_cursor_line(&codechat_server, &mut client_id, &path_str, 2).await;
+
+    // With the off-by-one fixed, this moves focus into the first doc block
+    // ("# 3", line 3) rather than skipping both (atomic) doc block widgets to
+    // land on "c" (line 5).
+    driver
+        .action_chain()
+        .send_keys(Key::Down)
+        .perform()
+        .await
+        .unwrap();
+    assert_cursor_line(&codechat_server, &mut client_id, &path_str, 3).await;
+
+    // ### Chained navigation between two consecutive doc blocks works too.
+    //
+    // Focus is now genuinely in the first doc block's `.CodeChat-doc-contents`
+    // div (promoted to TinyMCE), outside CodeMirror and thus outside
+    // `docBlockNavKeymap`. Even so, a further `ArrowDown` (with the caret
+    // already at the very end of that block's content) moves focus into the
+    // second, following doc block -- the browser's default caret-boundary
+    // handling for the contenteditable region falls through to the adjacent
+    // `.CodeChat-doc-contents` div, which then goes through the same
+    // `focusin` promotion as any other doc block. Doc block 2 (" # 4")
+    // translates to line 4.
+    driver
+        .action_chain()
+        .send_keys(Key::Down)
+        .perform()
+        .await
+        .unwrap();
+    assert_cursor_line(&codechat_server, &mut client_id, &path_str, 4).await;
+
+    // ### `ArrowDown` from the last doc block exits back to code.
+    //
+    // A doc block's contents div (once promoted, living inside TinyMCE's own
+    // iframe document) is a contenteditable region entirely separate from
+    // CodeMirror's, so unlike the doc-block-to-doc-block case above (which
+    // works because both blocks are DOM siblings the browser's default
+    // caret-boundary handling walks between), nothing hands focus back to
+    // CodeMirror when there's no further doc block to chain into via that
+    // same mechanism. In practice, though, the browser's caret-boundary walk
+    // continues past doc block 2's contents into its `.CodeChat-doc` sibling
+    // structure and on to the next code line "c" (line 5) once the indent
+    // div is no longer permanently `contenteditable` (see the `mousedown`/
+    // `focusout` handlers in `DocBlockPlugin`, which toggle it instead).
+    driver
+        .action_chain()
+        .send_keys(Key::Down)
+        .perform()
+        .await
+        .unwrap();
+    assert_cursor_line(&codechat_server, &mut client_id, &path_str, 5).await;
+
+    // ### `ArrowUp` from a code line correctly enters the doc block above it.
+    //
+    // `ArrowUp`'s boundary math has no off-by-one (a doc block's placeholder
+    // newline(s) sit immediately before the following code line), so this
+    // direction has always worked. Click directly on code line "c" to give
+    // CodeMirror real focus there (the doc block gap above left focus stuck
+    // in doc block 2's TinyMCE instance), then press `Home` so the cursor
+    // sits at the exact line start `docBlockNavKeymap`'s `ArrowUp` handler
+    // looks for.
+    let c_line = driver
+        .find(By::XPath("//*[contains(@class, 'cm-line')][text()='c']"))
+        .await
+        .unwrap();
+    click_element_top_left(&driver, &c_line).await.unwrap();
+    assert_cursor_line(&codechat_server, &mut client_id, &path_str, 5).await;
+    beginning_of_line(&c_line, "").await.unwrap();
+    sleep(Duration::from_millis(400)).await;
+    while let Some(msg) = codechat_server
+        .get_message_timeout(Duration::from_millis(100))
+        .await
+    {
+        assert_eq!(msg.id, client_id);
+        codechat_server.send_result(client_id, None).await.unwrap();
+        client_id += MESSAGE_ID_INCREMENT;
+    }
+
+    driver
+        .action_chain()
+        .send_keys(Key::Up)
+        .perform()
+        .await
+        .unwrap();
+    // The Client reports the doc block's cursor as a `DomLocation` (a DOM
+    // coordinate), but the Server translates that into a plain `Line` before
+    // forwarding to the IDE -- `DomLocation` is a Client/Server-only detail
+    // (see the comment on `CursorPosition::DomLocation` in `webserver.rs`).
+    // Doc block 2 (" # 4") translates to line 4.
+    assert_cursor_line(&codechat_server, &mut client_id, &path_str, 4).await;
+
+    // ### Chaining `ArrowUp` between two consecutive doc blocks overshoots
+    // straight to the code above, skipping doc block 1.
+    //
+    // Focus is now genuinely in the second doc block's
+    // `.CodeChat-doc-contents` div (promoted to TinyMCE), outside CodeMirror
+    // and thus outside `docBlockNavKeymap`, with the caret at the very end of
+    // that block's content ("entering from below" lands the caret at the
+    // end; see `DocBlockPlugin`'s `focusin` handler). Each doc block's
+    // wrapper (`.CodeChat-doc`) is no longer permanently `contenteditable`
+    // on its indent (see the `mousedown`/`focusout` handlers in
+    // `DocBlockPlugin`), so the browser's native caret-boundary walk now
+    // carries `ArrowUp` all the way from doc block 2's contents, through doc
+    // block 1's (very short, single-character) contents, and out the other
+    // side into code line "b" (line 2) in a single keypress -- reported as a
+    // plain `Line`, not a `DomLocation`, confirming focus landed in
+    // CodeMirror rather than a doc block's DOM.
+    driver
+        .action_chain()
+        .send_keys(Key::Up)
+        .perform()
+        .await
+        .unwrap();
+    assert_cursor_line(&codechat_server, &mut client_id, &path_str, 2).await;
+
+    assert_no_more_messages(&codechat_server).await;
+
+    Ok(())
+}
+
+make_test!(
+    test_arrow_key_navigation_multiline_doc_block,
+    test_arrow_key_navigation_multiline_doc_block_core
+);
+
+// Regression test for a manually-observed bug: moving the cursor from a code
+// line to a *multi-line* doc block places the cursor at the doc block's first
+// line rather than its last line. `test_arrow_key_navigation_core` above only
+// exercises single-line doc blocks (two separate one-line doc blocks, in
+// fact), which isn't enough to catch this -- entering a one-line doc block,
+// its first line and its last line are the same line, so an off-by-one in
+// "first vs. last" can't show up there.
+//
+// This test uses six consecutive comment lines sharing the same indent
+// ("# 3", "#", then four "# " lines), which the lexer merges
+// into a *single* six-line doc block (see the check `last_doc_block.indent ==
+// indent && last_doc_block.delimiter == delimiter` in `lexer.rs`, which
+// appends each comment's contents to the previous one rather than starting a
+// new doc block). The blank `#` line forces the Markdown contents to render
+// as two separate paragraphs rather than one line-wrapped paragraph (matching
+// the `// One`, `//`, `// Two` pattern used by the analogous Rust unit test in
+// `processing/tests.rs`); without it, CommonMark would join "3" and the
+// second paragraph into a single visual line, unable to expose a
+// first-vs-last-line bug. The second paragraph's four lines are themselves
+// pre-wrapped (each already at the Server's own word-wrap width for this doc
+// block -- see the `wrapped_line` comment below), so CommonMark's soft-wrap
+// rule joins them into one long visual paragraph *without* the Server's
+// HTML-to-Markdown caret-location logic (`doc_block_html_to_markdown` in
+// `processing.rs`) needing to invent any new line breaks when it re-wraps
+// them to locate the caret. That matters: an *unwrapped* single long source
+// line for this paragraph also fails this test, but for a different reason
+// than a beginning/end caret mix-up -- the re-wrap invents extra line breaks
+// not present in the actual CodeMirror source, inflating the reported line
+// number past the end of the document entirely. Pre-wrapping the source
+// avoids that confound, isolating this test to the beginning-vs-end caret
+// question alone; both the line-number check and a direct DOM caret-position
+// check below pass under these conditions, indicating that particular defect
+// doesn't reproduce here. That doc block spans CodeMirror lines 3-8; the
+// following code line "c" is line 9.
+async fn test_arrow_key_navigation_multiline_doc_block_core(
+    codechat_server: CodeChatEditorServerLog,
+    driver: WebDriver,
+    test_dir: PathBuf,
+) -> Result<(), WebDriverError> {
+    let path = canonicalize(test_dir.join("test.py")).unwrap();
+    let path_str = path.to_str().unwrap().to_string();
+    let ide_version = 0.0;
+    // A paragraph line, pre-wrapped at the same width the Server's own word
+    // wrap (`WORD_WRAP_COLUMN` minus this doc block's delimiter-plus-space
+    // width, in `processing.rs`) produces for this doc block's indent ("")
+    // and delimiter ("#") -- confirmed by feeding this exact paragraph
+    // through `doc_block_html_to_markdown` directly, which wraps it into four
+    // lines of "four" repeated 15 times each (74 characters). Repeating that
+    // already-wrapped line four times below reproduces the Server's own wrap
+    // points exactly, so its HTML-to-Markdown re-wrap (done to locate the
+    // caret) doesn't invent any new line breaks.
+    let wrapped_line = std::iter::repeat_n("four", 15)
+        .collect::>()
+        .join(" ");
+    // Source lines, and the CodeMirror line each becomes on the Client:
+    // "a" -> 1, "b" -> 2, "# 3" + "#" + four "# " lines (one
+    // merged six-line doc block, indent "") -> 3-8, "c" -> 9.
+    let orig_text = format!(
+        "a\nb\n# 3\n#\n# {wrapped_line}\n# {wrapped_line}\n# {wrapped_line}\n# {wrapped_line}\nc\n"
+    );
+    perform_loadfile(
+        &codechat_server,
+        &test_dir,
+        "test.py",
+        Some((orig_text, ide_version)),
+        false,
+        6.0,
+    )
+    .await;
+
+    // Target the iframe containing the Client.
+    select_codechat_iframe(&driver).await;
+
+    let mut client_id = INITIAL_CLIENT_MESSAGE_ID;
+
+    // Wait for the autosave timer to report the current cursor position, and
+    // check it against the expected code line.
+    async fn assert_cursor_line(
+        codechat_server: &CodeChatEditorServerLog,
+        client_id: &mut f64,
+        path_str: &str,
+        line: u32,
+    ) {
+        assert_eq!(
+            codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
+            EditorMessage {
+                id: *client_id,
+                message: EditorMessageContents::Update(UpdateMessageContents {
+                    file_path: path_str.to_string(),
+                    cursor_position: Some(CursorPosition::Line(line)),
+                    scroll_position: Some(1.0),
+                    is_re_translation: false,
+                    contents: None,
+                })
+            }
+        );
+        codechat_server.send_result(*client_id, None).await.unwrap();
+        *client_id += MESSAGE_ID_INCREMENT;
+    }
+
+    // Click directly on code line "c" -- the line immediately following the
+    // multi-line doc block -- to give CodeMirror real focus there, then press
+    // `Home` so the cursor sits at the exact line start `docBlockNavKeymap`'s
+    // `ArrowUp` handler looks for.
+    //
+    // Confirm the click genuinely lands on code line "c" (i.e. `Line(9)`),
+    // not inside the preceding doc block.
+    let c_line = driver
+        .find(By::XPath("//*[contains(@class, 'cm-line')][text()='c']"))
+        .await
+        .unwrap();
+    c_line.click().await.unwrap();
+    end_of_line(&c_line, "").await.unwrap();
+    assert_cursor_line(&codechat_server, &mut client_id, &path_str, 9).await;
+
+    // `ArrowUp` from code line "c" should enter the doc block above it with
+    // the cursor at the block's *last* line (8), matching the "entering from
+    // below lands at the end" rule documented on `docBlockNavKeymap` and
+    // `DocBlockPlugin`'s `focusin` handler.
+    driver
+        .action_chain()
+        .send_keys(Key::Up)
+        .perform()
+        .await
+        .unwrap();
+    let msg = optional_message(
+        &codechat_server,
+        &mut client_id,
+        EditorMessageContents::Update(UpdateMessageContents {
+            file_path: path_str.clone(),
+            cursor_position: Some(CursorPosition::Line(8)),
+            scroll_position: None,
+            is_re_translation: false,
+            contents: None,
+        }),
+    )
+    .await;
+    assert_eq!(
+        msg,
+        EditorMessage {
+            id: client_id,
+            message: EditorMessageContents::Update(UpdateMessageContents {
+                file_path: path_str.to_string(),
+                cursor_position: Some(CursorPosition::Line(8)),
+                scroll_position: Some(1.0),
+                is_re_translation: false,
+                contents: None,
+            })
+        }
+    );
+    codechat_server.send_result(client_id, None).await.unwrap();
+    //client_id += MESSAGE_ID_INCREMENT;
+
+    // `Line(8)` only proves the caret is somewhere on the paragraph's *last*
+    // source line -- it can't distinguish that line's start from its end.
+    // Independently confirm the DOM caret placement itself: per the
+    // "entering from below lands at the end" rule (see `DocBlockPlugin`'s
+    // `focusin` handler in `CodeMirror-integration.mts`, which does
+    // `range.selectNodeContents(contents); range.collapse(!at_end)`), the
+    // caret should sit at the very end of the doc block's text -- after the
+    // last "four" -- not at its start.
+    let is_caret_at_end: bool = driver
+        .execute(
+            "const contents = document.activeElement.closest('.CodeChat-doc-contents');
+            if (!contents) return false;
+            const sel = window.getSelection();
+            if (sel.rangeCount === 0) return false;
+            // Walk to the last text node under `contents` (the true end of
+            // its rendered content), rather than comparing against an
+            // element-boundary point -- an (element, childNodes.length)
+            // point always sorts after any (textNode, offset) point inside
+            // that last child, even when the text offset is the text node's
+            // own final position, which would produce false negatives here.
+            let last_text_node = contents;
+            while (last_text_node.lastChild) {
+                last_text_node = last_text_node.lastChild;
+            }
+            return (
+                sel.anchorNode === last_text_node &&
+                sel.anchorOffset === last_text_node.textContent.length
+            );",
+            Vec::new(),
+        )
+        .await
+        .unwrap()
+        .convert()
+        .unwrap();
+    assert!(
+        is_caret_at_end,
+        "ArrowUp from code line \"c\" should land the caret at the end of the \
+         multi-line doc block's last (word-wrapped) paragraph, not at its start."
+    );
+
+    assert_no_more_messages(&codechat_server).await;
+
+    Ok(())
+}
diff --git a/server/tests/overall_5.rs b/server/tests/overall_5.rs
new file mode 100644
index 00000000..8c7583d5
--- /dev/null
+++ b/server/tests/overall_5.rs
@@ -0,0 +1,272 @@
+// Copyright (C) 2025 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).
+/// `overall_5.rs` - test the overall system
+/// ========================================
+///
+/// These are functional tests of the overall system, performed by attaching a
+/// testing IDE to generate commands then observe results, along with a browser
+/// tester.
+///
+/// To run this test, execute `cargo test --test overall_5 `
+/// in the `server/` directory.
+// Modules
+// -------
+mod overall_common;
+
+// Imports
+// -------
+//
+// ### Standard library
+use std::path::PathBuf;
+
+// ### Third-party
+use dunce::canonicalize;
+use pretty_assertions::assert_eq;
+use thirtyfour::{By, Key, WebDriver, error::WebDriverError};
+
+// ### Local
+use crate::overall_common::{
+    CodeChatEditorServerLog, TIMEOUT, assert_no_more_messages, beginning_of_line, end_of_line,
+    perform_loadfile, select_codechat_iframe,
+};
+use code_chat_editor::webserver::{
+    CursorPosition, EditorMessage, EditorMessageContents, INITIAL_CLIENT_MESSAGE_ID,
+    MESSAGE_ID_INCREMENT, UpdateMessageContents,
+};
+use test_utils::prep_test_dir;
+
+// Tests
+// -----
+make_test!(
+    test_cursor_home_from_code_after_doc_block,
+    test_cursor_home_from_code_after_doc_block_core
+);
+
+// Regression test to ensure left arrow allows placing the cursor at the
+// beginning of a code block, then moves back to the end of the preceding doc
+// block on another left arrow press. The preceding doc block here spans two
+// source lines, to catch a manually-observed bug (currently failing) where
+// that second left-arrow press lands the cursor at the doc block's
+// *beginning* instead of its *end*. Also checks (currently failing) that
+// pressing Home at the end of the code block keeps the cursor on that line
+// rather than moving up into the preceding doc block, and that pressing Home
+// a second time (a no-op, since the cursor is already at the start of the
+// line) also keeps the cursor on the current line.
+async fn test_cursor_home_from_code_after_doc_block_core(
+    codechat_server: CodeChatEditorServerLog,
+    driver: WebDriver,
+    test_dir: PathBuf,
+) -> Result<(), WebDriverError> {
+    let path = canonicalize(test_dir.join("test.py")).unwrap();
+    let path_str = path.to_str().unwrap().to_string();
+    let ide_version = 0.0;
+    let orig_text = "# a
\n# b\ncc\n".to_string(); + perform_loadfile( + &codechat_server, + &test_dir, + "test.py", + Some((orig_text, ide_version)), + false, + 6.0, + ) + .await; + + // Target the iframe containing the Client. + select_codechat_iframe(&driver).await; + + let mut client_id = INITIAL_CLIENT_MESSAGE_ID; + + // Click on the two-character code block ("cc"), which focuses CodeMirror + // and reports the cursor at line 3. The click is in the middle of the element, which places the cursor at the end of the line (given that the width of the screen is much larger than the width of a two-character line.) + let code_line = driver + .find(By::XPath("//*[contains(@class, 'cm-line')][text()='cc']")) + .await + .unwrap(); + code_line.click().await.unwrap(); + assert_eq!( + codechat_server.get_message_timeout(TIMEOUT).await.unwrap(), + EditorMessage { + id: client_id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: path_str.clone(), + cursor_position: Some(CursorPosition::Line(3)), + scroll_position: Some(1.0), + is_re_translation: false, + contents: None, + }) + } + ); + codechat_server.send_result(client_id, None).await.unwrap(); + client_id += MESSAGE_ID_INCREMENT; + + // The cursor is at the end of the two "c"s. The first `Left` press should + // simply move the cursor to the middle of the two "c"s, staying on the current + // line rather than jumping into the preceding doc block. + code_line.send_keys(Key::Left).await.unwrap(); + assert_eq!( + codechat_server.get_message_timeout(TIMEOUT).await.unwrap(), + EditorMessage { + id: client_id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: path_str.clone(), + cursor_position: Some(CursorPosition::Line(3)), + scroll_position: Some(1.0), + is_re_translation: false, + contents: None, + }) + } + ); + codechat_server.send_result(client_id, None).await.unwrap(); + client_id += MESSAGE_ID_INCREMENT; + + // The cursor is at middle the two "c"s. The next `Left` press should + // move the cursor to the beginning of the two "c"s, staying on the current + // line rather than jumping into the preceding doc block. + code_line.send_keys(Key::Left).await.unwrap(); + assert_eq!( + codechat_server.get_message_timeout(TIMEOUT).await.unwrap(), + EditorMessage { + id: client_id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: path_str.clone(), + cursor_position: Some(CursorPosition::Line(3)), + scroll_position: Some(1.0), + is_re_translation: false, + contents: None, + }) + } + ); + codechat_server.send_result(client_id, None).await.unwrap(); + client_id += MESSAGE_ID_INCREMENT; + + // The cursor is now at the start of code line "cc". A final `Left` press + // should enter the preceding two-line doc block, with the caret landing + // at the block's *end* (per the "entering from below lands at the end" + // rule documented on `docBlockNavKeymap`'s `ArrowLeft` handler), not its + // start. + code_line.send_keys(Key::Left).await.unwrap(); + assert_eq!( + codechat_server.get_message_timeout(TIMEOUT).await.unwrap(), + EditorMessage { + id: client_id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: path_str.clone(), + cursor_position: Some(CursorPosition::Line(2)), + scroll_position: Some(1.0), + is_re_translation: false, + contents: None, + }) + } + ); + codechat_server.send_result(client_id, None).await.unwrap(); + client_id += MESSAGE_ID_INCREMENT; + + // `Line(2)` only proves the caret is somewhere on the doc block's last + // source line -- it can't distinguish that line's start from its end. + // Independently confirm the DOM caret placement itself, mirroring the + // check in `test_arrow_key_navigation_multiline_doc_block_core` + // (`overall_4.rs`): the caret should sit at the very end of the doc + // block's text -- after "b" -- not at its start. + let is_caret_at_end: bool = driver + .execute( + "const contents = document.activeElement.closest('.CodeChat-doc-contents'); + if (!contents) return false; + const sel = window.getSelection(); + if (sel.rangeCount === 0) return false; + let last_text_node = contents; + while (last_text_node.lastChild) { + last_text_node = last_text_node.lastChild; + } + return ( + sel.anchorNode === last_text_node && + sel.anchorOffset === last_text_node.textContent.length + );", + Vec::new(), + ) + .await + .unwrap() + .convert() + .unwrap(); + assert!( + is_caret_at_end, + "ArrowLeft from code line \"cc\" should land the caret at the end of the \ + two-line doc block, not at its start." + ); + + // Move back into the code block for the remaining `Home` checks below. + code_line.click().await.unwrap(); + end_of_line(&code_line, "").await.unwrap(); + assert_eq!( + codechat_server.get_message_timeout(TIMEOUT).await.unwrap(), + EditorMessage { + id: client_id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: path_str.clone(), + cursor_position: Some(CursorPosition::Line(3)), + scroll_position: Some(1.0), + is_re_translation: false, + contents: None, + }) + } + ); + codechat_server.send_result(client_id, None).await.unwrap(); + client_id += MESSAGE_ID_INCREMENT; + + // The cursor is already at the end of the line (from `end_of_line` above, + // line 214), so press `Home` via the `beginning_of_line` helper directly, + // to check for a regression: the cursor should stay on the current line + // rather than jumping up into the preceding doc block. + beginning_of_line(&code_line, "").await.unwrap(); + assert_eq!( + codechat_server.get_message_timeout(TIMEOUT).await.unwrap(), + EditorMessage { + id: client_id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: path_str.clone(), + cursor_position: Some(CursorPosition::Line(3)), + scroll_position: Some(1.0), + is_re_translation: false, + contents: None, + }) + } + ); + codechat_server.send_result(client_id, None).await.unwrap(); + client_id += MESSAGE_ID_INCREMENT; + + // Press `Home` a second time. The cursor is already at the beginning of + // the line, so this should be a no-op that keeps the cursor on the + // current line -- not a jump up into the preceding doc block. + beginning_of_line(&code_line, "").await.unwrap(); + assert_eq!( + codechat_server.get_message_timeout(TIMEOUT).await.unwrap(), + EditorMessage { + id: client_id, + message: EditorMessageContents::Update(UpdateMessageContents { + file_path: path_str.clone(), + cursor_position: Some(CursorPosition::Line(3)), + scroll_position: Some(1.0), + is_re_translation: false, + contents: None, + }) + } + ); + codechat_server.send_result(client_id, None).await.unwrap(); + //client_id += MESSAGE_ID_INCREMENT; + + assert_no_more_messages(&codechat_server).await; + + Ok(()) +} diff --git a/server/tests/overall_common/mod.rs b/server/tests/overall_common/mod.rs index 3b09a9b3..38be0205 100644 --- a/server/tests/overall_common/mod.rs +++ b/server/tests/overall_common/mod.rs @@ -54,7 +54,7 @@ use futures::FutureExt; use pretty_assertions::assert_eq; use thirtyfour::{ BrowserLogEntry, By, ChromiumLikeCapabilities, DesiredCapabilities, Key, LoggingPrefsLogLevel, - WebDriver, WebElement, error::WebDriverError, + TypingData, WebDriver, WebElement, error::WebDriverError, }; use tracing::{debug, error, info, warn}; use tracing_log::LogTracer; @@ -272,14 +272,22 @@ pub async fn harness< // key to go to the end of the line...but it's not the end of the full line // on a narrow screen. caps.add_arg("--window-size=1920,768")?; - //caps.add_arg("--auto-open-devtools-for-tabs")?; // Tell chromedriver to capture page-side `console.*` output and uncaught // JavaScript errors in the `browser` log buffer, which we drain below and // forward to Rust logging. Without this capability the `/log` endpoint // returns nothing regardless of what the page does. caps.set_browser_log_level(LoggingPrefsLogLevel::All)?; - // Comment this out to debug test failures. + + // Debug support: + // + // Comment/uncomment these out to debug test failures. caps.add_arg("--headless")?; + //caps.add_arg("--auto-open-devtools-for-tabs")?; + // Insert the code in a test to pause it for manual inspection. + //use std::time::Duration; + //use tokio::time::sleep; + //sleep(Duration::from_hours(1)).await; + // On Ubuntu CI, avoid failures, probably due to running Chrome as root. #[cfg(target_os = "linux")] if env::var("CI") == Ok("true".to_string()) { @@ -395,6 +403,23 @@ macro_rules! make_test { $crate::overall_common::harness($test_core_name, prep_test_dir!()).await } }; + + // Same as above, but for a test that's currently known to fail (a + // regression test pinning down an unfixed bug). `harness` converts a + // panic into a `Result::Err` (see its `catch_unwind` use, needed to shut + // the WebDriver down cleanly), so the failure never becomes a live + // unwind -- meaning `#[should_panic]` can't detect it. `#[ignore]` is + // the alternative: the test is skipped by default (so the suite stays + // green) but still compiles, and can be run explicitly with `cargo test + // -- --ignored` to check whether the bug has been fixed yet. + ($test_name: ident, $test_core_name: ident, ignore = $reason: literal) => { + #[tokio::test] + #[tracing::instrument] + #[ignore = $reason] + async fn $test_name() -> Result<(), Box> { + $crate::overall_common::harness($test_core_name, prep_test_dir!()).await + } + }; } // Given an `Update` message with contents, get the version. @@ -478,6 +503,106 @@ pub async fn goto_line( Ok(()) } +// Cursor-navigation helpers +// ------------------------- +// +// On macOS, key combinations that are supposed to jump to the beginning/end of +// a document (`Ctrl+Home`, `Ctrl+End`, `Cmd+Up`, `Cmd+Down`, ...) are handled +// by macOS's native Cocoa/WebKit text-editing bridge rather than by pure +// JavaScript `keydown`/`keyup` DOM events. ChromeDriver's `send_keys` only +// injects DOM-level key events, so on macOS these shortcuts are silently +// swallowed before they ever produce the OS-level cursor jump. This is a +// longstanding WebDriver/Selenium limitation, not a bug in this project -- +// see [Command key modifier doesn't work on Mac +// OS](https://github.com/SeleniumHQ/selenium/issues/1290). +// +// `Ctrl+Home`/`Ctrl+End` do work via `send_keys` on Windows/Linux for a plain +// CodeMirror line, but empirically do *not* reliably reach the true +// beginning/end inside a TinyMCE `contenteditable` doc block (observed +// landing partway through the block instead of at the first/last paragraph, +// even on Windows) -- presumably TinyMCE's own keyboard-shortcut handling +// intercepts or only partially handles them. So rather than branch by OS, +// [`beginning_of_document`] and [`end_of_document`] always use the +// repeated-arrow-key approach below, which works uniformly on every platform +// and in both CodeMirror and TinyMCE elements. +// +// Each helper accepts `keys_after`, sent in the same `send_keys` call as the +// navigation keys (rather than a separate `send_keys` call afterward): each +// `send_keys` call can produce its own debounced cursor-update message, so +// splitting one logical action into two calls can surface an extra, unwanted +// intermediate update. + +// Move the cursor to the beginning of the current line, then send `keys_after` +// (which may be empty). Plain `Home` (no modifier) is handled by the browser +// itself on every platform, so no OS-specific workaround is needed here. +#[allow(dead_code)] +#[tracing::instrument(skip(element))] +pub async fn beginning_of_line( + element: &WebElement, + keys_after: impl Into + std::fmt::Debug, +) -> Result<(), WebDriverError> { + element.send_keys(Key::Home + keys_after).await +} + +// Move the cursor to the end of the current line, then send `keys_after` +// (which may be empty). Plain `End` (no modifier) is handled by the browser +// itself on every platform, so no OS-specific workaround is needed here. +#[allow(dead_code)] +#[tracing::instrument(skip(element))] +pub async fn end_of_line( + element: &WebElement, + keys_after: impl Into + std::fmt::Debug, +) -> Result<(), WebDriverError> { + element.send_keys(Key::End + keys_after).await +} + +// Move the cursor to the beginning of the document, then send `keys_after` +// (which may be empty). See the module-level comment above for why this +// presses `Up` enough times to reach line 1 from anywhere within a test +// fixture's (small) document, rather than using `Ctrl+Home`/`Cmd+Up`. +#[allow(dead_code)] +#[tracing::instrument(skip(element))] +pub async fn beginning_of_document( + element: &WebElement, + keys_after: impl Into + std::fmt::Debug, +) -> Result<(), WebDriverError> { + // Test fixtures used by this suite are well under this many lines; + // repeating `Up` past the first line is a no-op, so an overshoot is + // harmless. Sent as a single `send_keys` call, along with `keys_after`, + // so this produces one cursor update rather than one per repeated key. + let keys: TypingData = repeated_key(Key::Up, MAX_TEST_DOCUMENT_LINES) + keys_after; + element.send_keys(keys).await +} + +// Move the cursor to the end of the document, then send `keys_after` (which +// may be empty). See the module-level comment above for why this presses +// `Down` enough times to reach the last line from anywhere within a test +// fixture's (small) document (then `End` to reach the end of that line), +// rather than using `Ctrl+End`/`Cmd+Down`. +#[allow(dead_code)] +#[tracing::instrument(skip(element))] +pub async fn end_of_document( + element: &WebElement, + keys_after: impl Into + std::fmt::Debug, +) -> Result<(), WebDriverError> { + let keys: TypingData = repeated_key(Key::Down, MAX_TEST_DOCUMENT_LINES) + Key::End + keys_after; + element.send_keys(keys).await +} + +// Build a `TypingData` consisting of `key` repeated `count` times, for the +// macOS repeated-arrow-key workaround in [`beginning_of_document`] and +// [`end_of_document`]. +fn repeated_key(key: Key, count: u32) -> TypingData { + std::iter::repeat_n(key.value(), count as usize) + .collect::() + .into() +} + +// An upper bound on the number of lines in any document used by this test +// suite's fixtures, used by the macOS `Up`/`Down`-repeating workaround in +// [`beginning_of_document`] and [`end_of_document`] above. +const MAX_TEST_DOCUMENT_LINES: u32 = 100; + pub async fn perform_loadfile( codechat_server: &CodeChatEditorServerLog, test_dir: &Path, diff --git a/test_utils/Cargo.lock b/test_utils/Cargo.lock index 32b8f1ab..af8324f3 100644 --- a/test_utils/Cargo.lock +++ b/test_utils/Cargo.lock @@ -13,18 +13,17 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "assert_fs" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a652f6cb1f516886fcfee5e7a5c078b9ade62cfcb889524efe5a64d682dd27a9" +checksum = "6ecf5c70ca07b7f80220bce936f0556a960ca6fb00fc2bd4125b5e581b218137" dependencies = [ "anstyle", - "doc-comment", "globwalk", "predicates", "predicates-core", @@ -34,37 +33,35 @@ dependencies = [ [[package]] name = "assertables" -version = "9.8.3" +version = "10.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbada39b42413d4db3d9460f6e791702490c40f72924378a1b6fc1a4181188fd" +checksum = "b3c16d80246a076246d8b525d9f404543e90fe0818636cd89c249c2a4bee3bb1" +dependencies = [ + "regex", + "walkdir", +] [[package]] name = "bitflags" -version = "2.10.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" [[package]] name = "bstr" -version = "1.12.1" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +checksum = "5cee35f73844aa3014bb606320a6c1f010249dbdf43342fe54b5a4f6a8ed4b79" dependencies = [ "memchr", - "serde", + "serde_core", ] -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -72,18 +69,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "difflib" @@ -91,12 +88,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" -[[package]] -name = "doc-comment" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" - [[package]] name = "errno" version = "0.3.14" @@ -109,21 +100,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasip2", -] +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "globset" @@ -151,9 +130,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.25" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" +checksum = "fe112b004901c62c2faa11f4f75e9864e0cc5af8da71c9115d184a3aa888749f" dependencies = [ "crossbeam-deque", "globset", @@ -167,39 +146,39 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.178" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "log" -version = "0.4.29" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "predicates" -version = "3.1.3" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" +checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe" dependencies = [ "anstyle", "difflib", @@ -208,15 +187,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" +checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144" [[package]] name = "predicates-tree" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +checksum = "d0de1b847b39c8131db0467e9df1ff60e6d0562ab8e9a16e568ad0fdb372e2f2" dependencies = [ "predicates-core", "termtree", @@ -224,33 +203,39 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" dependencies = [ "proc-macro2", ] [[package]] -name = "r-efi" -version = "5.3.0" +name = "regex" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -259,15 +244,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", @@ -285,15 +270,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", -] - [[package]] name = "serde_core" version = "1.0.228" @@ -316,9 +292,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.111" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -327,12 +303,11 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.23.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom", "once_cell", "rustix", "windows-sys", @@ -355,9 +330,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "walkdir" @@ -369,15 +344,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "wasip2" -version = "1.0.1+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" -dependencies = [ - "wit-bindgen", -] - [[package]] name = "winapi-util" version = "0.1.11" @@ -401,9 +367,3 @@ checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link", ] - -[[package]] -name = "wit-bindgen" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index a475d3db..fc6caa7e 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -5,5 +5,5 @@ edition = "2024" [dependencies] assert_fs = "1" -assertables = "9" +assertables = "10" log = "0.4" diff --git a/toc.md b/toc.md index d94247be..2d11d4d5 100644 --- a/toc.md +++ b/toc.md @@ -80,6 +80,7 @@ Implementation * [Cargo.toml](extensions/VSCode/Cargo.toml) * [Developer documentation](extensions/VSCode/developer.md) * Development tools + * [CLAUDE.md](CLAUDE.md) * Builder * [builder/Cargo.toml](builder/Cargo.toml) * [builder/src/main.rs](builder/src/main.rs)