From 2eb94500dd9008b9c695b0949441d5bfee7f10bd Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones" Unknown lexer type {}.
+* Improved synchronization between the cursor and scroll position of the Client
+ and IDE.
+* Removed accidental debug output.
+* Remove unnecessary TinyMCE plugins.
Version 0.1.40 -- 2025-Nov-11
------------------------------
+--------------------------------------------------------------------------------
-* File watcher now accepts new files from the Client.
-* Improved translation from HTML to Markdown.
-* Build correct binary for Mac M1.
-* Add CodeMirror support for SQL and YAML.
+* File watcher now accepts new files from the Client.
+* Improved translation from HTML to Markdown.
+* Build correct binary for Mac M1.
+* Add CodeMirror support for SQL and YAML.
Version 0.1.39 -- 2025-Oct-23
------------------------------
+--------------------------------------------------------------------------------
-* Scroll viewport to center on cursor movement.
-* Significant improvements to test framework.
-* Improved build framework.
-* Refactor IDE interface back into the Server.
+* Scroll viewport to center on cursor movement.
+* Significant improvements to test framework.
+* Improved build framework.
+* Refactor IDE interface back into the Server.
Version 0.1.38 -- 2025-Sep-24
------------------------------
+--------------------------------------------------------------------------------
-* Automatically find a free port for the Client, instead of requiring the user
- to specify it in the VSCode settings.
-* Remove unused VSCode settings.
-* Update code in the IDE when changes are made to the indent in the Client.
-* Enable spell checking in doc blocks. Note that the VSCode browser doesn't
- support spell checking.
-* Improved build process.
+* Automatically find a free port for the Client, instead of requiring the user
+ to specify it in the VSCode settings.
+* Remove unused VSCode settings.
+* Update code in the IDE when changes are made to the indent in the Client.
+* Enable spell checking in doc blocks. Note that the VSCode browser doesn't
+ support spell checking.
+* Improved build process.
Version 0.1.37 -- 2025-Sep-22
------------------------------
+--------------------------------------------------------------------------------
-* Fix: avoid loading the same file twice in a row when the user clicks on a
- link in the Client.
-* Improve VSCode connection with the Server.
+* Fix: avoid loading the same file twice in a row when the user clicks on a link
+ in the Client.
+* Improve VSCode connection with the Server.
Version 0.1.36 -- 2025-Sep-17
------------------------------
+--------------------------------------------------------------------------------
-* The system continues to work after a PC goes to sleep then wakes back up;
- communication within previous versions fails after a sleep/wake up cycle.
-* Communicate between the VSCode extension and the Server using queues instead
- of a websocket and a queue.
-* Remove the HTML editor's toolbar, to free up more space on the screen.
-* Add a code formatting button to the quick toolbar which appears when tex is
- selected in the HTML editor.
-* Remove the File entry from the HTML editor's main menu.
+* The system continues to work after a PC goes to sleep then wakes back up;
+ communication within previous versions fails after a sleep/wake up cycle.
+* Communicate between the VSCode extension and the Server using queues instead
+ of a websocket and a queue.
+* Remove the HTML editor's toolbar, to free up more space on the screen.
+* Add a code formatting button to the quick toolbar which appears when tex is
+ selected in the HTML editor.
+* Remove the File entry from the HTML editor's main menu.
Version 0.1.35 -- 2025-Sep-12
------------------------------
+--------------------------------------------------------------------------------
-* Embed the CodeChat Editor Server inside the VSCode extension, rather than
- running it as a standalone binary.
-* Fixes to the build process.
+* Embed the CodeChat Editor Server inside the VSCode extension, rather than
+ running it as a standalone binary.
+* Fixes to the build process.
Version 0.1.34 -- 2025-Sep-08
------------------------------
+--------------------------------------------------------------------------------
-* Make the Client text editable again. Improve handling of selections.
-* In VSCode, load a new file in the Client after a short delay, rather than
- immediately. This provides a more efficient process when changing files.
+* Make the Client text editable again. Improve handling of selections.
+* In VSCode, load a new file in the Client after a short delay, rather than
+ immediately. This provides a more efficient process when changing files.
Version 0.1.33 -- 2025-Sep-02
------------------------------
+--------------------------------------------------------------------------------
-* Change `sW5v$JWd&o0S@CeO
zTk-H%3Gi_Va@%lO(Ea!FUiLQsdwmzr|26|K2=wU=l#7G&Y0FPzVGR#^Yp{!_CB?Z!
z|8xKUx+V&J+Q|R0G4cPp0{&Mp`X9?YndyJ5YwZF|>I-bgmYRV9fiR3H$x7+?nI10s
z8xTxCNc
ebp;et(Njcypb9x+3NBo;)rJ1J+`Vf$1;m@;-|?MD*>|y~Ij+|LE%8+K^hYd
`|tF3g(J5dkB@g+Q2RtKsD0i1RByOFL822L{eii=mT})!6e(N$pI1p3L#Vw`hZ?0`fUhAP)d`+zU
zwHTjJ<27(A=*bTUK%`gjy;45E{c`4&-}w$+aqG=ndHUO&i9l4W<#@`LO9
+* Math is now protected from accidental edits in the Client:\
+ 
* Improved synchronization between the cursor and scroll position of the Client
and IDE.
* Removed accidental debug output.
From 033f31f759266268c4e93133fa87996e659acfd0 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
{lexer_spec}markdown
\n"), vec![] - )) + ))) ); // An empty source file. assert_eq!( source_to_codechat_for_web("", &"js".to_string(), false, false), - TranslationResults::CodeChat(build_codechat_for_web("javascript", "", vec![])) + Ok(TranslationResults::CodeChat(build_codechat_for_web( + "javascript", + "", + vec![] + ))) ); // A zero doc block source file. assert_eq!( source_to_codechat_for_web("let a = 1;", &"js".to_string(), false, false), - TranslationResults::CodeChat(build_codechat_for_web("javascript", "let a = 1;", vec![])) + Ok(TranslationResults::CodeChat(build_codechat_for_web( + "javascript", + "let a = 1;", + vec![] + ))) ); // One doc block source files. assert_eq!( source_to_codechat_for_web("// Test", &"js".to_string(), false, false), - TranslationResults::CodeChat(build_codechat_for_web( + Ok(TranslationResults::CodeChat(build_codechat_for_web( "javascript", "\n", vec![build_codemirror_doc_block(0, 1, "", "//", "Test
\n")] - )) + ))) ); assert_eq!( source_to_codechat_for_web("let a = 1;\n// Test", &"js".to_string(), false, false,), - TranslationResults::CodeChat(build_codechat_for_web( + Ok(TranslationResults::CodeChat(build_codechat_for_web( "javascript", "let a = 1;\n\n", vec![build_codemirror_doc_block( @@ -557,15 +570,15 @@ fn test_source_to_codechat_for_web_1() { "//", "Test
\n" )] - )) + ))) ); assert_eq!( source_to_codechat_for_web("// Test\nlet a = 1;", &"js".to_string(), false, false,), - TranslationResults::CodeChat(build_codechat_for_web( + Ok(TranslationResults::CodeChat(build_codechat_for_web( "javascript", "\nlet a = 1;", vec![build_codemirror_doc_block(0, 1, "", "//", "Test
\n")] - )) + ))) ); // A two doc block source file. This also tests references in one block to a @@ -577,7 +590,7 @@ fn test_source_to_codechat_for_web_1() { false, false, ), - TranslationResults::CodeChat(build_codechat_for_web( + Ok(TranslationResults::CodeChat(build_codechat_for_web( "javascript", "\nlet a = 1;\n\n", vec![ @@ -590,7 +603,7 @@ fn test_source_to_codechat_for_web_1() { ), build_codemirror_doc_block(12, 13, "", "/*", "") ] - )) + ))) ); // Trigger special cases: @@ -600,7 +613,7 @@ fn test_source_to_codechat_for_web_1() { // * A doc block with no trailing newline at the end of the file. assert_eq!( source_to_codechat_for_web("//\n\n//\n\n//", &"cpp".to_string(), false, false), - TranslationResults::CodeChat(build_codechat_for_web( + Ok(TranslationResults::CodeChat(build_codechat_for_web( "c_cpp", "\n\n\n\n", vec![ @@ -608,11 +621,11 @@ fn test_source_to_codechat_for_web_1() { build_codemirror_doc_block(2, 3, "", "//", ""), build_codemirror_doc_block(4, 5, "", "//", "") ] - )) + ))) ); assert_eq!( source_to_codechat_for_web("// ~~~\n\n//\n\n//", &"cpp".to_string(), false, false), - TranslationResults::CodeChat(build_codechat_for_web( + Ok(TranslationResults::CodeChat(build_codechat_for_web( "c_cpp", "\n\n\n\n", vec![ @@ -620,34 +633,34 @@ fn test_source_to_codechat_for_web_1() { build_codemirror_doc_block(2, 3, "", "//", ""), build_codemirror_doc_block(4, 5, "", "//", "") ] - )) + ))) ); // Test Unicode characters in code. assert_eq!( source_to_codechat_for_web("; // Ο\n//", &"cpp".to_string(), false, false), - TranslationResults::CodeChat(build_codechat_for_web( + Ok(TranslationResults::CodeChat(build_codechat_for_web( "c_cpp", "; // Ο\n", vec![build_codemirror_doc_block(7, 8, "", "//", ""),] - )) + ))) ); // Test Unicode characters in strings. assert_eq!( source_to_codechat_for_web("\"Ο\";\n//", &"cpp".to_string(), false, false), - TranslationResults::CodeChat(build_codechat_for_web( + Ok(TranslationResults::CodeChat(build_codechat_for_web( "c_cpp", "\"Ο\";\n", vec![build_codemirror_doc_block(5, 6, "", "//", ""),] - )) + ))) ); // Test a fenced code block that's unterminated. See [fence // mending](#fence-mending). assert_eq!( source_to_codechat_for_web("/* ``` foo\n*/\n// Test", &"cpp".to_string(), false, false), - TranslationResults::CodeChat(build_codechat_for_web( + Ok(TranslationResults::CodeChat(build_codechat_for_web( "c_cpp", "\n\n\n", vec![ @@ -660,7 +673,7 @@ fn test_source_to_codechat_for_web_1() { ), build_codemirror_doc_block(2, 3, "", "//", "Test
\n"), ] - )) + ))) ); // Test the other code fence character (the tilde). assert_eq!( @@ -670,7 +683,7 @@ fn test_source_to_codechat_for_web_1() { false, false ), - TranslationResults::CodeChat(build_codechat_for_web( + Ok(TranslationResults::CodeChat(build_codechat_for_web( "c_cpp", "\n\n\n", vec![ @@ -683,46 +696,46 @@ fn test_source_to_codechat_for_web_1() { ), build_codemirror_doc_block(2, 3, "", "//", "Test
\n"), ] - )) + ))) ); // Test multiple unterminated fenced code blocks. assert_eq!( source_to_codechat_for_web("// ```\n // ~~~", &"cpp".to_string(), false, false), - TranslationResults::CodeChat(build_codechat_for_web( + Ok(TranslationResults::CodeChat(build_codechat_for_web( "c_cpp", "\n\n", vec![ build_codemirror_doc_block(0, 1, "", "//", "\n\n"),
build_codemirror_doc_block(1, 2, " ", "//", "\n"),
]
- ))
+ )))
);
// Test an unterminated HTML block.
assert_eq!(
source_to_codechat_for_web("// Test
\n"), ] - )) + ))) ); // Test an unterminated `` block. Ensure that markdown after this is
// still parsed.
assert_eq!(
source_to_codechat_for_web("// \n // *Test*", &"cpp".to_string(), false, false),
- TranslationResults::CodeChat(build_codechat_for_web(
+ Ok(TranslationResults::CodeChat(build_codechat_for_web(
"c_cpp",
"\n\n",
vec![
build_codemirror_doc_block(0, 1, "", "//", "\n\n"),
build_codemirror_doc_block(1, 2, " ", "//", "Test
\n"),
]
- ))
+ )))
);
}
diff --git a/server/src/translation.rs b/server/src/translation.rs
index 6e399b74..ce6a17b4 100644
--- a/server/src/translation.rs
+++ b/server/src/translation.rs
@@ -214,10 +214,6 @@ use tokio::sync::mpsc::{Receiver, Sender};
use tokio::{fs::File, select, sync::mpsc};
// ### Local
-use crate::webserver::{
- EditorMessage, EditorMessageContents, ResultErrTypes, WebAppState, WebsocketQueues,
- send_response,
-};
use crate::{
oneshot_send,
processing::{
@@ -227,9 +223,11 @@ use crate::{
},
queue_send,
webserver::{
- INITIAL_MESSAGE_ID, MESSAGE_ID_INCREMENT, ProcessingTaskHttpRequest, ResultOkTypes,
- SimpleHttpResponse, SimpleHttpResponseError, SyncState, UpdateMessageContents,
- file_to_response, path_to_url, try_canonicalize, try_read_as_text, url_to_path,
+ EditorMessage, EditorMessageContents, INITIAL_MESSAGE_ID, MESSAGE_ID_INCREMENT,
+ ProcessingTaskHttpRequest, ResultErrTypes, ResultOkTypes, SimpleHttpResponse,
+ SimpleHttpResponseError, SyncState, UpdateMessageContents, WebAppState, WebsocketQueues,
+ file_to_response, path_to_url, send_response, try_canonicalize, try_read_as_text,
+ url_to_path,
},
};
@@ -618,94 +616,94 @@ pub async fn translation_task(
eol = find_eol_type(&code_mirror.doc);
let doc_normalized_eols = code_mirror.doc.replace("\r\n", "\n");
// Translate the file.
- let (translation_results_string, _path_to_toc) =
- source_to_codechat_for_web_string(&doc_normalized_eols, ¤t_file, false);
- match translation_results_string {
- TranslationResultsString::CodeChat(ccfw) => {
- // Send the new translated contents.
- debug!("Sending translated contents to Client.");
- let CodeMirrorDiffable::Plain(ref ccfw_source_plain) = ccfw.source else {
- error!("{}", "Unexpected diff value.");
- break;
- };
- // Send a diff if possible (only when the
- // Client's contents are synced with the
- // IDE).
- let contents = Some(
- if let Some(cmdb) = code_mirror_doc_blocks &&
- sync_state == SyncState::InSync {
- let doc_diff = diff_str(&code_mirror_doc, &ccfw_source_plain.doc);
- let code_mirror_diff = diff_code_mirror_doc_blocks(&cmdb, &ccfw_source_plain.doc_blocks);
- CodeChatForWeb {
- // Clone needed here, so we can copy it
- // later.
- metadata: ccfw.metadata.clone(),
- source: CodeMirrorDiffable::Diff(CodeMirrorDiff {
- doc: doc_diff,
- doc_blocks: code_mirror_diff
- })
+ match source_to_codechat_for_web_string(&doc_normalized_eols, ¤t_file, false) {
+ Err(err) => Err(ResultErrTypes::CannotTranslateSource(err.to_string())),
+ Ok((translation_results_string, _path_to_toc)) => match translation_results_string {
+ TranslationResultsString::CodeChat(ccfw) => {
+ // Send the new translated contents.
+ debug!("Sending translated contents to Client.");
+ let CodeMirrorDiffable::Plain(ref ccfw_source_plain) = ccfw.source else {
+ error!("{}", "Unexpected diff value.");
+ break;
+ };
+ // Send a diff if possible (only when the
+ // Client's contents are synced with the
+ // IDE).
+ let contents = Some(
+ if let Some(cmdb) = code_mirror_doc_blocks &&
+ sync_state == SyncState::InSync {
+ let doc_diff = diff_str(&code_mirror_doc, &ccfw_source_plain.doc);
+ let code_mirror_diff = diff_code_mirror_doc_blocks(&cmdb, &ccfw_source_plain.doc_blocks);
+ CodeChatForWeb {
+ // Clone needed here, so we can copy it
+ // later.
+ metadata: ccfw.metadata.clone(),
+ source: CodeMirrorDiffable::Diff(CodeMirrorDiff {
+ doc: doc_diff,
+ doc_blocks: code_mirror_diff
+ })
+ }
+ } else {
+ // We must make a clone to put in the TX
+ // queue; this allows us to keep the
+ // original below to use with the next
+ // diff.
+ ccfw.clone()
}
- } else {
- // We must make a clone to put in the TX
- // queue; this allows us to keep the
- // original below to use with the next
- // diff.
- ccfw.clone()
- }
- );
- queue_send!(to_client_tx.send(EditorMessage {
- id: ide_message.id,
- message: EditorMessageContents::Update(UpdateMessageContents {
- file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(),
- contents,
- cursor_position: update.cursor_position,
- scroll_position: update.scroll_position,
- }),
- }));
- // Update to the latest code after
- // computing diffs. To avoid ownership
- // problems, re-define `ccfw_source_plain`.
- let CodeMirrorDiffable::Plain(ccfw_source_plain) = ccfw.source else {
- error!("{}", "Unexpected diff value.");
- break;
- };
- source_code = code_mirror.doc;
- code_mirror_doc = ccfw_source_plain.doc;
- code_mirror_doc_blocks = Some(ccfw_source_plain.doc_blocks);
- // Mark the Client as unsynced until this
- // is acknowledged.
- sync_state = SyncState::Pending(ide_message.id);
- Ok(ResultOkTypes::Void)
- }
- // TODO
- TranslationResultsString::Binary => Err(ResultErrTypes::TodoBinarySupport),
- TranslationResultsString::Err(err) => Err(ResultErrTypes::CannotTranslateSource(err)),
- TranslationResultsString::Unknown => {
- // Send the new raw contents.
- debug!("Sending translated contents to Client.");
- queue_send!(to_client_tx.send(EditorMessage {
- id: ide_message.id,
- message: EditorMessageContents::Update(UpdateMessageContents {
- file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(),
- contents: Some(CodeChatForWeb {
- metadata: SourceFileMetadata {
- // Since this is raw data, `mode` doesn't
- // matter.
- mode: "".to_string(),
- },
- source: CodeMirrorDiffable::Plain(CodeMirror {
- doc: code_mirror.doc,
- doc_blocks: vec![]
- })
+ );
+ queue_send!(to_client_tx.send(EditorMessage {
+ id: ide_message.id,
+ message: EditorMessageContents::Update(UpdateMessageContents {
+ file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(),
+ contents,
+ cursor_position: update.cursor_position,
+ scroll_position: update.scroll_position,
+ }),
+ }));
+ // Update to the latest code after
+ // computing diffs. To avoid ownership
+ // problems, re-define `ccfw_source_plain`.
+ let CodeMirrorDiffable::Plain(ccfw_source_plain) = ccfw.source else {
+ error!("{}", "Unexpected diff value.");
+ break;
+ };
+ source_code = code_mirror.doc;
+ code_mirror_doc = ccfw_source_plain.doc;
+ code_mirror_doc_blocks = Some(ccfw_source_plain.doc_blocks);
+ // Mark the Client as unsynced until this
+ // is acknowledged.
+ sync_state = SyncState::Pending(ide_message.id);
+ Ok(ResultOkTypes::Void)
+ }
+ // TODO
+ TranslationResultsString::Binary => Err(ResultErrTypes::TodoBinarySupport),
+ TranslationResultsString::Unknown => {
+ // Send the new raw contents.
+ debug!("Sending translated contents to Client.");
+ queue_send!(to_client_tx.send(EditorMessage {
+ id: ide_message.id,
+ message: EditorMessageContents::Update(UpdateMessageContents {
+ file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(),
+ contents: Some(CodeChatForWeb {
+ metadata: SourceFileMetadata {
+ // Since this is raw data, `mode` doesn't
+ // matter.
+ mode: "".to_string(),
+ },
+ source: CodeMirrorDiffable::Plain(CodeMirror {
+ doc: code_mirror.doc,
+ doc_blocks: vec![]
+ })
+ }),
+ cursor_position: update.cursor_position,
+ scroll_position: update.scroll_position,
}),
- cursor_position: update.cursor_position,
- scroll_position: update.scroll_position,
- }),
- }));
- Ok(ResultOkTypes::Void)
- },
- TranslationResultsString::Toc(_) => {
- Err(ResultErrTypes::NotToc)
+ }));
+ Ok(ResultOkTypes::Void)
+ },
+ TranslationResultsString::Toc(_) => {
+ Err(ResultErrTypes::NotToc)
+ }
}
}
}
@@ -860,7 +858,7 @@ pub async fn translation_task(
ccfw
},
Err(message) => {
- let err = ResultErrTypes::CannotTranslateCodeChat(message);
+ let err = ResultErrTypes::CannotTranslateCodeChat(message.to_string());
error!("{err:?}");
send_response(&to_client_tx, client_message.id, Err(err)).await;
continue;
diff --git a/server/src/webserver.rs b/server/src/webserver.rs
index 1e6db907..e5599a6c 100644
--- a/server/src/webserver.rs
+++ b/server/src/webserver.rs
@@ -77,14 +77,20 @@ use url::Url;
// ### Local
//use crate::capture::EventCapture;
-use crate::ide::filewatcher::{
- filewatcher_browser_endpoint, filewatcher_client_endpoint, filewatcher_root_fs_redirect,
- filewatcher_websocket,
-};
-use crate::ide::vscode::vscode_ide_websocket;
-use crate::ide::vscode::{serve_vscode_fs, vscode_client_framework, vscode_client_websocket};
-use crate::processing::{
- CodeChatForWeb, TranslationResultsString, find_path_to_toc, source_to_codechat_for_web_string,
+use crate::{
+ ide::{
+ filewatcher::{
+ filewatcher_browser_endpoint, filewatcher_client_endpoint,
+ filewatcher_root_fs_redirect, filewatcher_websocket,
+ },
+ vscode::{
+ serve_vscode_fs, vscode_client_framework, vscode_client_websocket, vscode_ide_websocket,
+ },
+ },
+ processing::{
+ CodeChatForWeb, SourceToCodeChatForWebError, TranslationResultsString, find_path_to_toc,
+ source_to_codechat_for_web_string,
+ },
};
// Data structures
@@ -157,7 +163,7 @@ pub enum SimpleHttpResponseError {
#[error("Bundled file {0} not found.")]
BundledFileNotFound(String),
#[error("Lexer error: {0}.")]
- LexerError(String),
+ LexerError(#[from] SourceToCodeChatForWebError),
}
/// Define the data structure used to pass data between the CodeChat Editor
@@ -826,8 +832,7 @@ pub async fn file_to_response(
// `try_canonical`.
let is_current_file = file_path == current_filepath;
let is_toc = http_request.flags == ProcessingTaskHttpRequestFlags::Toc;
- let (translation_results_string, path_to_toc) = if let Some(file_contents_text) = file_contents
- {
+ let translation_results = if let Some(file_contents_text) = file_contents {
if is_current_file || is_toc {
source_to_codechat_for_web_string(
// Ensure we work with Unix-style (LF only) files, since other
@@ -838,13 +843,23 @@ pub async fn file_to_response(
)
} else {
// If this isn't the current file, then don't parse it.
- (TranslationResultsString::Unknown, None)
+ Ok((TranslationResultsString::Unknown, None))
}
} else {
- (
+ Ok((
TranslationResultsString::Binary,
find_path_to_toc(file_path),
- )
+ ))
+ };
+ let (translation_results_string, path_to_toc) = match translation_results {
+ // Report a lexer error.
+ Err(err) => {
+ return (
+ SimpleHttpResponse::Err(SimpleHttpResponseError::LexerError(err)),
+ None,
+ );
+ }
+ Ok(tr) => tr,
};
let is_project = path_to_toc.is_some();
// For project files, add in the sidebar. Convert this from a Windows path
@@ -914,10 +929,6 @@ pub async fn file_to_response(
None,
);
}
- // Report a lexer error.
- TranslationResultsString::Err(err_string) => {
- return (SimpleHttpResponse::Err(SimpleHttpResponseError::LexerError(err_string)), None);
- }
// This is a CodeChat file. The following code wraps the CodeChat for
// web results in a CodeChat Editor Client webpage.
TranslationResultsString::CodeChat(codechat_for_web) => codechat_for_web,
diff --git a/server/src/webserver/tests.rs b/server/src/webserver/tests.rs
index 174f0fc3..2cd3a034 100644
--- a/server/src/webserver/tests.rs
+++ b/server/src/webserver/tests.rs
@@ -17,15 +17,18 @@
/// ================================================
// Imports
// -------
+// ### Standard library
use std::{
path::{MAIN_SEPARATOR_STR, PathBuf},
thread::sleep,
time::Duration,
};
+// ### Third-party
use assert_cmd::Command;
use assertables::{assert_ends_with, assert_not_contains, assert_starts_with};
+// ### Local
use super::{path_to_url, url_to_path};
use crate::prep_test_dir;
use crate::{
From da27047b60554882039426b6b0f195f510e79d64 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Mon, 24 Nov 2025 07:38:44 -0600
Subject: [PATCH 13/38] Feat: rewrite sync system to use versions instead of
sync status.
---
client/src/CodeChatEditor.mts | 1 +
client/src/CodeChatEditorFramework.mts | 17 ++++
extensions/VSCode/src/extension.ts | 27 +++++-
extensions/VSCode/src/lib.rs | 4 +-
server/src/ide.rs | 7 +-
server/src/ide/filewatcher.rs | 21 ++++-
server/src/ide/vscode/tests.rs | 33 ++++++-
server/src/processing.rs | 27 ++++--
server/src/processing/tests.rs | 47 +++++++---
server/src/translation.rs | 91 ++++++++++---------
server/src/webserver.rs | 7 +-
.../overall/overall_core/test_server/test.md | 4 +-
server/tests/overall_core/mod.rs | 89 +++++++++++++-----
13 files changed, 266 insertions(+), 109 deletions(-)
diff --git a/client/src/CodeChatEditor.mts b/client/src/CodeChatEditor.mts
index 504c5803..c220b7ca 100644
--- a/client/src/CodeChatEditor.mts
+++ b/client/src/CodeChatEditor.mts
@@ -348,6 +348,7 @@ const save_lp = (is_dirty: boolean) => {
update.contents = {
metadata: current_metadata,
source: code_mirror_diffable,
+ version: Math.random(),
};
}
diff --git a/client/src/CodeChatEditorFramework.mts b/client/src/CodeChatEditorFramework.mts
index c3015f75..a202b39c 100644
--- a/client/src/CodeChatEditorFramework.mts
+++ b/client/src/CodeChatEditorFramework.mts
@@ -81,6 +81,10 @@ class WebSocketComm {
// IDE and passed back to it, but not otherwise used by the Framework.
current_filename: string | undefined = undefined;
+ // The version number of the current file. This default value will be overwritten when
+ // the first `Update` is sent.
+ version = 0.0;
+
// True when the iframe is loading, so that an `Update` should be postponed
// until the page load is finished. Otherwise, the page is fully loaded, so
// the `Update` may be applied immediately.
@@ -160,6 +164,17 @@ class WebSocketComm {
const contents = current_update.contents;
const cursor_position = current_update.cursor_position;
if (contents !== undefined) {
+ // Check and update the version. If this is a diff, ensure the diff was made against the version of the file we have.
+ if ("Diff" in contents.source) {
+ if (
+ contents.source.Diff.version !==
+ this.version
+ ) {
+ this.send_result(id, "OutOfSync");
+ return;
+ }
+ }
+ this.version = contents.version;
// I'd prefer to use a system-maintained value to
// determine the ready state of the iframe, such as
// [readyState](https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState).
@@ -313,6 +328,8 @@ class WebSocketComm {
if (typeof message == "object" && "Update" in message) {
assert(this.current_filename !== undefined);
message.Update.file_path = this.current_filename!;
+ // Update the version of this file if it's provided.
+ this.version = message.Update.contents?.version ?? this.version;
}
console_log(
`CodeChat Editor Client: sent message ${id}, ${format_struct(message)}`,
diff --git a/extensions/VSCode/src/extension.ts b/extensions/VSCode/src/extension.ts
index 4ae3ea93..8d59f9d0 100644
--- a/extensions/VSCode/src/extension.ts
+++ b/extensions/VSCode/src/extension.ts
@@ -93,6 +93,8 @@ let quiet_next_error = false;
// True if the editor contents have changed (are dirty) from the perspective of
// the CodeChat Editor (not if the contents are saved to disk).
let is_dirty = false;
+// The version of the current file.
+let version = 0.0;
// An object to start/stop the CodeChat Editor Server.
let codeChatEditorServer: CodeChatEditorServer | undefined;
@@ -353,6 +355,16 @@ export const activate = (context: vscode.ExtensionContext) => {
);
} else {
assert("Diff" in source);
+ // If this diff was not made against the text we currently have, reject it.
+ if (source.Diff.version !== version) {
+ sendResult(
+ id,
+ "Out of sync: incorrect version for diff.",
+ );
+ // Send an `Update` with the full text to re-sync the Client.
+ send_update(true);
+ break;
+ }
const diffs = source.Diff.doc;
for (const diff of diffs) {
// Convert from character offsets from the
@@ -384,6 +396,8 @@ export const activate = (context: vscode.ExtensionContext) => {
() =>
(ignore_text_document_change = false),
);
+ // Now that we've updated our text, update the associated version as well.
+ version = current_update.contents.version;
}
// Update the cursor and scroll position if
@@ -504,8 +518,13 @@ export const activate = (context: vscode.ExtensionContext) => {
// Look through all open documents to see if we have
// the requested file.
const doc = get_document(load_file);
- const load_file_result =
- doc === undefined ? null : doc.getText();
+ const load_file_result: null | [string, number] =
+ doc === undefined
+ ? null
+ : [
+ doc.getText(),
+ (version = Math.random()),
+ ];
console_log(
`CodeChat Editor extension: Result(LoadFile(${format_struct(load_file_result)}))`,
);
@@ -614,8 +633,8 @@ const send_update = (this_is_dirty: boolean) => {
const scroll_position = ate.visibleRanges[0].start.line + 1;
const file_path = ate.document.fileName;
// Send contents only if necessary.
- const option_contents = is_dirty
- ? ate.document.getText()
+ const option_contents: null | [string, number] = is_dirty
+ ? [ate.document.getText(), (version = Math.random())]
: null;
is_dirty = false;
console_log(
diff --git a/extensions/VSCode/src/lib.rs b/extensions/VSCode/src/lib.rs
index c837e6d6..aedeed8c 100644
--- a/extensions/VSCode/src/lib.rs
+++ b/extensions/VSCode/src/lib.rs
@@ -86,7 +86,7 @@ impl CodeChatEditorServer {
&self,
file_path: String,
// `null` to send no source code; a string to send the source code.
- option_contents: Option,
+ option_contents: Option<(String, f64)>,
cursor_position: Option,
scroll_position: Option,
) -> std::io::Result {
@@ -108,7 +108,7 @@ impl CodeChatEditorServer {
pub async fn send_result_loadfile(
&self,
id: f64,
- load_file: Option,
+ load_file: Option<(String, f64)>,
) -> std::io::Result<()> {
self.0.send_result_loadfile(id, load_file).await
}
diff --git a/server/src/ide.rs b/server/src/ide.rs
index 49c576f8..b9ef2b08 100644
--- a/server/src/ide.rs
+++ b/server/src/ide.rs
@@ -251,7 +251,7 @@ impl CodeChatEditorServer {
&self,
file_path: String,
// `null` to send no source code; a string to send the source code.
- option_contents: Option,
+ option_contents: Option<(String, f64)>,
cursor_position: Option,
scroll_position: Option,
) -> std::io::Result {
@@ -262,9 +262,10 @@ impl CodeChatEditorServer {
mode: "".to_string(),
},
source: CodeMirrorDiffable::Plain(CodeMirror {
- doc: contents,
+ doc: contents.0,
doc_blocks: vec![],
}),
+ version: contents.1,
}),
cursor_position,
scroll_position: scroll_position.map(|x| x as f32),
@@ -294,7 +295,7 @@ impl CodeChatEditorServer {
pub async fn send_result_loadfile(
&self,
id: f64,
- load_file: Option,
+ load_file: Option<(String, f64)>,
) -> std::io::Result<()> {
self.send_message_raw(EditorMessage {
id,
diff --git a/server/src/ide/filewatcher.rs b/server/src/ide/filewatcher.rs
index 58527461..7074a589 100644
--- a/server/src/ide/filewatcher.rs
+++ b/server/src/ide/filewatcher.rs
@@ -40,6 +40,7 @@ use notify_debouncer_full::{
DebounceEventResult, new_debouncer,
notify::{EventKind, RecursiveMode},
};
+use rand::random;
use regex::Regex;
use tokio::{
fs::DirEntry,
@@ -534,7 +535,9 @@ async fn processing_task(
source: crate::processing::CodeMirrorDiffable::Plain(CodeMirror {
doc: file_contents,
doc_blocks: vec![],
- })
+ }),
+ // The filewatcher doesn't store a version, since it only accepts plain (non-diff) results. Provide a version so the Client stays in sync with any diffs.
+ version: random(),
}),
cursor_position: None,
scroll_position: None,
@@ -845,7 +848,13 @@ mod tests {
send_response(&from_client_tx, id, Ok(ResultOkTypes::Void)).await;
// Check the contents.
- let translation_results = source_to_codechat_for_web("", &"py".to_string(), false, false);
+ let translation_results = source_to_codechat_for_web(
+ "",
+ &"py".to_string(),
+ umc.contents.as_ref().unwrap().version,
+ false,
+ false,
+ );
let codechat_for_web = cast!(cast!(translation_results, Ok), TranslationResults::CodeChat);
assert_eq!(umc.contents, Some(codechat_for_web));
@@ -961,6 +970,7 @@ mod tests {
doc: "".to_string(),
doc_blocks: vec![],
}),
+ version: 0.0,
}),
cursor_position: None,
scroll_position: None,
@@ -990,6 +1000,7 @@ mod tests {
doc: "testing".to_string(),
doc_blocks: vec![],
}),
+ version: 1.0,
}),
cursor_position: None,
scroll_position: None,
@@ -1022,6 +1033,7 @@ mod tests {
doc: "testing()".to_string(),
doc_blocks: vec![],
}),
+ version: 2.0,
}),
cursor_position: None,
scroll_position: None,
@@ -1048,8 +1060,10 @@ mod tests {
fs::write(&file_path, s).unwrap();
// Wait for the filewatcher to debounce this file write.
sleep(Duration::from_secs(2)).await;
+ // The version is random; don't check it with a fixed value.
+ let msg = get_message_as!(to_client_rx, EditorMessageContents::Update);
assert_eq!(
- get_message_as!(to_client_rx, EditorMessageContents::Update),
+ msg,
(
INITIAL_IDE_MESSAGE_ID + MESSAGE_ID_INCREMENT,
UpdateMessageContents {
@@ -1062,6 +1076,7 @@ mod tests {
doc: "testing()123".to_string(),
doc_blocks: vec![],
}),
+ version: msg.1.contents.as_ref().unwrap().version,
}),
cursor_position: None,
scroll_position: None,
diff --git a/server/src/ide/vscode/tests.rs b/server/src/ide/vscode/tests.rs
index b80e3f14..63178391 100644
--- a/server/src/ide/vscode/tests.rs
+++ b/server/src/ide/vscode/tests.rs
@@ -516,9 +516,10 @@ async fn test_vscode_ide_websocket8() {
&mut ws_ide,
&EditorMessage {
id: INITIAL_MESSAGE_ID + MESSAGE_ID_INCREMENT,
- message: EditorMessageContents::Result(Ok(ResultOkTypes::LoadFile(Some(
+ message: EditorMessageContents::Result(Ok(ResultOkTypes::LoadFile(Some((
"# testing".to_string(),
- )))),
+ 0.0,
+ ))))),
},
)
.await;
@@ -547,6 +548,7 @@ async fn test_vscode_ide_websocket8() {
contents: "testing
\n".to_string()
}],
}),
+ version: 0.0,
}),
cursor_position: None,
scroll_position: None,
@@ -648,6 +650,7 @@ async fn test_vscode_ide_websocket7() {
doc: "# more".to_string(),
doc_blocks: vec![],
}),
+ version: 0.0,
}),
cursor_position: None,
scroll_position: None,
@@ -674,7 +677,8 @@ async fn test_vscode_ide_websocket7() {
delimiter: "#".to_string(),
contents: "more
\n".to_string()
}]
- })
+ }),
+ version: 0.0,
}),
cursor_position: None,
scroll_position: None,
@@ -720,6 +724,7 @@ async fn test_vscode_ide_websocket7() {
.to_string(),
doc_blocks: vec![],
}),
+ version: 1.0,
}),
cursor_position: None,
scroll_position: None,
@@ -749,8 +754,10 @@ async fn test_vscode_ide_websocket7() {
indent: "".to_string(),
delimiter: "#".to_string(),
contents: "most
\n".to_string()
- })]
+ })],
+ version: 0.0,
}),
+ version: 1.0,
}),
cursor_position: None,
scroll_position: None,
@@ -807,6 +814,7 @@ async fn test_vscode_ide_websocket6() {
contents: "less\n".to_string(),
}],
}),
+ version: 0.0,
}),
cursor_position: None,
scroll_position: None,
@@ -828,6 +836,7 @@ async fn test_vscode_ide_websocket6() {
doc: "# less\n".to_string(),
doc_blocks: vec![],
}),
+ version: 0.0,
}),
cursor_position: None,
scroll_position: None,
@@ -946,8 +955,11 @@ async fn test_vscode_ide_websocket4() {
// This should also produce an `Update` message sent from the Server.
//
// Message ids: IDE - 0, Server - 2->3, Client - 0.
+ //
+ // Since the version is randomly generated, copy that from the received message.
+ let msg = read_message(&mut ws_client).await;
assert_eq!(
- read_message(&mut ws_client).await,
+ msg,
EditorMessage {
id: INITIAL_MESSAGE_ID + 2.0 * MESSAGE_ID_INCREMENT,
message: EditorMessageContents::Update(UpdateMessageContents {
@@ -966,6 +978,11 @@ async fn test_vscode_ide_websocket4() {
contents: "test.py
\n".to_string()
}],
}),
+ version: cast!(&msg.message, EditorMessageContents::Update)
+ .contents
+ .as_ref()
+ .unwrap()
+ .version,
}),
cursor_position: None,
scroll_position: None,
@@ -1025,6 +1042,8 @@ async fn test_vscode_ide_websocket4() {
.await;
join_handle.join().unwrap();
+ // What makes sense here? If the IDE didn't load the file, either the Client shouldn't edit it or the Client should switch to using a filewatcher for edits.
+ /*
// Send an update from the Client, which should produce a diff.
//
// Message ids: IDE - 0, Server - 4, Client - 0->1.
@@ -1048,6 +1067,7 @@ async fn test_vscode_ide_websocket4() {
contents: "test.py
".to_string(),
}],
}),
+ version: 1.0,
}),
cursor_position: None,
scroll_position: None,
@@ -1072,7 +1092,9 @@ async fn test_vscode_ide_websocket4() {
insert: format!("More{}", if cfg!(windows) { "\r\n" } else { "\n" }),
}],
doc_blocks: vec![],
+ version: 0.0,
}),
+ version: 1.0,
}),
cursor_position: None,
scroll_position: None,
@@ -1094,6 +1116,7 @@ async fn test_vscode_ide_websocket4() {
message: EditorMessageContents::Result(Ok(ResultOkTypes::Void))
}
);
+ */
check_logger_errors(0);
// Report any errors produced when removing the temporary directory.
diff --git a/server/src/processing.rs b/server/src/processing.rs
index 76d3d2b7..4b69ec70 100644
--- a/server/src/processing.rs
+++ b/server/src/processing.rs
@@ -84,6 +84,8 @@ use crate::lexer::{CodeDocBlock, DocBlock, LEXERS, LanguageLexerCompiled, source
pub struct CodeChatForWeb {
pub metadata: SourceFileMetadata,
pub source: CodeMirrorDiffable,
+ /// The version number after accepting this update.
+ pub version: f64,
}
/// Provide two options for sending CodeMirror data -- as the full contents
@@ -123,6 +125,8 @@ pub struct CodeMirrorDiff {
/// A diff of the document being edited.
pub doc: Vec,
pub doc_blocks: Vec,
+ /// The version number from which this diff was produced.
+ pub version: f64,
}
/// A transaction produced by the diff of the `CodeMirror` struct.
@@ -762,6 +766,8 @@ pub fn source_to_codechat_for_web(
file_contents: &str,
// The file's extension.
file_ext: &String,
+ // The version of this file.
+ version: f64,
// True if this file is a TOC.
_is_toc: bool,
// True if this file is part of a project.
@@ -795,6 +801,7 @@ pub fn source_to_codechat_for_web(
metadata: SourceFileMetadata {
mode: lexer.language_lexer.lexer_name.to_string(),
},
+ version,
source: if lexer.language_lexer.lexer_name.as_str() == "markdown" {
// Document-only files are easy: just encode the contents.
let html = markdown_to_html(file_contents);
@@ -900,6 +907,8 @@ pub fn source_to_codechat_for_web_string(
file_contents: &str,
// The path to this file.
file_path: &Path,
+ // The version to assign to this file.
+ version: f64,
// True if this file is a TOC.
is_toc: bool,
) -> Result<
@@ -924,7 +933,13 @@ pub fn source_to_codechat_for_web_string(
let is_project = path_to_toc.is_some();
Ok((
- match source_to_codechat_for_web(file_contents, &ext.to_string(), is_toc, is_project) {
+ match source_to_codechat_for_web(
+ file_contents,
+ &ext.to_string(),
+ version,
+ is_toc,
+ is_project,
+ ) {
Err(err) => return Err(err),
Ok(translation_results) => match translation_results {
TranslationResults::CodeChat(codechat_for_web) => {
@@ -964,11 +979,11 @@ fn markdown_to_html(markdown: &str) -> String {
// ### Diff support
//
// This section provides methods to diff the previous and current
-// `CodeMirrorDocBlockVec`.Β The primary purpose is to fix a visual bug: if the
+// `CodeMirrorDocBlockVec`. The primary purpose is to fix a visual bug: if the
// entire CodeMirror data structure is overwritten, then CodeMirror loses track
// of the correct vertical scroll bar position, probably because it has build up
// information on the size of each rendered doc block; these correct sizes are
-// reset when all data is overrwritten, causing unexpected scrolling. Therefore,
+// reset when all data is overwritten, causing unexpected scrolling. Therefore,
// this approach is to modify only what changed, rather than changing
// everything. As a secondary goal, this hopefully improves overall performance
// by sending less data between the server and the client, in spite of the
@@ -998,11 +1013,11 @@ fn markdown_to_html(markdown: &str) -> String {
// 1. Use the diff algorithm to find the minimal change set between a before and
// after `CodeMirrorDocBlocksVec`, which only looks at the `contents`. This
// avoids "noise" from changes in from/to fields from obscuring changes only
-// to theΒ `contents`.
-// 2. For all before and after blocks whoseΒ `contents` were identical, compare
+// to the `contents`.
+// 2. For all before and after blocks whose `contents` were identical, compare
// the other fields, adding these to the change set, but not attempting to
// use the diff algorithm.
-// 3. Represent changes to theΒ `contents` as a `StringDiff`.
+// 3. Represent changes to the `contents` as a `StringDiff`.
//
// #### String diff
/// Given two strings, return a list of changes between them.
diff --git a/server/src/processing/tests.rs b/server/src/processing/tests.rs
index f3be7fa1..cda3396a 100644
--- a/server/src/processing/tests.rs
+++ b/server/src/processing/tests.rs
@@ -62,6 +62,7 @@ fn build_codechat_for_web(
doc: doc.to_string(),
doc_blocks,
}),
+ version: 0.0,
}
}
@@ -485,7 +486,7 @@ fn test_source_to_codechat_for_web_1() {
// A file with an unknown extension and no lexer, which is classified as a
// text file.
assert_eq!(
- source_to_codechat_for_web("", &".xxx".to_string(), false, false),
+ source_to_codechat_for_web("", &".xxx".to_string(), 0.0, false, false),
Ok(TranslationResults::Unknown)
);
@@ -496,6 +497,7 @@ fn test_source_to_codechat_for_web_1() {
source_to_codechat_for_web(
&format!("{lexer_spec}unknown"),
&".xxx".to_string(),
+ 0.0,
false,
false,
),
@@ -506,7 +508,7 @@ fn test_source_to_codechat_for_web_1() {
// A CodeChat Editor document via filename.
assert_eq!(
- source_to_codechat_for_web("", &"md".to_string(), false, false),
+ source_to_codechat_for_web("", &"md".to_string(), 0.0, false, false),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
"markdown",
"",
@@ -519,6 +521,7 @@ fn test_source_to_codechat_for_web_1() {
source_to_codechat_for_web(
&format!("{lexer_spec}markdown"),
&"xxx".to_string(),
+ 0.0,
false,
false,
),
@@ -531,7 +534,7 @@ fn test_source_to_codechat_for_web_1() {
// An empty source file.
assert_eq!(
- source_to_codechat_for_web("", &"js".to_string(), false, false),
+ source_to_codechat_for_web("", &"js".to_string(), 0.0, false, false),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
"javascript",
"",
@@ -541,7 +544,7 @@ fn test_source_to_codechat_for_web_1() {
// A zero doc block source file.
assert_eq!(
- source_to_codechat_for_web("let a = 1;", &"js".to_string(), false, false),
+ source_to_codechat_for_web("let a = 1;", &"js".to_string(), 0.0, false, false),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
"javascript",
"let a = 1;",
@@ -551,7 +554,7 @@ fn test_source_to_codechat_for_web_1() {
// One doc block source files.
assert_eq!(
- source_to_codechat_for_web("// Test", &"js".to_string(), false, false),
+ source_to_codechat_for_web("// Test", &"js".to_string(), 0.0, false, false),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
"javascript",
"\n",
@@ -559,7 +562,7 @@ fn test_source_to_codechat_for_web_1() {
)))
);
assert_eq!(
- source_to_codechat_for_web("let a = 1;\n// Test", &"js".to_string(), false, false,),
+ source_to_codechat_for_web("let a = 1;\n// Test", &"js".to_string(), 0.0, false, false,),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
"javascript",
"let a = 1;\n\n",
@@ -573,7 +576,7 @@ fn test_source_to_codechat_for_web_1() {
)))
);
assert_eq!(
- source_to_codechat_for_web("// Test\nlet a = 1;", &"js".to_string(), false, false,),
+ source_to_codechat_for_web("// Test\nlet a = 1;", &"js".to_string(), 0.0, false, false,),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
"javascript",
"\nlet a = 1;",
@@ -587,6 +590,7 @@ fn test_source_to_codechat_for_web_1() {
source_to_codechat_for_web(
"// [Link][1]\nlet a = 1;\n/* [1]: http://b.org */",
&"js".to_string(),
+ 0.0,
false,
false,
),
@@ -612,7 +616,7 @@ fn test_source_to_codechat_for_web_1() {
// * A doc block in the middle of the file
// * A doc block with no trailing newline at the end of the file.
assert_eq!(
- source_to_codechat_for_web("//\n\n//\n\n//", &"cpp".to_string(), false, false),
+ source_to_codechat_for_web("//\n\n//\n\n//", &"cpp".to_string(), 0.0, false, false),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
"c_cpp",
"\n\n\n\n",
@@ -624,7 +628,7 @@ fn test_source_to_codechat_for_web_1() {
)))
);
assert_eq!(
- source_to_codechat_for_web("// ~~~\n\n//\n\n//", &"cpp".to_string(), false, false),
+ source_to_codechat_for_web("// ~~~\n\n//\n\n//", &"cpp".to_string(), 0.0, false, false),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
"c_cpp",
"\n\n\n\n",
@@ -638,7 +642,7 @@ fn test_source_to_codechat_for_web_1() {
// Test Unicode characters in code.
assert_eq!(
- source_to_codechat_for_web("; // Ο\n//", &"cpp".to_string(), false, false),
+ source_to_codechat_for_web("; // Ο\n//", &"cpp".to_string(), 0.0, false, false),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
"c_cpp",
"; // Ο\n",
@@ -648,7 +652,7 @@ fn test_source_to_codechat_for_web_1() {
// Test Unicode characters in strings.
assert_eq!(
- source_to_codechat_for_web("\"Ο\";\n//", &"cpp".to_string(), false, false),
+ source_to_codechat_for_web("\"Ο\";\n//", &"cpp".to_string(), 0.0, false, false),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
"c_cpp",
"\"Ο\";\n",
@@ -659,7 +663,13 @@ fn test_source_to_codechat_for_web_1() {
// Test a fenced code block that's unterminated. See [fence
// mending](#fence-mending).
assert_eq!(
- source_to_codechat_for_web("/* ``` foo\n*/\n// Test", &"cpp".to_string(), false, false),
+ source_to_codechat_for_web(
+ "/* ``` foo\n*/\n// Test",
+ &"cpp".to_string(),
+ 0.0,
+ false,
+ false
+ ),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
"c_cpp",
"\n\n\n",
@@ -680,6 +690,7 @@ fn test_source_to_codechat_for_web_1() {
source_to_codechat_for_web(
"/* ~~~~~~~ foo\n*/\n// Test",
&"cpp".to_string(),
+ 0.0,
false,
false
),
@@ -700,7 +711,7 @@ fn test_source_to_codechat_for_web_1() {
);
// Test multiple unterminated fenced code blocks.
assert_eq!(
- source_to_codechat_for_web("// ```\n // ~~~", &"cpp".to_string(), false, false),
+ source_to_codechat_for_web("// ```\n // ~~~", &"cpp".to_string(), 0.0, false, false),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
"c_cpp",
"\n\n",
@@ -713,7 +724,7 @@ fn test_source_to_codechat_for_web_1() {
// Test an unterminated HTML block.
assert_eq!(
- source_to_codechat_for_web("// \n // Test", &"cpp".to_string(), false, false),
+ source_to_codechat_for_web("// \n // Test", &"cpp".to_string(), 0.0, false, false),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
"c_cpp",
"\n\n",
@@ -727,7 +738,13 @@ fn test_source_to_codechat_for_web_1() {
// Test an unterminated `` block. Ensure that markdown after this is
// still parsed.
assert_eq!(
- source_to_codechat_for_web("// \n // *Test*", &"cpp".to_string(), false, false),
+ source_to_codechat_for_web(
+ "// \n // *Test*",
+ &"cpp".to_string(),
+ 0.0,
+ false,
+ false
+ ),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
"c_cpp",
"\n\n",
diff --git a/server/src/translation.rs b/server/src/translation.rs
index ce6a17b4..3eb82a13 100644
--- a/server/src/translation.rs
+++ b/server/src/translation.rs
@@ -225,7 +225,7 @@ use crate::{
webserver::{
EditorMessage, EditorMessageContents, INITIAL_MESSAGE_ID, MESSAGE_ID_INCREMENT,
ProcessingTaskHttpRequest, ResultErrTypes, ResultOkTypes, SimpleHttpResponse,
- SimpleHttpResponseError, SyncState, UpdateMessageContents, WebAppState, WebsocketQueues,
+ SimpleHttpResponseError, UpdateMessageContents, WebAppState, WebsocketQueues,
file_to_response, path_to_url, send_response, try_canonicalize, try_read_as_text,
url_to_path,
},
@@ -238,7 +238,7 @@ use crate::{
const MAX_MESSAGE_LENGTH: usize = 300;
lazy_static! {
- /// A regex to determine the type of the first EOL. See 'PROCESSINGS1.
+ /// A regex to determine the type of the first EOL. See 'PROCESSINGS`.
pub static ref EOL_FINDER: Regex = Regex::new("[^\r\n]*(\r?\n)").unwrap();
}
@@ -439,7 +439,10 @@ pub async fn translation_task(
// Server and Client to re-sync. When a file is first loaded, its
// version number is None, signaling that the sender must always
// provide the full text, not a diff.
- let mut sync_state = SyncState::OutOfSync;
+ let mut version = 0.0;
+ // Has the full (non-diff) version of the current file been sent?
+ // Don't send diffs until this is sent.
+ let mut sent_full = false;
loop {
select! {
// Look for messages from the IDE.
@@ -480,11 +483,9 @@ pub async fn translation_task(
// which the Server should handle).
if !is_loadfile {
debug!("Forwarding it to the Client.");
- // If this was confirmation from the IDE
- // that it received the latest update, then
- // mark the IDE as synced.
- if sync_state == SyncState::Pending(ide_message.id) {
- sync_state = SyncState::InSync;
+ // If the Server can't read our diff, send the full text next time.
+ if matches!(result, Err(ResultErrTypes::OutOfSync)) {
+ sent_full = false;
}
queue_send!(to_client_tx.send(ide_message));
continue;
@@ -521,11 +522,11 @@ pub async fn translation_task(
// number also -- "%PDF").
let use_pdf_js = http_request.file_path.extension() == Some(OsStr::new("pdf"));
let ((simple_http_response, option_update), file_contents) = match file_contents_option {
- Some(file_contents) => {
- // If there are Windows newlines, replace
- // with Unix; this is reversed when the
- // file is sent back to the IDE.
- (file_to_response(&http_request, ¤t_file, Some(&file_contents), use_pdf_js).await, file_contents)
+ Some((file_contents, new_version)) => {
+ version = new_version;
+ // The IDE just sent the full contents; we're sending full contents to the Client.
+ sent_full = true;
+ (file_to_response(&http_request, new_version, ¤t_file, Some(&file_contents), use_pdf_js).await, file_contents)
},
None => {
// The file wasn't available in the IDE.
@@ -545,6 +546,7 @@ pub async fn translation_task(
(
file_to_response(
&http_request,
+ version,
¤t_file,
option_file_contents.as_ref(),
use_pdf_js,
@@ -573,7 +575,6 @@ pub async fn translation_task(
// placed in the TX queue.
code_mirror_doc = plain.doc.clone();
code_mirror_doc_blocks = Some(plain.doc_blocks.clone());
- sync_state = SyncState::Pending(id);
debug!("Sending Update to Client, id = {id}.");
queue_send!(to_client_tx.send(EditorMessage {
@@ -616,7 +617,7 @@ pub async fn translation_task(
eol = find_eol_type(&code_mirror.doc);
let doc_normalized_eols = code_mirror.doc.replace("\r\n", "\n");
// Translate the file.
- match source_to_codechat_for_web_string(&doc_normalized_eols, ¤t_file, false) {
+ match source_to_codechat_for_web_string(&doc_normalized_eols, ¤t_file, contents.version, false) {
Err(err) => Err(ResultErrTypes::CannotTranslateSource(err.to_string())),
Ok((translation_results_string, _path_to_toc)) => match translation_results_string {
TranslationResultsString::CodeChat(ccfw) => {
@@ -626,12 +627,10 @@ pub async fn translation_task(
error!("{}", "Unexpected diff value.");
break;
};
- // Send a diff if possible (only when the
- // Client's contents are synced with the
- // IDE).
- let contents = Some(
+ // Send a diff if possible.
+ let client_contents = Some(
if let Some(cmdb) = code_mirror_doc_blocks &&
- sync_state == SyncState::InSync {
+ sent_full {
let doc_diff = diff_str(&code_mirror_doc, &ccfw_source_plain.doc);
let code_mirror_diff = diff_code_mirror_doc_blocks(&cmdb, &ccfw_source_plain.doc_blocks);
CodeChatForWeb {
@@ -640,10 +639,14 @@ pub async fn translation_task(
metadata: ccfw.metadata.clone(),
source: CodeMirrorDiffable::Diff(CodeMirrorDiff {
doc: doc_diff,
- doc_blocks: code_mirror_diff
- })
+ doc_blocks: code_mirror_diff,
+ // The diff was made between the current version (`version`) and the new version (`contents.version`).
+ version
+ }),
+ version: contents.version,
}
} else {
+ sent_full = true;
// We must make a clone to put in the TX
// queue; this allows us to keep the
// original below to use with the next
@@ -655,7 +658,7 @@ pub async fn translation_task(
id: ide_message.id,
message: EditorMessageContents::Update(UpdateMessageContents {
file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(),
- contents,
+ contents: client_contents,
cursor_position: update.cursor_position,
scroll_position: update.scroll_position,
}),
@@ -670,9 +673,8 @@ pub async fn translation_task(
source_code = code_mirror.doc;
code_mirror_doc = ccfw_source_plain.doc;
code_mirror_doc_blocks = Some(ccfw_source_plain.doc_blocks);
- // Mark the Client as unsynced until this
- // is acknowledged.
- sync_state = SyncState::Pending(ide_message.id);
+ // Update to the version of the file just sent.
+ version = contents.version;
Ok(ResultOkTypes::Void)
}
// TODO
@@ -693,7 +695,8 @@ pub async fn translation_task(
source: CodeMirrorDiffable::Plain(CodeMirror {
doc: code_mirror.doc,
doc_blocks: vec![]
- })
+ }),
+ version: contents.version
}),
cursor_position: update.cursor_position,
scroll_position: update.scroll_position,
@@ -735,8 +738,8 @@ pub async fn translation_task(
}));
current_file = file_path.into();
// Since this is a new file, mark it as
- // unsynced.
- sync_state = SyncState::OutOfSync;
+ // unsent in full.
+ sent_full = false;
}
Err(err) => {
error!("{err:?}");
@@ -776,14 +779,16 @@ pub async fn translation_task(
},
// Handle messages that are simply passed through.
- EditorMessageContents::Closed |
- EditorMessageContents::Result(_) => {
+ EditorMessageContents::Closed => {
+ debug!("Forwarding it to the IDE.");
+ queue_send!(to_ide_tx.send(client_message))
+ },
+
+ EditorMessageContents::Result(ref result) => {
debug!("Forwarding it to the IDE.");
- // If this result confirms that the Client
- // received the most recent IDE update, then
- // mark the documents as synced.
- if sync_state == SyncState::Pending(client_message.id) {
- sync_state = SyncState::InSync;
+ // If the Client can't read our diff, send the full text next time.
+ if matches!(result, Err(ResultErrTypes::OutOfSync)) {
+ sent_full = false;
}
queue_send!(to_ide_tx.send(client_message))
},
@@ -822,7 +827,7 @@ pub async fn translation_task(
// Correct EOL endings for use with the
// IDE.
let new_source_code_eol = eol_convert(new_source_code, &eol);
- let ccfw = if sync_state == SyncState::InSync && allow_source_diffs {
+ let ccfw = if sent_full && allow_source_diffs {
Some(CodeChatForWeb {
metadata: cfw.metadata,
source: CodeMirrorDiffable::Diff(CodeMirrorDiff {
@@ -831,7 +836,9 @@ pub async fn translation_task(
// are correct.
doc: diff_str(&source_code, &new_source_code_eol),
doc_blocks: vec![],
+ version,
}),
+ version: cfw.version,
})
} else {
Some(CodeChatForWeb {
@@ -842,8 +849,10 @@ pub async fn translation_task(
doc: new_source_code_eol.clone(),
doc_blocks: vec![],
}),
+ version: cfw.version,
})
};
+ version = cfw.version;
source_code = new_source_code_eol;
let CodeMirrorDiffable::Plain(cmd) = cfw.source else {
// TODO: support diffable!
@@ -874,9 +883,6 @@ pub async fn translation_task(
scroll_position: update_message_contents.scroll_position,
})
}));
- // Mark the IDE contents as out of sync
- // until this message is received.
- sync_state = SyncState::Pending(client_message.id);
}
}
},
@@ -904,9 +910,8 @@ pub async fn translation_task(
message: EditorMessageContents::CurrentFile(file_path_string.to_string(), Some(is_text))
}));
current_file = file_path;
- // Mark the IDE as out of sync, since this
- // is a new file.
- sync_state = SyncState::OutOfSync;
+ // Since this is a new file, the full text hasn't been sent yet.
+ sent_full = false;
Ok(())
}
}
diff --git a/server/src/webserver.rs b/server/src/webserver.rs
index e5599a6c..239ae2c5 100644
--- a/server/src/webserver.rs
+++ b/server/src/webserver.rs
@@ -247,9 +247,9 @@ type MessageResult = Result<
pub enum ResultOkTypes {
/// Most messages have no result.
Void,
- /// The `LoadFile` message provides file contents, if available. This
+ /// The `LoadFile` message provides file contents and a revision number, if available. This
/// message may only be sent from the IDE to the Server.
- LoadFile(Option),
+ LoadFile(Option<(String, f64)>),
}
#[derive(Debug, Serialize, Deserialize, TS, PartialEq, thiserror::Error)]
@@ -776,6 +776,8 @@ pub async fn try_read_as_text(file: &mut File) -> Option {
pub async fn file_to_response(
// The HTTP request presented to the processing task.
http_request: &ProcessingTaskHttpRequest,
+ // The version of this file.
+ version: f64,
// Path to the file currently being edited. This path should be cleaned by
// `try_canonicalize`.
current_filepath: &Path,
@@ -839,6 +841,7 @@ pub async fn file_to_response(
// line endings break the translation process.
&file_contents_text.replace("\r\n", "\n"),
file_path,
+ version,
is_toc,
)
} else {
diff --git a/server/tests/fixtures/overall/overall_core/test_server/test.md b/server/tests/fixtures/overall/overall_core/test_server/test.md
index 0a55de74..75c4c898 100644
--- a/server/tests/fixtures/overall/overall_core/test_server/test.md
+++ b/server/tests/fixtures/overall/overall_core/test_server/test.md
@@ -1 +1,3 @@
-A **markdown** file.
\ No newline at end of file
+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.
\ No newline at end of file
diff --git a/server/tests/overall_core/mod.rs b/server/tests/overall_core/mod.rs
index ac429bfc..e5ff21be 100644
--- a/server/tests/overall_core/mod.rs
+++ b/server/tests/overall_core/mod.rs
@@ -56,8 +56,8 @@ use std::{
collections::HashMap, env, error::Error, panic::AssertUnwindSafe, path::PathBuf, time::Duration,
};
-use assert_fs::TempDir;
// ### Third-party
+use assert_fs::TempDir;
use dunce::canonicalize;
use futures::FutureExt;
use pretty_assertions::assert_eq;
@@ -240,6 +240,15 @@ macro_rules! harness {
};
}
+// Given an `Update` message with contents, get the version.
+fn get_version(msg: &EditorMessage) -> f64 {
+ cast!(&msg.message, EditorMessageContents::Update)
+ .contents
+ .as_ref()
+ .unwrap()
+ .version
+}
+
// Tests
// -----
//
@@ -289,8 +298,9 @@ async fn test_server_core(
.await;
// Respond to the load request.
+ let mut version = 1.0;
codechat_server
- .send_result_loadfile(server_id, Some("# Test\ncode()".to_string()))
+ .send_result_loadfile(server_id, Some(("# Test\ncode()".to_string(), version)))
.await
.unwrap();
@@ -353,8 +363,11 @@ async fn test_server_core(
// Verify the updated text.
let mut client_id = INITIAL_CLIENT_MESSAGE_ID;
+ // Update the version from the value provided by the client, which varies randomly.
+ let msg = codechat_server.get_message_timeout(TIMEOUT).await.unwrap();
+ let client_version = get_version(&msg);
assert_eq!(
- codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
+ msg,
EditorMessage {
id: client_id,
message: EditorMessageContents::Update(UpdateMessageContents {
@@ -369,22 +382,27 @@ async fn test_server_core(
to: Some(7),
insert: "# Testfoo\n".to_string()
}],
- doc_blocks: vec![]
- })
+ doc_blocks: vec![],
+ version,
+ }),
+ version: client_version,
}),
cursor_position: Some(1),
scroll_position: Some(1.0)
})
}
);
+ version = client_version;
codechat_server.send_result(client_id, None).await.unwrap();
// Edit the indent. It should only allow spaces and tabs, rejecting other
// edits.
doc_block_indent.send_keys(" 123").await.unwrap();
+ let msg = codechat_server.get_message_timeout(TIMEOUT).await.unwrap();
+ let client_version = get_version(&msg);
client_id += MESSAGE_ID_INCREMENT;
assert_eq!(
- codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
+ msg,
EditorMessage {
id: client_id,
message: EditorMessageContents::Update(UpdateMessageContents {
@@ -397,16 +415,19 @@ async fn test_server_core(
doc: vec![StringDiff {
from: 0,
to: Some(10),
- insert: " # Testfoo\n".to_string()
+ insert: " # Testfoo\n".to_string(),
}],
- doc_blocks: vec![]
- })
+ doc_blocks: vec![],
+ version,
+ }),
+ version: client_version,
}),
cursor_position: Some(1),
- scroll_position: Some(1.0)
- })
+ scroll_position: Some(1.0),
+ }),
}
);
+ version = client_version;
codechat_server.send_result(client_id, None).await.unwrap();
// #### Code block tests
@@ -457,8 +478,10 @@ async fn test_server_core(
// Verify the updated text.
client_id += MESSAGE_ID_INCREMENT;
+ let msg = codechat_server.get_message_timeout(TIMEOUT).await.unwrap();
+ let client_version = get_version(&msg);
assert_eq!(
- codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
+ msg,
EditorMessage {
id: client_id,
message: EditorMessageContents::Update(UpdateMessageContents {
@@ -473,8 +496,10 @@ async fn test_server_core(
to: Some(18),
insert: "code()bar".to_string()
}],
- doc_blocks: vec![]
- })
+ doc_blocks: vec![],
+ version,
+ }),
+ version: client_version,
}),
cursor_position: Some(2),
scroll_position: Some(1.0)
@@ -486,10 +511,11 @@ async fn test_server_core(
// #### IDE edits
//
// Perform IDE edits.
+ version = 2.0;
let ide_id = codechat_server
.send_message_update_plain(
path_str.clone(),
- Some(" # Testfood\ncode()bark".to_string()),
+ Some((" # Testfood\ncode()bark".to_string(), version)),
Some(1),
None,
)
@@ -516,10 +542,11 @@ async fn test_server_core(
// Perform a second edit and verification, to produce a diff sent to the
// Client.
+ version = 3.0;
let ide_id = codechat_server
.send_message_update_plain(
path_str.clone(),
- Some(" # food\nbark".to_string()),
+ Some((" # food\nbark".to_string(), version)),
Some(1),
None,
)
@@ -554,8 +581,10 @@ async fn test_server_core(
// Before changing files, the current file will be updated.
client_id += MESSAGE_ID_INCREMENT;
+ let msg = codechat_server.get_message_timeout(TIMEOUT).await.unwrap();
+ let client_version = get_version(&msg);
assert_eq!(
- codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
+ msg,
EditorMessage {
id: client_id,
message: EditorMessageContents::Update(UpdateMessageContents {
@@ -567,10 +596,11 @@ async fn test_server_core(
source: CodeMirrorDiffable::Plain(CodeMirror {
doc: " # food\nbark".to_string(),
doc_blocks: vec![]
- })
+ }),
+ version: client_version,
}),
cursor_position: Some(1),
- scroll_position: Some(1.0)
+ scroll_position: Some(1.0),
})
}
);
@@ -590,9 +620,13 @@ async fn test_server_core(
.assert_all_messages(&codechat_server, TIMEOUT)
.await;
- // Ask the server to load the file from disk.
+ // Provide the requested file contents.
+ version = 4.0;
codechat_server
- .send_result_loadfile(server_id, None)
+ .send_result_loadfile(
+ server_id,
+ Some(("A **markdown** file.".to_string(), version)),
+ )
.await
.unwrap();
@@ -633,8 +667,10 @@ async fn test_server_core(
// Perform edits.
body_content.send_keys("foo ").await.unwrap();
client_id += MESSAGE_ID_INCREMENT;
+ let msg = codechat_server.get_message_timeout(TIMEOUT).await.unwrap();
+ let client_version = get_version(&msg);
assert_eq!(
- codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
+ msg,
EditorMessage {
id: client_id,
message: EditorMessageContents::Update(UpdateMessageContents {
@@ -652,8 +688,10 @@ async fn test_server_core(
if cfg!(windows) { "\r\n" } else { "\n" }
),
}],
- doc_blocks: vec![]
- })
+ doc_blocks: vec![],
+ version,
+ }),
+ version: client_version,
}),
cursor_position: None,
scroll_position: None
@@ -663,10 +701,11 @@ async fn test_server_core(
codechat_server.send_result(client_id, None).await.unwrap();
// Perform an IDE edit.
+ version = 5.0;
let ide_id = codechat_server
.send_message_update_plain(
md_path_str.clone(),
- Some("food A **markdown** file.".to_string()),
+ Some(("food A **markdown** file.".to_string(), version)),
Some(1),
None,
)
From 22ff197f7e4773bea086bde4446234d11fc0100c Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Mon, 24 Nov 2025 08:14:46 -0600
Subject: [PATCH 14/38] Fix: export JavaScript bindings before compiling the
VSCode extension.
---
builder/src/main.rs | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/builder/src/main.rs b/builder/src/main.rs
index ec1a3719..0b7896d3 100644
--- a/builder/src/main.rs
+++ b/builder/src/main.rs
@@ -510,8 +510,6 @@ fn run_build() -> io::Result<()> {
cargo build --manifest-path=$BUILDER_PATH/Cargo.toml;
info "cargo build";
cargo build;
- info "cargo test export_bindings";
- cargo test export_bindings;
)?;
// Clean out all bundled files before the rebuild.
remove_dir_all_if_exists(format!("{CLIENT_PATH}/static/bundled"))?;
@@ -528,7 +526,7 @@ fn run_client_build(
// checks.
skip_check_errors: bool,
) -> io::Result<()> {
- // Ensure the JavaScript data structured generated from Rust are up to date.
+ // Ensure the JavaScript data structures generated from Rust are up to date.
run_cmd!(
info "cargo test export_bindings";
cargo test export_bindings;
@@ -632,6 +630,12 @@ fn run_extensions_build(
}
run_script("npx", &napi_args, VSCODE_PATH, true)?;
+ // Ensure the JavaScript data structures generated from Rust are up to date.
+ run_cmd!(
+ info "cargo test export_bindings";
+ cargo test export_bindings;
+ )?;
+
// The main build for the extension.
run_script(
&esbuild,
From 747cb21dd16f6ef7068cc06b21b9b28502b6a361 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Mon, 24 Nov 2025 08:16:12 -0600
Subject: [PATCH 15/38] Fix: better error reporting in the VSCode extension.
---
extensions/VSCode/src/extension.ts | 37 +++++++++++++++---------------
extensions/VSCode/src/lib.rs | 11 ++++++++-
server/src/ide.rs | 4 ++--
server/src/webserver.rs | 6 +++--
4 files changed, 35 insertions(+), 23 deletions(-)
diff --git a/extensions/VSCode/src/extension.ts b/extensions/VSCode/src/extension.ts
index 8d59f9d0..e7dbc1da 100644
--- a/extensions/VSCode/src/extension.ts
+++ b/extensions/VSCode/src/extension.ts
@@ -48,6 +48,7 @@ import {
DEBUG_ENABLED,
MAX_MESSAGE_LENGTH,
} from "../../../client/src/debug_enabled.mjs";
+import { ResultErrTypes } from "../../../client/src/rust-types/ResultErrTypes";
// Globals
// -----------------------------------------------------------------------------
@@ -325,10 +326,9 @@ export const activate = (context: vscode.ExtensionContext) => {
value as UpdateMessageContents;
const doc = get_document(current_update.file_path);
if (doc === undefined) {
- sendResult(
- id,
- `No open document for ${current_update.file_path}`,
- );
+ sendResult(id, {
+ NoOpenDocument: current_update.file_path,
+ });
break;
}
if (current_update.contents !== undefined) {
@@ -357,10 +357,7 @@ export const activate = (context: vscode.ExtensionContext) => {
assert("Diff" in source);
// If this diff was not made against the text we currently have, reject it.
if (source.Diff.version !== version) {
- sendResult(
- id,
- "Out of sync: incorrect version for diff.",
- );
+ sendResult(id, "OutOfSync");
// Send an `Update` with the full text to re-sync the Client.
send_update(true);
break;
@@ -454,10 +451,12 @@ export const activate = (context: vscode.ExtensionContext) => {
current_file,
);
} catch (e) {
- sendResult(
- id,
- `Error: unable to open file ${current_file}: ${e}`,
- );
+ sendResult(id, {
+ OpenFileFailed: [
+ current_file,
+ (e as Error).toString(),
+ ],
+ });
continue;
}
ignore_active_editor_change = true;
@@ -491,10 +490,12 @@ export const activate = (context: vscode.ExtensionContext) => {
.then(
() => sendResult(id),
(reason) =>
- sendResult(
- id,
- `Error: unable to open file ${current_file}: ${reason}`,
- ),
+ sendResult(id, {
+ OpenFileFailed: [
+ current_file,
+ reason,
+ ],
+ }),
);
}
sendResult(id);
@@ -581,12 +582,12 @@ const format_struct = (complex_data_structure: any): string =>
: "";
// Send a result (a response to a message from the server) back to the server.
-const sendResult = (id: number, result: string | null = null) => {
+const sendResult = (id: number, result: ResultErrTypes | null = null) => {
assert(codeChatEditorServer);
console_log(
`CodeChat Editor extension: sending Result(id = ${id}, ${format_struct(result)}).`,
);
- codeChatEditorServer.sendResult(id, result);
+ codeChatEditorServer.sendResult(id, JSON.stringify(result));
};
// This is called after an event such as an edit, when the CodeChat panel
diff --git a/extensions/VSCode/src/lib.rs b/extensions/VSCode/src/lib.rs
index aedeed8c..c15ee28e 100644
--- a/extensions/VSCode/src/lib.rs
+++ b/extensions/VSCode/src/lib.rs
@@ -99,9 +99,18 @@ impl CodeChatEditorServer {
pub async fn send_result(
&self,
id: f64,
+ // If provided, a JSON-encoded `ResultErrTypes`.
message_result: Option,
) -> std::io::Result<()> {
- self.0.send_result(id, message_result).await
+ let message = if let Some(err_json) = message_result {
+ match serde_json::from_str(&err_json) {
+ Ok(v) => Some(v),
+ Err(err) => return Err(std::io::Error::other(err.to_string())),
+ }
+ } else {
+ None
+ };
+ self.0.send_result(id, message).await
}
#[napi]
diff --git a/server/src/ide.rs b/server/src/ide.rs
index b9ef2b08..6a7119ae 100644
--- a/server/src/ide.rs
+++ b/server/src/ide.rs
@@ -277,13 +277,13 @@ impl CodeChatEditorServer {
pub async fn send_result(
&self,
id: f64,
- message_result: Option,
+ message_result: Option,
) -> std::io::Result<()> {
let editor_message = EditorMessage {
id,
message: webserver::EditorMessageContents::Result(
if let Some(message_result) = message_result {
- Err(ResultErrTypes::ExtensionError(message_result))
+ Err(message_result)
} else {
Ok(ResultOkTypes::Void)
},
diff --git a/server/src/webserver.rs b/server/src/webserver.rs
index 239ae2c5..0ebc1780 100644
--- a/server/src/webserver.rs
+++ b/server/src/webserver.rs
@@ -297,10 +297,12 @@ pub enum ResultErrTypes {
SaveFileError(PathBuf, String),
#[error("unable to watch file '{0}': {1}")]
FileWatchError(PathBuf, String),
- #[error("IDE error: {0}")]
- ExtensionError(String),
#[error("ignoring update for {0} because it's not the current file {1}")]
IgnoredUpdate(String, String),
+ #[error("no open document for {0}")]
+ NoOpenDocument(String),
+ #[error("unable to open file {0}: {1}")]
+ OpenFileFailed(String, String),
}
/// Specify the type of IDE that this client represents.
From c16f312fd76bb4a7e8c85c6c78b7f6aea18471d3 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Mon, 24 Nov 2025 10:49:07 -0600
Subject: [PATCH 16/38] docs: changelog updates.
---
CHANGELOG.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 08518c7c..8ecd277a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -22,9 +22,10 @@ Changelog
[Github master](https://github.com/bjones1/CodeChat_Editor)
--------------------------------------------------------------------------------
-* Block drag and drop of images, which creates a mess.
+* Drag and drop of images creates a mess; disable drop and drop for this reason.
* Send sync data when doc blocks receive focus.
* Improve error handling.
+* Improve method used to keep Client and IDE contents in sync.
Version 0.1.41 -- 2025-Nov-17
--------------------------------------------------------------------------------
From 8a51c77fc17ec9ebe99830d5f41d702ae389af2b Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Mon, 24 Nov 2025 10:49:07 -0600
Subject: [PATCH 17/38] Fix: ignore test that fails intermittently on Mac.
---
server/src/webserver/tests.rs | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/server/src/webserver/tests.rs b/server/src/webserver/tests.rs
index 2cd3a034..9cc41e2c 100644
--- a/server/src/webserver/tests.rs
+++ b/server/src/webserver/tests.rs
@@ -18,13 +18,12 @@
// Imports
// -------
// ### Standard library
-use std::{
- path::{MAIN_SEPARATOR_STR, PathBuf},
- thread::sleep,
- time::Duration,
-};
+use std::path::{MAIN_SEPARATOR_STR, PathBuf};
+#[cfg(not(target_os = "macos"))]
+use std::{thread::sleep, time::Duration};
// ### Third-party
+#[cfg(not(target_os = "macos"))]
use assert_cmd::Command;
use assertables::{assert_ends_with, assert_not_contains, assert_starts_with};
@@ -48,6 +47,7 @@ use crate::{
// warning: use of deprecated associated function `assert_cmd::Command::cargo_bin`:
// incompatible with a custom cargo build-dir, see instead `cargo::cargo_bin_cmd!`
// ```
+#[cfg(not(target_os = "macos"))]
#[allow(deprecated)]
fn get_server() -> Command {
Command::cargo_bin(assert_cmd::pkg_name!()).unwrap()
@@ -131,7 +131,8 @@ fn test_path_to_url() {
temp_dir.close().unwrap();
}
-// Test startup outside the repo path.
+// Test startup outside the repo path. For some reason, this fails intermittently on Mac. Ignore these failures.
+#[cfg(not(target_os = "macos"))]
#[test]
fn test_other_path() {
let (temp_dir, test_dir) = prep_test_dir!();
From 2c346ccd3db730755ce0bf8a560f6ff002e539b8 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Tue, 25 Nov 2025 17:03:51 -0600
Subject: [PATCH 18/38] Refactor: split translation function into subfunctions.
---
server/src/translation.rs | 1194 ++++++++++++++++++++-----------------
server/src/webserver.rs | 19 +-
2 files changed, 652 insertions(+), 561 deletions(-)
diff --git a/server/src/translation.rs b/server/src/translation.rs
index 3eb82a13..aea8dfa5 100644
--- a/server/src/translation.rs
+++ b/server/src/translation.rs
@@ -215,13 +215,12 @@ use tokio::{fs::File, select, sync::mpsc};
// ### Local
use crate::{
- oneshot_send,
processing::{
- CodeChatForWeb, CodeMirror, CodeMirrorDiff, CodeMirrorDiffable, SourceFileMetadata,
- TranslationResultsString, codechat_for_web_to_source, diff_code_mirror_doc_blocks,
- diff_str, source_to_codechat_for_web_string,
+ CodeChatForWeb, CodeMirror, CodeMirrorDiff, CodeMirrorDiffable, CodeMirrorDocBlock,
+ SourceFileMetadata, TranslationResultsString, codechat_for_web_to_source,
+ diff_code_mirror_doc_blocks, diff_str, source_to_codechat_for_web_string,
},
- queue_send,
+ queue_send, queue_send_func,
webserver::{
EditorMessage, EditorMessageContents, INITIAL_MESSAGE_ID, MESSAGE_ID_INCREMENT,
ProcessingTaskHttpRequest, ResultErrTypes, ResultOkTypes, SimpleHttpResponse,
@@ -373,14 +372,68 @@ pub fn create_translation_queues(
})
}
-// This is the processing task for the Visual Studio Code IDE. It handles all
-// the core logic to moving data between the IDE and the client.
+/// This holds the state used by the main loop of the translation task; this allows factoring out lengthy contents in the loop into subfunctions.
+struct TranslationTask {
+ // These parameters are passed to us.
+ connection_id_raw: String,
+ prefix: &'static [&'static str],
+ allow_source_diffs: bool,
+ to_ide_tx: Sender,
+ from_ide_rx: Receiver,
+ to_client_tx: Sender,
+ from_client_rx: Receiver,
+ from_http_rx: Receiver,
+
+ // These parameters are internal state.
+ //
+ /// The file currently loaded in the Client.
+ current_file: PathBuf,
+ /// A map of `LoadFile` requests sent to the IDE, awaiting its response.
+ load_file_requests: HashMap,
+ /// The id for messages created by the server. Leave space for a server message during the init phase.
+ id: f64,
+ /// The source code, provided by the IDE. It will use whatever the
+ /// IDE provides for EOLs, which is stored in `eol` below.
+ source_code: String,
+ code_mirror_doc: String,
+ eol: EolType,
+ /// Some means this contains valid HTML; None means don't use it
+ /// (since it would have contained Markdown).
+ code_mirror_doc_blocks: Option>,
+ prefix_str: String,
+ /// To support sending diffs, we must provide a way to determine if
+ /// the sender and receiver have the same file contents before
+ /// applying a diff. File contents can become unsynced due to:
+ ///
+ /// 1. A dropped/lost message between the IDE and Client.
+ /// 2. Edits to file contents in two locations before updates from
+ /// one location (the Client, for example) propagate to the other
+ /// location (the IDE).
+ ///
+ /// Therefore, assign each file a version number. All files are sent
+ /// with a unique, randomly-generated version number which define the
+ /// file's version after this update is applied. Diffs also include
+ /// the version number of the file before applying the diff; the
+ // receiver's current version number must match with the sender's
+ /// pre-diff version number in order to apply the diff. When the
+ /// versions don't match, the IDE must send a full text file to the
+ /// Server and Client to re-sync. When a file is first loaded, its
+ /// version number is None, signaling that the sender must always
+ /// provide the full text, not a diff.
+ version: f64,
+ /// Has the full (non-diff) version of the current file been sent?
+ /// Don't send diffs until this is sent.
+ sent_full: bool,
+}
+
+/// This is the processing task for the Visual Studio Code IDE. It handles all
+/// the core logic to moving data between the IDE and the client.
#[allow(clippy::too_many_arguments)]
pub async fn translation_task(
connection_id_prefix: String,
connection_id_raw: String,
prefix: &'static [&'static str],
- app_state_task: WebAppState,
+ app_state: WebAppState,
shutdown_only: bool,
allow_source_diffs: bool,
to_ide_tx: Sender,
@@ -388,588 +441,627 @@ pub async fn translation_task(
to_client_tx: Sender,
mut from_client_rx: Receiver,
) {
- // Start the processing task.
let connection_id = format!("{connection_id_prefix}{connection_id_raw}");
if !shutdown_only {
- // Use a [labeled block
- // expression](https://doc.rust-lang.org/reference/expressions/loop-expr.html#labelled-block-expressions)
- // to provide a way to exit the current task.
- 'task: {
- let mut current_file = PathBuf::new();
- let mut load_file_requests: HashMap = HashMap::new();
- debug!("VSCode processing task started.");
-
- // Create a queue for HTTP requests fo communicate with this task.
- let (from_http_tx, mut from_http_rx) = mpsc::channel(10);
- app_state_task
- .processing_task_queue_tx
- .lock()
- .unwrap()
- .insert(connection_id.to_string(), from_http_tx);
-
- // Leave space for a server message during the init phase.
- let mut id: f64 = INITIAL_MESSAGE_ID + MESSAGE_ID_INCREMENT;
- // The source code, provided by the IDE. It will use whatever the
- // IDE provides for EOLs, which is stored in `eol` below.
- let mut source_code = String::new();
- let mut code_mirror_doc = String::new();
+ debug!("VSCode processing task started.");
+
+ // Create a queue for HTTP requests fo communicate with this task.
+ let (from_http_tx, from_http_rx) = mpsc::channel(10);
+ app_state
+ .processing_task_queue_tx
+ .lock()
+ .unwrap()
+ .insert(connection_id.to_string(), from_http_tx);
+
+ let mut continue_loop = true;
+ let mut tt = TranslationTask {
+ connection_id_raw,
+ prefix,
+ allow_source_diffs,
+ to_ide_tx,
+ from_ide_rx,
+ to_client_tx,
+ from_client_rx,
+ from_http_rx,
+ current_file: PathBuf::new(),
+ load_file_requests: HashMap::new(),
+ id: INITIAL_MESSAGE_ID + MESSAGE_ID_INCREMENT,
+ source_code: String::new(),
+ code_mirror_doc: String::new(),
// The initial state will be overwritten by the first `Update` or
// `LoadFile`, so this value doesn't matter.
- let mut eol = EolType::Lf;
+ eol: EolType::Lf,
// Some means this contains valid HTML; None means don't use it
// (since it would have contained Markdown).
- let mut code_mirror_doc_blocks = Some(Vec::new());
- let prefix_str = "/".to_string() + &prefix.join("/");
- // To support sending diffs, we must provide a way to determine if
- // the sender and receiver have the same file contents before
- // applying a diff. File contents can become unsynced due to:
- //
- // 1. A dropped/lost message between the IDE and Client.
- // 2. Edits to file contents in two locations before updates from
- // one location (the Client, for example) propagate to the other
- // location (the IDE).
- //
- // Therefore, assign each file a version number. All files are sent
- // with a unique, randomly-generated version number which define the
- // file's version after this update is applied. Diffs also include
- // the version number of the file before applying the diff; the
- // receiver's current version number must match with the sender's
- // pre-diff version number in order to apply the diff. When the
- // versions don't match, the IDE must send a full text file to the
- // Server and Client to re-sync. When a file is first loaded, its
- // version number is None, signaling that the sender must always
- // provide the full text, not a diff.
- let mut version = 0.0;
- // Has the full (non-diff) version of the current file been sent?
+ code_mirror_doc_blocks: Some(Vec::new()),
+ prefix_str: "/".to_string() + &prefix.join("/"),
+ version: 0.0,
// Don't send diffs until this is sent.
- let mut sent_full = false;
- loop {
- select! {
- // Look for messages from the IDE.
- Some(ide_message) = from_ide_rx.recv() => {
- debug!("Received IDE message id = {}, message = {}", ide_message.id, debug_shorten(&ide_message.message));
- match ide_message.message {
- // Handle messages that the IDE must not send.
- EditorMessageContents::Opened(_) |
- EditorMessageContents::OpenUrl(_) |
- EditorMessageContents::LoadFile(_) |
- EditorMessageContents::ClientHtml(_) => {
- let err = ResultErrTypes::IdeIllegalMessage;
- error!("{err:?}");
- send_response(&to_ide_tx, ide_message.id, Err(err)).await;
- },
-
- // Handle messages that are simply passed through.
- EditorMessageContents::Closed |
- EditorMessageContents::RequestClose => {
- debug!("Forwarding it to the Client.");
- queue_send!(to_client_tx.send(ide_message))
- },
-
- // Pass a `Result` message to the Client, unless
- // it's a `LoadFile` result.
- EditorMessageContents::Result(ref result) => {
- let is_loadfile = match result {
- // See if this error was produced by a
- // `LoadFile` result.
- Err(_) => load_file_requests.contains_key(&ide_message.id.to_bits()),
- Ok(result_ok) => match result_ok {
- ResultOkTypes::Void => false,
- ResultOkTypes::LoadFile(_) => true,
- }
- };
- // Pass the message to the client if this isn't
- // a `LoadFile` result (the only type of result
- // which the Server should handle).
- if !is_loadfile {
- debug!("Forwarding it to the Client.");
- // If the Server can't read our diff, send the full text next time.
- if matches!(result, Err(ResultErrTypes::OutOfSync)) {
- sent_full = false;
- }
- queue_send!(to_client_tx.send(ide_message));
- continue;
- }
- // Ensure there's an HTTP request for this
- // `LoadFile` result.
- let Some(http_request) = load_file_requests.remove(&ide_message.id.to_bits()) else {
- error!("Error: no HTTP request found for LoadFile result ID {}.", ide_message.id);
- break 'task;
- };
-
- // Take ownership of the result after sending it
- // above (which requires ownership).
- let EditorMessageContents::Result(result) = ide_message.message else {
- error!("{}", "Not a result.");
- break;
- };
- // Get the file contents from a `LoadFile`
- // result; otherwise, this is None.
- let file_contents_option = match result {
- Err(err) => {
- error!("{err:?}");
- None
- },
- Ok(result_ok) => match result_ok {
- ResultOkTypes::Void => panic!("LoadFile result should not be void."),
- ResultOkTypes::LoadFile(file_contents) => file_contents,
- }
- };
-
- // Process the file contents. Since VSCode
- // doesn't have a PDF viewer, determine if this
- // is a PDF file. (TODO: look at the magic
- // number also -- "%PDF").
- let use_pdf_js = http_request.file_path.extension() == Some(OsStr::new("pdf"));
- let ((simple_http_response, option_update), file_contents) = match file_contents_option {
- Some((file_contents, new_version)) => {
- version = new_version;
- // The IDE just sent the full contents; we're sending full contents to the Client.
- sent_full = true;
- (file_to_response(&http_request, new_version, ¤t_file, Some(&file_contents), use_pdf_js).await, file_contents)
- },
- None => {
- // The file wasn't available in the IDE.
- // Look for it in the filesystem.
- match File::open(&http_request.file_path).await {
- Err(err) => (
- (
- SimpleHttpResponse::Err(SimpleHttpResponseError::Io(err)),
- None,
- ),
- // There's no file, so return empty
- // contents, which will be ignored.
- "".to_string()
- ),
- Ok(mut fc) => {
- let option_file_contents = try_read_as_text(&mut fc).await;
- (
- file_to_response(
- &http_request,
- version,
- ¤t_file,
- option_file_contents.as_ref(),
- use_pdf_js,
- )
- .await,
- // If the file is binary, return empty
- // contents, which will be ignored.
- option_file_contents.unwrap_or("".to_string())
- )
- }
- }
- }
- };
- if let Some(update) = option_update {
- let Some(ref tmp) = update.contents else {
- error!("None.");
- break;
- };
- let CodeMirrorDiffable::Plain(ref plain) = tmp.source else {
- error!("Not plain!");
- break;
- };
- source_code = file_contents;
- eol = find_eol_type(&source_code);
- // We must clone here, since the original is
- // placed in the TX queue.
- code_mirror_doc = plain.doc.clone();
- code_mirror_doc_blocks = Some(plain.doc_blocks.clone());
-
- debug!("Sending Update to Client, id = {id}.");
- queue_send!(to_client_tx.send(EditorMessage {
- id,
- message: EditorMessageContents::Update(update)
+ sent_full: false,
+ };
+ while continue_loop {
+ select! {
+ // Look for messages from the IDE.
+ Some(ide_message) = tt.from_ide_rx.recv() => {
+ debug!("Received IDE message id = {}, message = {}", ide_message.id, debug_shorten(&ide_message.message));
+ match ide_message.message {
+ // Handle messages that the IDE must not send.
+ EditorMessageContents::Opened(_) |
+ EditorMessageContents::OpenUrl(_) |
+ EditorMessageContents::LoadFile(_) |
+ EditorMessageContents::ClientHtml(_) => {
+ let err = ResultErrTypes::IdeIllegalMessage;
+ error!("{err:?}");
+ send_response(&tt.to_ide_tx, ide_message.id, Err(err)).await;
+ },
+
+ // Handle messages that are simply passed through.
+ EditorMessageContents::Closed |
+ EditorMessageContents::RequestClose => {
+ debug!("Forwarding it to the Client.");
+ queue_send!(tt.to_client_tx.send(ide_message))
+ },
+
+ EditorMessageContents::Result(_) => continue_loop = tt.ide_result(ide_message).await,
+ EditorMessageContents::Update(_) => continue_loop = tt.ide_update(ide_message).await,
+
+ // Update the current file; translate it to a URL
+ // then pass it to the Client.
+ EditorMessageContents::CurrentFile(file_path, _is_text) => {
+ debug!("Translating and forwarding it to the Client.");
+ match try_canonicalize(&file_path) {
+ Ok(clean_file_path) => {
+ queue_send!(tt.to_client_tx.send(EditorMessage {
+ id: ide_message.id,
+ message: EditorMessageContents::CurrentFile(
+ path_to_url(&tt.prefix_str, Some(&tt.connection_id_raw), &clean_file_path), Some(true)
+ )
}));
- id += MESSAGE_ID_INCREMENT;
+ tt.current_file = file_path.into();
+ // Since this is a new file, mark it as
+ // unsent in full.
+ tt.sent_full = false;
+ }
+ Err(err) => {
+ error!("{err:?}");
+ send_response(&tt.to_client_tx, ide_message.id, Err(ResultErrTypes::TryCanonicalizeError(err.to_string()))).await;
}
- debug!("Sending HTTP response.");
- oneshot_send!(http_request.response_queue.send(simple_http_response));
}
+ }
+ }
+ },
- // Handle the `Update` message.
- EditorMessageContents::Update(update) => {
- // Normalize the provided file name.
- let result = match try_canonicalize(&update.file_path) {
- Err(err) => Err(ResultErrTypes::TryCanonicalizeError(err.to_string())),
- Ok(clean_file_path) => {
- match update.contents {
- None => {
- queue_send!(to_client_tx.send(EditorMessage {
- id: ide_message.id,
- message: EditorMessageContents::Update(UpdateMessageContents {
- file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(),
- contents: None,
- cursor_position: update.cursor_position,
- scroll_position: update.scroll_position,
- }),
- }));
- Ok(ResultOkTypes::Void)
- }
+ // Handle HTTP requests.
+ Some(http_request) = tt.from_http_rx.recv() => {
+ debug!("Received HTTP request for {:?} and sending LoadFile to IDE, id = {}.", http_request.file_path, tt.id);
+ // Convert the request into a `LoadFile` message.
+ queue_send!(tt.to_ide_tx.send(EditorMessage {
+ id: tt.id,
+ message: EditorMessageContents::LoadFile(http_request.file_path.clone())
+ }));
+ // Store the ID and request, which are needed to send a
+ // response when the `LoadFile` result is received.
+ tt.load_file_requests.insert(tt.id.to_bits(), http_request);
+ tt.id += MESSAGE_ID_INCREMENT;
+ }
- Some(contents) => {
- match contents.source {
- CodeMirrorDiffable::Diff(_diff) => Err(ResultErrTypes::TodoDiffSupport),
- CodeMirrorDiffable::Plain(code_mirror) => {
- // If there are Windows newlines, replace
- // with Unix; this is reversed when the
- // file is sent back to the IDE.
- eol = find_eol_type(&code_mirror.doc);
- let doc_normalized_eols = code_mirror.doc.replace("\r\n", "\n");
- // Translate the file.
- match source_to_codechat_for_web_string(&doc_normalized_eols, ¤t_file, contents.version, false) {
- Err(err) => Err(ResultErrTypes::CannotTranslateSource(err.to_string())),
- Ok((translation_results_string, _path_to_toc)) => match translation_results_string {
- TranslationResultsString::CodeChat(ccfw) => {
- // Send the new translated contents.
- debug!("Sending translated contents to Client.");
- let CodeMirrorDiffable::Plain(ref ccfw_source_plain) = ccfw.source else {
- error!("{}", "Unexpected diff value.");
- break;
- };
- // Send a diff if possible.
- let client_contents = Some(
- if let Some(cmdb) = code_mirror_doc_blocks &&
- sent_full {
- let doc_diff = diff_str(&code_mirror_doc, &ccfw_source_plain.doc);
- let code_mirror_diff = diff_code_mirror_doc_blocks(&cmdb, &ccfw_source_plain.doc_blocks);
- CodeChatForWeb {
- // Clone needed here, so we can copy it
- // later.
- metadata: ccfw.metadata.clone(),
- source: CodeMirrorDiffable::Diff(CodeMirrorDiff {
- doc: doc_diff,
- doc_blocks: code_mirror_diff,
- // The diff was made between the current version (`version`) and the new version (`contents.version`).
- version
- }),
- version: contents.version,
- }
- } else {
- sent_full = true;
- // We must make a clone to put in the TX
- // queue; this allows us to keep the
- // original below to use with the next
- // diff.
- ccfw.clone()
- }
- );
- queue_send!(to_client_tx.send(EditorMessage {
- id: ide_message.id,
- message: EditorMessageContents::Update(UpdateMessageContents {
- file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(),
- contents: client_contents,
- cursor_position: update.cursor_position,
- scroll_position: update.scroll_position,
- }),
- }));
- // Update to the latest code after
- // computing diffs. To avoid ownership
- // problems, re-define `ccfw_source_plain`.
- let CodeMirrorDiffable::Plain(ccfw_source_plain) = ccfw.source else {
- error!("{}", "Unexpected diff value.");
- break;
- };
- source_code = code_mirror.doc;
- code_mirror_doc = ccfw_source_plain.doc;
- code_mirror_doc_blocks = Some(ccfw_source_plain.doc_blocks);
- // Update to the version of the file just sent.
- version = contents.version;
- Ok(ResultOkTypes::Void)
- }
- // TODO
- TranslationResultsString::Binary => Err(ResultErrTypes::TodoBinarySupport),
- TranslationResultsString::Unknown => {
- // Send the new raw contents.
- debug!("Sending translated contents to Client.");
- queue_send!(to_client_tx.send(EditorMessage {
- id: ide_message.id,
- message: EditorMessageContents::Update(UpdateMessageContents {
- file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(),
- contents: Some(CodeChatForWeb {
- metadata: SourceFileMetadata {
- // Since this is raw data, `mode` doesn't
- // matter.
- mode: "".to_string(),
- },
- source: CodeMirrorDiffable::Plain(CodeMirror {
- doc: code_mirror.doc,
- doc_blocks: vec![]
- }),
- version: contents.version
- }),
- cursor_position: update.cursor_position,
- scroll_position: update.scroll_position,
- }),
- }));
- Ok(ResultOkTypes::Void)
- },
- TranslationResultsString::Toc(_) => {
- Err(ResultErrTypes::NotToc)
- }
- }
- }
- }
- }
- }
- }
- }
- };
- // If there's an error, then report it;
- // otherwise, the message is passed to the
- // Client, which will provide the result.
- if let Err(err) = &result {
- error!("{err:?}");
- send_response(&to_ide_tx, ide_message.id, result).await;
- }
+ // Handle messages from the client.
+ Some(client_message) = tt.from_client_rx.recv() => {
+ debug!("Received Client message id = {}, message = {}", client_message.id, debug_shorten(&client_message.message));
+ match client_message.message {
+ // Handle messages that the client must not send.
+ EditorMessageContents::Opened(_) |
+ EditorMessageContents::LoadFile(_) |
+ EditorMessageContents::RequestClose |
+ EditorMessageContents::ClientHtml(_) => {
+ let err = ResultErrTypes::ClientIllegalMessage;
+ error!("{err:?}");
+ send_response(&tt.to_client_tx, client_message.id, Err(err)).await;
+ },
+
+ // Handle messages that are simply passed through.
+ EditorMessageContents::Closed => {
+ debug!("Forwarding it to the IDE.");
+ queue_send!(tt.to_ide_tx.send(client_message))
+ },
+
+ EditorMessageContents::Result(ref result) => {
+ debug!("Forwarding it to the IDE.");
+ // If the Client can't read our diff, send the full text next time.
+ if matches!(result, Err(ResultErrTypes::OutOfSync)) {
+ tt.sent_full = false;
}
+ queue_send!(tt.to_ide_tx.send(client_message))
+ },
- // Update the current file; translate it to a URL
- // then pass it to the Client.
- EditorMessageContents::CurrentFile(file_path, _is_text) => {
- debug!("Translating and forwarding it to the Client.");
- match try_canonicalize(&file_path) {
- Ok(clean_file_path) => {
- queue_send!(to_client_tx.send(EditorMessage {
- id: ide_message.id,
- message: EditorMessageContents::CurrentFile(
- path_to_url(&prefix_str, Some(&connection_id_raw), &clean_file_path), Some(true)
- )
- }));
- current_file = file_path.into();
- // Since this is a new file, mark it as
- // unsent in full.
- sent_full = false;
- }
- Err(err) => {
- error!("{err:?}");
- send_response(&to_client_tx, ide_message.id, Err(ResultErrTypes::TryCanonicalizeError(err.to_string()))).await;
+ // Open a web browser when requested.
+ EditorMessageContents::OpenUrl(url) => {
+ // This doesn't work in Codespaces. TODO: send
+ // this back to the VSCode window, then call
+ // `vscode.env.openExternal(vscode.Uri.parse(url))`.
+ if let Err(err) = webbrowser::open(&url) {
+ let err = ResultErrTypes::WebBrowserOpenFailed(err.to_string());
+ error!("{err:?}");
+ send_response(&tt.to_client_tx, client_message.id, Err(err)).await;
+ } else {
+ send_response(&tt.to_client_tx, client_message.id, Ok(ResultOkTypes::Void)).await;
+ }
+ },
+
+ EditorMessageContents::Update(_) => continue_loop = tt.client_update(client_message).await,
+
+ // Update the current file; translate it to a URL
+ // then pass it to the IDE.
+ EditorMessageContents::CurrentFile(url_string, _is_text) => {
+ debug!("Forwarding translated path to IDE.");
+ let result = match url_to_path(&url_string, tt.prefix) {
+ Err(err) => Err(ResultErrTypes::UrlToPathError(url_string.to_string(), err.to_string())),
+ Ok(file_path) => {
+ match file_path.to_str() {
+ None => Err(ResultErrTypes::NoPathToString(file_path)),
+ Some(file_path_string) => {
+ // Use a [binary file
+ // sniffer](#binary-file-sniffer) to
+ // determine if the file is text or binary.
+ let is_text = if let Ok(mut fc) = File::open(&file_path).await {
+ try_read_as_text(&mut fc).await.is_some()
+ } else {
+ false
+ };
+ queue_send!(tt.to_ide_tx.send(EditorMessage {
+ id: client_message.id,
+ message: EditorMessageContents::CurrentFile(file_path_string.to_string(), Some(is_text))
+ }));
+ tt.current_file = file_path;
+ // Since this is a new file, the full text hasn't been sent yet.
+ tt.sent_full = false;
+ Ok(())
+ }
}
}
+ };
+ if let Err(msg) = result {
+ error!("{msg}");
+ send_response(&tt.to_client_tx, client_message.id, Err(msg)).await;
}
}
- },
+ }
+ },
- // Handle HTTP requests.
- Some(http_request) = from_http_rx.recv() => {
- debug!("Received HTTP request for {:?} and sending LoadFile to IDE, id = {id}.", http_request.file_path);
- // Convert the request into a `LoadFile` message.
- queue_send!(to_ide_tx.send(EditorMessage {
- id,
- message: EditorMessageContents::LoadFile(http_request.file_path.clone())
- }));
- // Store the ID and request, which are needed to send a
- // response when the `LoadFile` result is received.
- load_file_requests.insert(id.to_bits(), http_request);
- id += MESSAGE_ID_INCREMENT;
+ else => break
+ }
+ }
+ (from_ide_rx, from_client_rx) = (tt.from_ide_rx, tt.from_client_rx);
+ }
+ debug!("VSCode processing task shutting down.");
+ if app_state
+ .processing_task_queue_tx
+ .lock()
+ .unwrap()
+ .remove(&connection_id)
+ .is_none()
+ {
+ error!("Unable to remove connection ID {connection_id} from processing task queue.");
+ }
+ if app_state
+ .client_queues
+ .lock()
+ .unwrap()
+ .remove(&connection_id)
+ .is_none()
+ {
+ error!("Unable to remove connection ID {connection_id} from client queues.");
+ }
+ if app_state
+ .ide_queues
+ .lock()
+ .unwrap()
+ .remove(&connection_id)
+ .is_none()
+ {
+ error!("Unable to remove connection ID {connection_id} from IDE queues.");
+ }
+
+ from_ide_rx.close();
+ from_client_rx.close();
+
+ // Drain any remaining messages after closing the queue.
+ while let Some(m) = from_ide_rx.recv().await {
+ warn!("Dropped queued message {m:?}");
+ }
+ while let Some(m) = from_client_rx.recv().await {
+ warn!("Dropped queued message {m:?}");
+ }
+ debug!("VSCode processing task exited.");
+}
+
+// These provide translation for messages passing through the Server.
+impl TranslationTask {
+ // Pass a `Result` message to the Client, unless
+ // it's a `LoadFile` result.
+ async fn ide_result(&mut self, ide_message: EditorMessage) -> bool {
+ let EditorMessageContents::Result(ref result) = ide_message.message else {
+ panic!("Should only be called with a result.");
+ };
+ let is_loadfile = match result {
+ // See if this error was produced by a
+ // `LoadFile` result.
+ Err(_) => self
+ .load_file_requests
+ .contains_key(&ide_message.id.to_bits()),
+ Ok(result_ok) => match result_ok {
+ ResultOkTypes::Void => false,
+ ResultOkTypes::LoadFile(_) => true,
+ },
+ };
+ // Pass the message to the client if this isn't
+ // a `LoadFile` result (the only type of result
+ // which the Server should handle).
+ if !is_loadfile {
+ debug!("Forwarding it to the Client.");
+ // If the Server can't read our diff, send the full text next time.
+ if matches!(result, Err(ResultErrTypes::OutOfSync)) {
+ self.sent_full = false;
+ }
+ queue_send_func!(self.to_client_tx.send(ide_message));
+ return true;
+ }
+ // Ensure there's an HTTP request for this
+ // `LoadFile` result.
+ let Some(http_request) = self.load_file_requests.remove(&ide_message.id.to_bits()) else {
+ error!(
+ "Error: no HTTP request found for LoadFile result ID {}.",
+ ide_message.id
+ );
+ return true;
+ };
+
+ // Take ownership of the result after sending it
+ // above (which requires ownership).
+ let EditorMessageContents::Result(result) = ide_message.message else {
+ panic!("Not a result.");
+ };
+ // Get the file contents from a `LoadFile`
+ // result; otherwise, this is None.
+ let file_contents_option = match result {
+ Err(err) => {
+ error!("{err:?}");
+ None
+ }
+ Ok(result_ok) => match result_ok {
+ ResultOkTypes::Void => panic!("LoadFile result should not be void."),
+ ResultOkTypes::LoadFile(file_contents) => file_contents,
+ },
+ };
+
+ // Process the file contents. Since VSCode
+ // doesn't have a PDF viewer, determine if this
+ // is a PDF file. (TODO: look at the magic
+ // number also -- "%PDF").
+ let use_pdf_js = http_request.file_path.extension() == Some(OsStr::new("pdf"));
+ let ((simple_http_response, option_update), file_contents) = match file_contents_option {
+ Some((file_contents, new_version)) => {
+ self.version = new_version;
+ // The IDE just sent the full contents; we're sending full contents to the Client.
+ self.sent_full = true;
+ (
+ file_to_response(
+ &http_request,
+ new_version,
+ &self.current_file,
+ Some(&file_contents),
+ use_pdf_js,
+ )
+ .await,
+ file_contents,
+ )
+ }
+ None => {
+ // The file wasn't available in the IDE.
+ // Look for it in the filesystem.
+ match File::open(&http_request.file_path).await {
+ Err(err) => (
+ (
+ SimpleHttpResponse::Err(SimpleHttpResponseError::Io(err)),
+ None,
+ ),
+ // There's no file, so return empty
+ // contents, which will be ignored.
+ "".to_string(),
+ ),
+ Ok(mut fc) => {
+ let option_file_contents = try_read_as_text(&mut fc).await;
+ (
+ file_to_response(
+ &http_request,
+ self.version,
+ &self.current_file,
+ option_file_contents.as_ref(),
+ use_pdf_js,
+ )
+ .await,
+ // If the file is binary, return empty
+ // contents, which will be ignored.
+ option_file_contents.unwrap_or("".to_string()),
+ )
}
+ }
+ }
+ };
+ if let Some(update) = option_update {
+ let Some(ref tmp) = update.contents else {
+ panic!("Contents must always be provided.");
+ };
+ let CodeMirrorDiffable::Plain(ref plain) = tmp.source else {
+ panic!("Diff not supported.");
+ };
+ self.source_code = file_contents;
+ self.eol = find_eol_type(&self.source_code);
+ // We must clone here, since the original is
+ // placed in the TX queue.
+ self.code_mirror_doc = plain.doc.clone();
+ self.code_mirror_doc_blocks = Some(plain.doc_blocks.clone());
- // Handle messages from the client.
- Some(client_message) = from_client_rx.recv() => {
- debug!("Received Client message id = {}, message = {}", client_message.id, debug_shorten(&client_message.message));
- match client_message.message {
- // Handle messages that the client must not send.
- EditorMessageContents::Opened(_) |
- EditorMessageContents::LoadFile(_) |
- EditorMessageContents::RequestClose |
- EditorMessageContents::ClientHtml(_) => {
- let err = ResultErrTypes::ClientIllegalMessage;
- error!("{err:?}");
- send_response(&to_client_tx, client_message.id, Err(err)).await;
- },
-
- // Handle messages that are simply passed through.
- EditorMessageContents::Closed => {
- debug!("Forwarding it to the IDE.");
- queue_send!(to_ide_tx.send(client_message))
- },
-
- EditorMessageContents::Result(ref result) => {
- debug!("Forwarding it to the IDE.");
- // If the Client can't read our diff, send the full text next time.
- if matches!(result, Err(ResultErrTypes::OutOfSync)) {
- sent_full = false;
- }
- queue_send!(to_ide_tx.send(client_message))
- },
-
- // Open a web browser when requested.
- EditorMessageContents::OpenUrl(url) => {
- // This doesn't work in Codespaces. TODO: send
- // this back to the VSCode window, then call
- // `vscode.env.openExternal(vscode.Uri.parse(url))`.
- if let Err(err) = webbrowser::open(&url) {
- let err = ResultErrTypes::WebBrowserOpenFailed(err.to_string());
- error!("{err:?}");
- send_response(&to_client_tx, client_message.id, Err(err)).await;
- } else {
- send_response(&to_client_tx, client_message.id, Ok(ResultOkTypes::Void)).await;
- }
- },
+ debug!("Sending Update to Client, id = {}.", self.id);
+ queue_send_func!(self.to_client_tx.send(EditorMessage {
+ id: self.id,
+ message: EditorMessageContents::Update(update)
+ }));
+ self.id += MESSAGE_ID_INCREMENT;
+ }
+ debug!("Sending HTTP response.");
+ if let Err(err) = http_request.response_queue.send(simple_http_response) {
+ error!("Unable to enqueue: {err:?}");
+ return false;
+ }
- // Handle the `Update` message.
- EditorMessageContents::Update(update_message_contents) => {
- debug!("Forwarding translation of it to the IDE.");
- match try_canonicalize(&update_message_contents.file_path) {
+ true
+ }
+
+ async fn ide_update(&mut self, ide_message: EditorMessage) -> bool {
+ let EditorMessageContents::Update(update) = ide_message.message else {
+ panic!("Expected update message.");
+ };
+ // Normalize the provided file name.
+ let result = match try_canonicalize(&update.file_path) {
+ Err(err) => Err(ResultErrTypes::TryCanonicalizeError(err.to_string())),
+ Ok(clean_file_path) => {
+ match update.contents {
+ None => {
+ queue_send_func!(self.to_client_tx.send(EditorMessage {
+ id: ide_message.id,
+ message: EditorMessageContents::Update(UpdateMessageContents {
+ file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(),
+ contents: None,
+ cursor_position: update.cursor_position,
+ scroll_position: update.scroll_position,
+ }),
+ }));
+ Ok(ResultOkTypes::Void)
+ }
+
+ Some(contents) => {
+ match contents.source {
+ CodeMirrorDiffable::Diff(_diff) => Err(ResultErrTypes::TodoDiffSupport),
+ CodeMirrorDiffable::Plain(code_mirror) => {
+ // If there are Windows newlines, replace
+ // with Unix; this is reversed when the
+ // file is sent back to the IDE.
+ self.eol = find_eol_type(&code_mirror.doc);
+ let doc_normalized_eols = code_mirror.doc.replace("\r\n", "\n");
+ // Translate the file.
+ match source_to_codechat_for_web_string(
+ &doc_normalized_eols,
+ &self.current_file,
+ contents.version,
+ false,
+ ) {
Err(err) => {
- let err = ResultErrTypes::TryCanonicalizeError(err.to_string());
- error!("{err:?}");
- send_response(&to_client_tx, client_message.id, Err(err)).await;
- continue;
+ Err(ResultErrTypes::CannotTranslateSource(err.to_string()))
}
- Ok(clean_file_path) => {
- let codechat_for_web = match update_message_contents.contents {
- None => None,
- Some(cfw) => match codechat_for_web_to_source(
- &cfw)
- {
- Ok(new_source_code) => {
- // Correct EOL endings for use with the
- // IDE.
- let new_source_code_eol = eol_convert(new_source_code, &eol);
- let ccfw = if sent_full && allow_source_diffs {
- Some(CodeChatForWeb {
- metadata: cfw.metadata,
- source: CodeMirrorDiffable::Diff(CodeMirrorDiff {
- // Diff with correct EOLs, so that (for
- // CRLF files as well as LF files) offsets
- // are correct.
- doc: diff_str(&source_code, &new_source_code_eol),
- doc_blocks: vec![],
- version,
- }),
- version: cfw.version,
- })
- } else {
- Some(CodeChatForWeb {
- metadata: cfw.metadata,
- source: CodeMirrorDiffable::Plain(CodeMirror {
- // We must clone here, so that it can be
- // placed in the TX queue.
- doc: new_source_code_eol.clone(),
- doc_blocks: vec![],
- }),
- version: cfw.version,
- })
- };
- version = cfw.version;
- source_code = new_source_code_eol;
- let CodeMirrorDiffable::Plain(cmd) = cfw.source else {
- // TODO: support diffable!
- error!("No diff!");
- break;
- };
- code_mirror_doc = cmd.doc;
- // TODO: instead of `cmd.doc_blocks`, use
- // `None` to indicate that the doc blocks
- // contain Markdown instead of HTML.
- code_mirror_doc_blocks = None;
- ccfw
- },
- Err(message) => {
- let err = ResultErrTypes::CannotTranslateCodeChat(message.to_string());
- error!("{err:?}");
- send_response(&to_client_tx, client_message.id, Err(err)).await;
- continue;
- }
- },
- };
- queue_send!(to_ide_tx.send(EditorMessage {
- id: client_message.id,
- message: EditorMessageContents::Update(UpdateMessageContents {
- file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(),
- contents: codechat_for_web,
- cursor_position: update_message_contents.cursor_position,
- scroll_position: update_message_contents.scroll_position,
- })
- }));
- }
- }
- },
-
- // Update the current file; translate it to a URL
- // then pass it to the IDE.
- EditorMessageContents::CurrentFile(url_string, _is_text) => {
- debug!("Forwarding translated path to IDE.");
- let result = match url_to_path(&url_string, prefix) {
- Err(err) => Err(ResultErrTypes::UrlToPathError(url_string.to_string(), err.to_string())),
- Ok(file_path) => {
- match file_path.to_str() {
- None => Err(ResultErrTypes::NoPathToString(file_path)),
- Some(file_path_string) => {
- // Use a [binary file
- // sniffer](#binary-file-sniffer) to
- // determine if the file is text or binary.
- let is_text = if let Ok(mut fc) = File::open(&file_path).await {
- try_read_as_text(&mut fc).await.is_some()
+ Ok((translation_results_string, _path_to_toc)) => {
+ match translation_results_string {
+ TranslationResultsString::CodeChat(ccfw) => {
+ // Send the new translated contents.
+ debug!("Sending translated contents to Client.");
+ let CodeMirrorDiffable::Plain(
+ ref ccfw_source_plain,
+ ) = ccfw.source
+ else {
+ panic!("Unexpected diff value.");
+ };
+ // Send a diff if possible.
+ let client_contents = if let Some(ref cmdb) =
+ self.code_mirror_doc_blocks
+ && self.sent_full
+ {
+ let doc_diff = diff_str(
+ &self.code_mirror_doc,
+ &ccfw_source_plain.doc,
+ );
+ let code_mirror_diff =
+ diff_code_mirror_doc_blocks(
+ cmdb,
+ &ccfw_source_plain.doc_blocks,
+ );
+ CodeChatForWeb {
+ // Clone needed here, so we can copy it
+ // later.
+ metadata: ccfw.metadata.clone(),
+ source: CodeMirrorDiffable::Diff(
+ CodeMirrorDiff {
+ doc: doc_diff,
+ doc_blocks: code_mirror_diff,
+ // The diff was made between the current version (`version`) and the new version (`contents.version`).
+ version: self.version,
+ },
+ ),
+ version: ccfw.version,
+ }
} else {
- false
+ self.sent_full = true;
+ // We must make a clone to put in the TX
+ // queue; this allows us to keep the
+ // original below to use with the next
+ // diff.
+ ccfw.clone()
+ };
+ queue_send_func!(self.to_client_tx.send(EditorMessage {
+ id: ide_message.id,
+ message: EditorMessageContents::Update(UpdateMessageContents {
+ file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(),
+ contents: Some(client_contents),
+ cursor_position: update.cursor_position,
+ scroll_position: update.scroll_position,
+ }),
+ }));
+ // Update to the latest code after
+ // computing diffs. To avoid ownership
+ // problems, re-define `ccfw_source_plain`.
+ let CodeMirrorDiffable::Plain(ccfw_source_plain) =
+ ccfw.source
+ else {
+ panic!("{}", "Unexpected diff value.");
};
- queue_send!(to_ide_tx.send(EditorMessage {
- id: client_message.id,
- message: EditorMessageContents::CurrentFile(file_path_string.to_string(), Some(is_text))
+ self.source_code = code_mirror.doc;
+ self.code_mirror_doc = ccfw_source_plain.doc;
+ self.code_mirror_doc_blocks =
+ Some(ccfw_source_plain.doc_blocks);
+ // Update to the version of the file just sent.
+ self.version = contents.version;
+ Ok(ResultOkTypes::Void)
+ }
+ // TODO
+ TranslationResultsString::Binary => {
+ Err(ResultErrTypes::TodoBinarySupport)
+ }
+ TranslationResultsString::Unknown => {
+ // Send the new raw contents.
+ debug!("Sending translated contents to Client.");
+ queue_send_func!(self.to_client_tx.send(EditorMessage {
+ id: ide_message.id,
+ message: EditorMessageContents::Update(UpdateMessageContents {
+ file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(),
+ contents: Some(CodeChatForWeb {
+ metadata: SourceFileMetadata {
+ // Since this is raw data, `mode` doesn't
+ // matter.
+ mode: "".to_string(),
+ },
+ source: CodeMirrorDiffable::Plain(CodeMirror {
+ doc: code_mirror.doc,
+ doc_blocks: vec![]
+ }),
+ version: contents.version
+ }),
+ cursor_position: update.cursor_position,
+ scroll_position: update.scroll_position,
+ }),
}));
- current_file = file_path;
- // Since this is a new file, the full text hasn't been sent yet.
- sent_full = false;
- Ok(())
+ Ok(ResultOkTypes::Void)
+ }
+ TranslationResultsString::Toc(_) => {
+ Err(ResultErrTypes::NotToc)
}
}
}
- };
- if let Err(msg) = result {
- error!("{msg}");
- send_response(&to_client_tx, client_message.id, Err(msg)).await;
}
}
}
- },
-
- else => break
+ }
}
}
+ };
+ // If there's an error, then report it;
+ // otherwise, the message is passed to the
+ // Client, which will provide the result.
+ if let Err(err) = &result {
+ error!("{err:?}");
+ send_response(&self.to_ide_tx, ide_message.id, result).await;
}
- debug!("VSCode processing task shutting down.");
- if app_state_task
- .processing_task_queue_tx
- .lock()
- .unwrap()
- .remove(&connection_id)
- .is_none()
- {
- error!("Unable to remove connection ID {connection_id} from processing task queue.");
- }
- if app_state_task
- .client_queues
- .lock()
- .unwrap()
- .remove(&connection_id)
- .is_none()
- {
- error!("Unable to remove connection ID {connection_id} from client queues.");
- }
- if app_state_task
- .ide_queues
- .lock()
- .unwrap()
- .remove(&connection_id)
- .is_none()
- {
- error!("Unable to remove connection ID {connection_id} from IDE queues.");
- }
-
- from_ide_rx.close();
- from_ide_rx.close();
+ true
+ }
- // Drain any remaining messages after closing the queue.
- while let Some(m) = from_ide_rx.recv().await {
- warn!("Dropped queued message {m:?}");
- }
- while let Some(m) = from_client_rx.recv().await {
- warn!("Dropped queued message {m:?}");
+ async fn client_update(&mut self, client_message: EditorMessage) -> bool {
+ let EditorMessageContents::Update(update_message_contents) = client_message.message else {
+ panic!("Expected update message.");
+ };
+ debug!("Forwarding translation of it to the IDE.");
+ match try_canonicalize(&update_message_contents.file_path) {
+ Err(err) => {
+ let err = ResultErrTypes::TryCanonicalizeError(err.to_string());
+ error!("{err:?}");
+ send_response(&self.to_client_tx, client_message.id, Err(err)).await;
+ return true;
+ }
+ Ok(clean_file_path) => {
+ let codechat_for_web = match update_message_contents.contents {
+ None => None,
+ Some(cfw) => match codechat_for_web_to_source(&cfw) {
+ Ok(new_source_code) => {
+ // Correct EOL endings for use with the
+ // IDE.
+ let new_source_code_eol = eol_convert(new_source_code, &self.eol);
+ let ccfw = if self.sent_full && self.allow_source_diffs {
+ Some(CodeChatForWeb {
+ metadata: cfw.metadata,
+ source: CodeMirrorDiffable::Diff(CodeMirrorDiff {
+ // Diff with correct EOLs, so that (for
+ // CRLF files as well as LF files) offsets
+ // are correct.
+ doc: diff_str(&self.source_code, &new_source_code_eol),
+ doc_blocks: vec![],
+ version: self.version,
+ }),
+ version: cfw.version,
+ })
+ } else {
+ Some(CodeChatForWeb {
+ metadata: cfw.metadata,
+ source: CodeMirrorDiffable::Plain(CodeMirror {
+ // We must clone here, so that it can be
+ // placed in the TX queue.
+ doc: new_source_code_eol.clone(),
+ doc_blocks: vec![],
+ }),
+ version: cfw.version,
+ })
+ };
+ self.version = cfw.version;
+ self.source_code = new_source_code_eol;
+ let CodeMirrorDiffable::Plain(cmd) = cfw.source else {
+ // TODO: support diffable!
+ panic!("Diff not supported.");
+ };
+ self.code_mirror_doc = cmd.doc;
+ // TODO: instead of `cmd.doc_blocks`, use
+ // `None` to indicate that the doc blocks
+ // contain Markdown instead of HTML.
+ self.code_mirror_doc_blocks = None;
+ ccfw
+ }
+ Err(message) => {
+ let err = ResultErrTypes::CannotTranslateCodeChat(message.to_string());
+ error!("{err:?}");
+ send_response(&self.to_client_tx, client_message.id, Err(err)).await;
+ return true;
+ }
+ },
+ };
+ queue_send_func!(self.to_ide_tx.send(EditorMessage {
+ id: client_message.id,
+ message: EditorMessageContents::Update(UpdateMessageContents {
+ file_path: clean_file_path.to_str().expect("Since the path started as a string, assume it losslessly translates back to a string.").to_string(),
+ contents: codechat_for_web,
+ cursor_position: update_message_contents.cursor_position,
+ scroll_position: update_message_contents.scroll_position,
+ })
+ }));
+ }
}
- debug!("VSCode processing task exited.");
+
+ true
}
}
diff --git a/server/src/webserver.rs b/server/src/webserver.rs
index 0ebc1780..baef0294 100644
--- a/server/src/webserver.rs
+++ b/server/src/webserver.rs
@@ -236,7 +236,7 @@ pub enum EditorMessageContents {
/// The contents of a `Result` message. We can't export this type, since `ts-rs`
/// only supports structs and enums.
-type MessageResult = Result<
+pub type MessageResult = Result<
// The result of the operation, if successful.
ResultOkTypes,
// The error message.
@@ -372,16 +372,15 @@ pub struct Credentials {
// -----------------------------------------------------------------------------
/// Create a macro to report an error when enqueueing an item.
#[macro_export]
-macro_rules! oneshot_send {
- // Provide two options: `break` or `break 'label`.
+macro_rules! queue_send {
($tx: expr) => {
- if let Err(err) = $tx {
+ if let Err(err) = $tx.await {
error!("Unable to enqueue: {err:?}");
break;
}
};
($tx: expr, $label: tt) => {
- if let Err(err) = $tx {
+ if let Err(err) = $tx.await {
error!("Unable to enqueue: {err:?}");
break $label;
}
@@ -389,12 +388,12 @@ macro_rules! oneshot_send {
}
#[macro_export]
-macro_rules! queue_send {
+macro_rules! queue_send_func {
($tx: expr) => {
- $crate::oneshot_send!($tx.await)
- };
- ($tx: expr, $label: tt) => {
- $crate::oneshot_send!($tx.await, $label)
+ if let Err(err) = $tx.await {
+ error!("Unable to enqueue: {err:?}");
+ return false;
+ }
};
}
From 0ac7ff1a94a81b695739fa2f2ef517480c1a1554 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Tue, 25 Nov 2025 17:45:13 -0600
Subject: [PATCH 19/38] wip - Fix: update Client with changes produced during
translation.
---
server/src/translation.rs | 106 +++++++++++-------
.../overall_core/test_client_updates/test.py | 7 +-
server/tests/overall_core/mod.rs | 47 +++++---
3 files changed, 102 insertions(+), 58 deletions(-)
diff --git a/server/src/translation.rs b/server/src/translation.rs
index aea8dfa5..61ef56db 100644
--- a/server/src/translation.rs
+++ b/server/src/translation.rs
@@ -865,45 +865,19 @@ impl TranslationTask {
// Send the new translated contents.
debug!("Sending translated contents to Client.");
let CodeMirrorDiffable::Plain(
- ref ccfw_source_plain,
+ ref code_mirror_translated,
) = ccfw.source
else {
panic!("Unexpected diff value.");
};
// Send a diff if possible.
- let client_contents = if let Some(ref cmdb) =
- self.code_mirror_doc_blocks
- && self.sent_full
- {
- let doc_diff = diff_str(
- &self.code_mirror_doc,
- &ccfw_source_plain.doc,
- );
- let code_mirror_diff =
- diff_code_mirror_doc_blocks(
- cmdb,
- &ccfw_source_plain.doc_blocks,
- );
- CodeChatForWeb {
- // Clone needed here, so we can copy it
- // later.
- metadata: ccfw.metadata.clone(),
- source: CodeMirrorDiffable::Diff(
- CodeMirrorDiff {
- doc: doc_diff,
- doc_blocks: code_mirror_diff,
- // The diff was made between the current version (`version`) and the new version (`contents.version`).
- version: self.version,
- },
- ),
- version: ccfw.version,
- }
+ let client_contents = if self.sent_full {
+ self.wrap_translation(
+ &ccfw,
+ code_mirror_translated,
+ )
} else {
self.sent_full = true;
- // We must make a clone to put in the TX
- // queue; this allows us to keep the
- // original below to use with the next
- // diff.
ccfw.clone()
};
queue_send_func!(self.to_client_tx.send(EditorMessage {
@@ -918,15 +892,16 @@ impl TranslationTask {
// Update to the latest code after
// computing diffs. To avoid ownership
// problems, re-define `ccfw_source_plain`.
- let CodeMirrorDiffable::Plain(ccfw_source_plain) =
- ccfw.source
+ let CodeMirrorDiffable::Plain(
+ code_mirror_translated,
+ ) = ccfw.source
else {
panic!("{}", "Unexpected diff value.");
};
self.source_code = code_mirror.doc;
- self.code_mirror_doc = ccfw_source_plain.doc;
+ self.code_mirror_doc = code_mirror_translated.doc;
self.code_mirror_doc_blocks =
- Some(ccfw_source_plain.doc_blocks);
+ Some(code_mirror_translated.doc_blocks);
// Update to the version of the file just sent.
self.version = contents.version;
Ok(ResultOkTypes::Void)
@@ -983,6 +958,32 @@ impl TranslationTask {
true
}
+ /// Given contents translated from `ccfw` to `code_mirror_translated`, return a `CodeChatForWeb` with these translated contents, using a diff.
+ fn wrap_translation(
+ &self,
+ ccfw: &CodeChatForWeb,
+ code_mirror_translated: &CodeMirror,
+ ) -> CodeChatForWeb {
+ assert!(self.sent_full);
+ let doc_diff = diff_str(&self.code_mirror_doc, &code_mirror_translated.doc);
+ let Some(ref cmdb) = self.code_mirror_doc_blocks else {
+ panic!("Should have diff of doc blocks!");
+ };
+ let doc_blocks_diff = diff_code_mirror_doc_blocks(cmdb, &code_mirror_translated.doc_blocks);
+ CodeChatForWeb {
+ // Clone needed here, so we can copy it
+ // later.
+ metadata: ccfw.metadata.clone(),
+ source: CodeMirrorDiffable::Diff(CodeMirrorDiff {
+ doc: doc_diff,
+ doc_blocks: doc_blocks_diff,
+ // The diff was made between the current version (`version`) and the new version (`contents.version`).
+ version: self.version,
+ }),
+ version: ccfw.version,
+ }
+ }
+
async fn client_update(&mut self, client_message: EditorMessage) -> bool {
let EditorMessageContents::Update(update_message_contents) = client_message.message else {
panic!("Expected update message.");
@@ -1000,6 +1001,34 @@ impl TranslationTask {
None => None,
Some(cfw) => match codechat_for_web_to_source(&cfw) {
Ok(new_source_code) => {
+ // Translate back to the Client to see if there are any changes after this conversion.
+ if let Ok(ccfws) = source_to_codechat_for_web_string(
+ &new_source_code,
+ &clean_file_path,
+ cfw.version,
+ false,
+ ) && let TranslationResultsString::CodeChat(ref ccfw) = ccfws.0
+ && let CodeMirrorDiffable::Plain(ref code_mirror_translated) =
+ ccfw.source
+ && self.sent_full
+ {
+ // Compute the diff.
+ let ccfw_client_diff =
+ self.wrap_translation(ccfw, code_mirror_translated);
+ let CodeMirrorDiffable::Diff(client_contents) =
+ ccfw_client_diff.source
+ else {
+ panic!("Expected diff.");
+ };
+ if !client_contents.doc.is_empty()
+ || !client_contents.doc_blocks.is_empty()
+ {
+ // Translating back to the client produced a non-empty diff. Send this to the client.
+ println!(
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ );
+ }
+ };
// Correct EOL endings for use with the
// IDE.
let new_source_code_eol = eol_convert(new_source_code, &self.eol);
@@ -1035,10 +1064,7 @@ impl TranslationTask {
panic!("Diff not supported.");
};
self.code_mirror_doc = cmd.doc;
- // TODO: instead of `cmd.doc_blocks`, use
- // `None` to indicate that the doc blocks
- // contain Markdown instead of HTML.
- self.code_mirror_doc_blocks = None;
+ self.code_mirror_doc_blocks = Some(cmd.doc_blocks);
ccfw
}
Err(message) => {
diff --git a/server/tests/fixtures/overall/overall_core/test_client_updates/test.py b/server/tests/fixtures/overall/overall_core/test_client_updates/test.py
index 9d935e6c..23103ab8 100644
--- a/server/tests/fixtures/overall/overall_core/test_client_updates/test.py
+++ b/server/tests/fixtures/overall/overall_core/test_client_updates/test.py
@@ -1,4 +1,3 @@
-# Test updates in the client that modify the client after appending to a line.
-def foo():
- A comment
- print()
\ No newline at end of file
+# 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_core/mod.rs b/server/tests/overall_core/mod.rs
index e5ff21be..349999be 100644
--- a/server/tests/overall_core/mod.rs
+++ b/server/tests/overall_core/mod.rs
@@ -60,6 +60,7 @@ use std::{
use assert_fs::TempDir;
use dunce::canonicalize;
use futures::FutureExt;
+use indoc::indoc;
use pretty_assertions::assert_eq;
use thirtyfour::{
By, ChromiumLikeCapabilities, DesiredCapabilities, Key, WebDriver, error::WebDriverError,
@@ -1035,7 +1036,6 @@ async fn test_client_core(
Ok(())
}
-/* TODO: fails until self-updates work.
mod test3 {
use super::*;
use pretty_assertions::assert_eq;
@@ -1084,8 +1084,23 @@ async fn test_client_updates_core(
.await;
// Respond to the load request.
+ let ide_version = 0.0;
codechat_server
- .send_result_loadfile(server_id, None)
+ .send_result_loadfile(
+ server_id,
+ Some((
+ indoc!(
+ "
+ # Test updates in the client that modify the client after appending to a line.
+ def foo():
+ A comment
+ print()
+ "
+ )
+ .to_string(),
+ ide_version,
+ )),
+ )
.await
.unwrap();
@@ -1132,9 +1147,11 @@ async fn test_client_updates_core(
.unwrap();
// Verify the updated text.
+ let msg = codechat_server.get_message_timeout(TIMEOUT).await.unwrap();
+ let client_version = get_version(&msg);
let mut client_id = INITIAL_CLIENT_MESSAGE_ID;
assert_eq!(
- codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
+ msg,
EditorMessage {
id: client_id,
message: EditorMessageContents::Update(UpdateMessageContents {
@@ -1149,19 +1166,18 @@ async fn test_client_updates_core(
to: None,
insert: "# testing\n".to_string()
}],
- doc_blocks: vec![]
- })
+ doc_blocks: vec![],
+ version: ide_version,
+ }),
+ version: client_version,
}),
cursor_position: Some(1),
- scroll_position: Some(0.0)
+ scroll_position: Some(1.0)
})
}
);
codechat_server.send_result(client_id, None).await.unwrap();
- // Move the cursor to code, then check that the position is correct. TODO:
- // need access to codemirror in test mode.
-
// Insert a character to check the insertion point.
let code_line_css = ".CodeChat-CodeMirror .cm-line";
let code_line = driver_ref.find(By::Css(code_line_css)).await.unwrap();
@@ -1181,9 +1197,11 @@ async fn test_client_updates_core(
code_line.send_keys(Key::Home + "# ").await.unwrap();
// This should edit the (new) third line of the file after word wrap: `def
// foo():`.
+ let msg = codechat_server.get_message_timeout(TIMEOUT).await.unwrap();
+ let new_client_version = get_version(&msg);
client_id += MESSAGE_ID_INCREMENT;
assert_eq!(
- codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
+ msg,
EditorMessage {
id: client_id,
message: EditorMessageContents::Update(UpdateMessageContents {
@@ -1198,11 +1216,13 @@ async fn test_client_updates_core(
to: Some(131),
insert: " # A comment\n".to_string()
}],
- doc_blocks: vec![]
- })
+ doc_blocks: vec![],
+ version: client_version,
+ }),
+ version: new_client_version,
}),
cursor_position: Some(4),
- scroll_position: Some(0.0)
+ scroll_position: Some(1.0)
})
}
);
@@ -1210,4 +1230,3 @@ async fn test_client_updates_core(
Ok(())
}
- */
From 44994a843af4c5dfdc5b4b708fabe68f65b35c92 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Tue, 2 Dec 2025 17:03:25 -0600
Subject: [PATCH 20/38] wip: translate update
---
server/src/translation.rs | 172 +++++++++++++++++++++++++++++---------
1 file changed, 131 insertions(+), 41 deletions(-)
diff --git a/server/src/translation.rs b/server/src/translation.rs
index 61ef56db..7e544285 100644
--- a/server/src/translation.rs
+++ b/server/src/translation.rs
@@ -209,10 +209,13 @@ use std::{collections::HashMap, ffi::OsStr, fmt::Debug, path::PathBuf};
// ### Third-party
use lazy_static::lazy_static;
use log::{debug, error, warn};
+use rand::random;
use regex::Regex;
use tokio::sync::mpsc::{Receiver, Sender};
use tokio::{fs::File, select, sync::mpsc};
+use crate::lexer::supported_languages::MARKDOWN_MODE;
+use crate::processing::CodeMirrorDocBlockVec;
// ### Local
use crate::{
processing::{
@@ -234,7 +237,7 @@ use crate::{
// -------
//
// The max length of a message to show in the console.
-const MAX_MESSAGE_LENGTH: usize = 300;
+const MAX_MESSAGE_LENGTH: usize = 3000;
lazy_static! {
/// A regex to determine the type of the first EOL. See 'PROCESSINGS`.
@@ -872,8 +875,10 @@ impl TranslationTask {
};
// Send a diff if possible.
let client_contents = if self.sent_full {
- self.wrap_translation(
- &ccfw,
+ self.diff_code_mirror(
+ ccfw.metadata.clone(),
+ self.version,
+ ccfw.version,
code_mirror_translated,
)
} else {
@@ -958,29 +963,35 @@ impl TranslationTask {
true
}
- /// Given contents translated from `ccfw` to `code_mirror_translated`, return a `CodeChatForWeb` with these translated contents, using a diff.
- fn wrap_translation(
+ /// Return a `CodeChatForWeb` struct containing a diff between `self.code_mirror_doc` / `self.code_mirror_doc_blocks` and `code_mirror_translated`.
+ fn diff_code_mirror(
&self,
- ccfw: &CodeChatForWeb,
- code_mirror_translated: &CodeMirror,
+ // The `metadata` and `version` fields will be copied from this to the returned `CodeChatForWeb` struct.
+ metadata: SourceFileMetadata,
+ // The version number of the previous (before) data. Typically, `self.version`.
+ before_version: f64,
+ // The version number for the resulting return struct.
+ version: f64,
+ // This provides the after data for the diff; before data comes from `self.code_mirror` / `self.code_mirror_doc`.
+ code_mirror_after: &CodeMirror,
) -> CodeChatForWeb {
assert!(self.sent_full);
- let doc_diff = diff_str(&self.code_mirror_doc, &code_mirror_translated.doc);
+ let doc_diff = diff_str(&self.code_mirror_doc, &code_mirror_after.doc);
let Some(ref cmdb) = self.code_mirror_doc_blocks else {
panic!("Should have diff of doc blocks!");
};
- let doc_blocks_diff = diff_code_mirror_doc_blocks(cmdb, &code_mirror_translated.doc_blocks);
+ let doc_blocks_diff = diff_code_mirror_doc_blocks(cmdb, &code_mirror_after.doc_blocks);
CodeChatForWeb {
// Clone needed here, so we can copy it
// later.
- metadata: ccfw.metadata.clone(),
+ metadata,
source: CodeMirrorDiffable::Diff(CodeMirrorDiff {
doc: doc_diff,
doc_blocks: doc_blocks_diff,
- // The diff was made between the current version (`version`) and the new version (`contents.version`).
- version: self.version,
+ // The diff was made between the before version (this) and the after version (`ccfw.version`).
+ version: before_version,
}),
- version: ccfw.version,
+ version,
}
}
@@ -1001,32 +1012,64 @@ impl TranslationTask {
None => None,
Some(cfw) => match codechat_for_web_to_source(&cfw) {
Ok(new_source_code) => {
- // Translate back to the Client to see if there are any changes after this conversion.
- if let Ok(ccfws) = source_to_codechat_for_web_string(
- &new_source_code,
- &clean_file_path,
- cfw.version,
- false,
- ) && let TranslationResultsString::CodeChat(ref ccfw) = ccfws.0
+ // Update the stored CodeMirror data structures with what we just received. This must be updated before we can translate back to check for changes (the next step).
+ let CodeMirrorDiffable::Plain(code_mirror) = cfw.source else {
+ // TODO: support diffable!
+ panic!("Diff not supported.");
+ };
+ let debug_cm = code_mirror.clone();
+ self.code_mirror_doc = code_mirror.doc;
+ self.code_mirror_doc_blocks = Some(code_mirror.doc_blocks);
+ // We may need to change this version if we send a diff back to the Client.
+ let mut cfw_version = cfw.version;
+
+ // Translate back to the Client to see if there are any changes after this conversion. Only check CodeChat documents, not Markdown docs.
+ if cfw.metadata.mode != MARKDOWN_MODE
+ && let Ok(ccfws) = source_to_codechat_for_web_string(
+ &new_source_code,
+ &clean_file_path,
+ cfw.version,
+ false,
+ )
+ && let TranslationResultsString::CodeChat(ccfw) = ccfws.0
&& let CodeMirrorDiffable::Plain(ref code_mirror_translated) =
ccfw.source
&& self.sent_full
{
- // Compute the diff.
- let ccfw_client_diff =
- self.wrap_translation(ccfw, code_mirror_translated);
- let CodeMirrorDiffable::Diff(client_contents) =
- ccfw_client_diff.source
- else {
- panic!("Expected diff.");
- };
- if !client_contents.doc.is_empty()
- || !client_contents.doc_blocks.is_empty()
+ // Determine if the re-translation includes changes (such as line wrapping in doc blocks which changes line numbering, creation of a new doc block from previous code block text, or updates from future document intelligence such as renamed headings, etc.) For doc blocks that haven't been edited by TinyMCE, this is easy; equality is sufficient. Doc blocks that have been edited are a different case: TinyMCE removes newlines, causing a lot of "changes" to re-insert these. Therefore, use the following approach:
+ //
+ // 1. Compare the `doc` values. If they differ, then the the Client needs an update.
+ // 2. Compare each code block using simple equality. If this fails, compare the doc block text excluding newlines. If still different, then the Client needs an update.
+ if code_mirror_translated.doc != self.code_mirror_doc
+ || !doc_block_compare(
+ &code_mirror_translated.doc_blocks,
+ self.code_mirror_doc_blocks.as_ref().unwrap(),
+ )
{
- // Translating back to the client produced a non-empty diff. Send this to the client.
+ cfw_version = random();
+ // The Client needs an update.
+ let client_contents = self.diff_code_mirror(
+ cfw.metadata.clone(),
+ cfw.version,
+ cfw_version,
+ code_mirror_translated,
+ );
println!(
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "Sending client re-translation update:\nBefore:\n{debug_cm:#?}\nAfter:\n{code_mirror_translated:#?}\nDiff:\n{client_contents:#?}"
);
+ queue_send_func!(self.to_client_tx.send(EditorMessage {
+ id: self.id,
+ message: EditorMessageContents::Update(
+ UpdateMessageContents {
+ file_path: update_message_contents.file_path,
+ contents: Some(client_contents),
+ // Don't change the current position, since the Client editing position should be left undisturbed.
+ cursor_position: None,
+ scroll_position: None
+ }
+ )
+ }));
+ self.id += MESSAGE_ID_INCREMENT;
}
};
// Correct EOL endings for use with the
@@ -1043,7 +1086,7 @@ impl TranslationTask {
doc_blocks: vec![],
version: self.version,
}),
- version: cfw.version,
+ version: cfw_version,
})
} else {
Some(CodeChatForWeb {
@@ -1054,17 +1097,11 @@ impl TranslationTask {
doc: new_source_code_eol.clone(),
doc_blocks: vec![],
}),
- version: cfw.version,
+ version: cfw_version,
})
};
- self.version = cfw.version;
+ self.version = cfw_version;
self.source_code = new_source_code_eol;
- let CodeMirrorDiffable::Plain(cmd) = cfw.source else {
- // TODO: support diffable!
- panic!("Diff not supported.");
- };
- self.code_mirror_doc = cmd.doc;
- self.code_mirror_doc_blocks = Some(cmd.doc_blocks);
ccfw
}
Err(message) => {
@@ -1101,6 +1138,33 @@ fn eol_convert(s: String, eol_type: &EolType) -> String {
}
}
+// Given a vector of two doc blocks, compare them, ignoring newlines.
+fn doc_block_compare(a: &CodeMirrorDocBlockVec, b: &CodeMirrorDocBlockVec) -> bool {
+ if a.len() != b.len() {
+ return false;
+ }
+
+ a.iter().zip(b).all(|el| {
+ let a = el.0;
+ let b = el.1;
+ a.from == b.from
+ && a.to == b.to
+ && a.indent == b.indent
+ && a.delimiter == b.delimiter
+ && (a.contents == b.contents
+ // TinyMCE replaces newlines inside paragraphs with a space; for a crude comparison, translate all newlines back to spaces, then ignore leading/trailing newlines.
+ || map_newlines_to_spaces(&a.contents).eq(map_newlines_to_spaces(&b.contents)))
+ })
+}
+
+fn map_newlines_to_spaces<'a>(
+ s: &'a str,
+) -> std::iter::Map, impl FnMut(char) -> char> {
+ s.trim()
+ .chars()
+ .map(|c: char| if c == '\n' { ' ' } else { c })
+}
+
// Provide a simple debug function that prints only the first
// `MAX_MESSAGE_LENGTH` characters of the provided value.
fn debug_shorten(val: T) -> String {
@@ -1116,3 +1180,29 @@ fn debug_shorten(val: T) -> String {
"".to_string()
}
}
+
+// Tests
+// -----
+#[cfg(test)]
+mod tests {
+ use crate::{processing::CodeMirrorDocBlock, translation::doc_block_compare};
+
+ #[test]
+ fn test_x1() {
+ let before = vec![CodeMirrorDocBlock {
+ from: 0,
+ to: 20,
+ indent: "".to_string(),
+ delimiter: "//".to_string(),
+ contents: "Copyright (C) 2025 Bryan A. Jones.
\nThis 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.
\nThe 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.
\nYou should have received a copy of the GNU General Public License along with the CodeChat Editor. If not, see http://www.gnu.org/licenses.
\ndebug_enable.mts -- Configure debug features
\nTrue to enable additional debug logging.
".to_string(),
+ }];
+ let after = vec![CodeMirrorDocBlock {
+ from: 0,
+ to: 20,
+ indent: "".to_string(),
+ delimiter: "//".to_string(),
+ contents: "Copyright (C) 2025 Bryan A. Jones.
\nThis file is part of the CodeChat Editor. The CodeChat Editor is free\nsoftware: you can redistribute it and/or modify it under the terms of the GNU\nGeneral Public License as published by the Free Software Foundation, either\nversion 3 of the License, or (at your option) any later version.
\nThe CodeChat Editor is distributed in the hope that it will be useful, but\nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\nFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more\ndetails.
\nYou should have received a copy of the GNU General Public License along with\nthe CodeChat Editor. If not, see\nhttp://www.gnu.org/licenses.
\ndebug_enable.mts -- Configure debug features
\nTrue to enable additional debug logging.
\n".to_string(),
+ }];
+ assert!(doc_block_compare(&before, &after));
+ }
+}
From 951450c529863272598d1edba286a22b095a05a7 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Tue, 2 Dec 2025 22:05:36 -0600
Subject: [PATCH 21/38] Clean: use constants where possible.
---
client/src/CodeChatEditor.mts | 4 ++--
client/src/shared_types.mts | 2 ++
extensions/VSCode/src/extension.ts | 5 +++--
server/src/ide/vscode.rs | 2 +-
server/src/lexer/supported_languages.rs | 4 +++-
server/src/processing.rs | 9 ++++++---
server/src/processing/tests.rs | 9 ++++++---
server/tests/overall_core/mod.rs | 2 +-
8 files changed, 24 insertions(+), 13 deletions(-)
diff --git a/client/src/CodeChatEditor.mts b/client/src/CodeChatEditor.mts
index c220b7ca..40bc0852 100644
--- a/client/src/CodeChatEditor.mts
+++ b/client/src/CodeChatEditor.mts
@@ -66,10 +66,10 @@ import "graphviz-webcomponent";
import { tinymce, init, Editor } from "./tinymce-config.mjs";
import {
CodeChatForWeb,
- CodeMirrorDocBlockTuple,
CodeMirrorDiffable,
UpdateMessageContents,
CodeMirror,
+ autosave_timeout_ms,
} from "./shared_types.mjs";
import { show_toast } from "./show_toast.mjs";
@@ -400,7 +400,7 @@ export const startAutosaveTimer = () => {
autosaveTimeoutId = window.setTimeout(() => {
console_log("CodeChat Editor Client: autosaving.");
on_save();
- }, 1000);
+ }, autosave_timeout_ms);
};
const clearAutosaveTimer = () => {
diff --git a/client/src/shared_types.mts b/client/src/shared_types.mts
index a532eca1..a80f0754 100644
--- a/client/src/shared_types.mts
+++ b/client/src/shared_types.mts
@@ -16,6 +16,8 @@
//
// `shared_types.mts` -- Shared type definitions
// =============================================
+// The time, in ms, to wait between the last user edit and sending updated data to the Server.
+export const autosave_timeout_ms = 300;
//
// ### Message types
//
diff --git a/extensions/VSCode/src/extension.ts b/extensions/VSCode/src/extension.ts
index e7dbc1da..65e67cbb 100644
--- a/extensions/VSCode/src/extension.ts
+++ b/extensions/VSCode/src/extension.ts
@@ -40,6 +40,7 @@ import { CodeChatEditorServer, initServer } from "./index";
// ### Local packages
import {
+ autosave_timeout_ms,
EditorMessage,
MessageResult,
UpdateMessageContents,
@@ -600,7 +601,7 @@ const send_update = (this_is_dirty: boolean) => {
if (idle_timer !== undefined) {
clearTimeout(idle_timer);
}
- // ... schedule a render after 300 ms.
+ // ... schedule a render after an autosave timeout.
idle_timer = setTimeout(async () => {
if (can_render()) {
const ate = vscode.window.activeTextEditor!;
@@ -648,7 +649,7 @@ const send_update = (this_is_dirty: boolean) => {
scroll_position,
);
}
- }, 300);
+ }, autosave_timeout_ms);
}
};
diff --git a/server/src/ide/vscode.rs b/server/src/ide/vscode.rs
index e0bf4ee0..18b378ec 100644
--- a/server/src/ide/vscode.rs
+++ b/server/src/ide/vscode.rs
@@ -183,7 +183,7 @@ pub fn vscode_ide_core(
// Make sure it's the `Result` message with no errors.
let res =
// First, make sure the ID matches.
- if message.id != 0.0 {
+ if message.id != RESERVED_MESSAGE_ID {
Err(format!("Unexpected message ID {}.", message.id))
} else {
match message.message {
diff --git a/server/src/lexer/supported_languages.rs b/server/src/lexer/supported_languages.rs
index f8450a9a..3949a6b1 100644
--- a/server/src/lexer/supported_languages.rs
+++ b/server/src/lexer/supported_languages.rs
@@ -56,6 +56,8 @@ use super::{
StringDelimiterSpec, pest_parser,
};
+pub const MARKDOWN_MODE: &str = "markdown";
+
// Helper functions
// -----------------------------------------------------------------------------
//
@@ -543,7 +545,7 @@ pub fn get_language_lexer_vec() -> Vec {
),
// ### Markdown
make_language_lexer(
- "markdown",
+ MARKDOWN_MODE,
&["md"],
&[],
&[],
diff --git a/server/src/processing.rs b/server/src/processing.rs
index 4b69ec70..1bd0b633 100644
--- a/server/src/processing.rs
+++ b/server/src/processing.rs
@@ -59,7 +59,10 @@ use serde::{Deserialize, Serialize};
use ts_rs::TS;
// ### Local
-use crate::lexer::{CodeDocBlock, DocBlock, LEXERS, LanguageLexerCompiled, source_lexer};
+use crate::lexer::{
+ CodeDocBlock, DocBlock, LEXERS, LanguageLexerCompiled, source_lexer,
+ supported_languages::MARKDOWN_MODE,
+};
// Data structures
// -----------------------------------------------------------------------------
@@ -426,7 +429,7 @@ pub fn codechat_for_web_to_source(
};
// If this is a Markdown-only document, handle this special case.
- if *lexer.language_lexer.lexer_name == "markdown" {
+ if *lexer.language_lexer.lexer_name == MARKDOWN_MODE {
// There should be no doc blocks.
if !code_mirror.doc_blocks.is_empty() {
return Err(CodechatForWebToSourceError::DocBlocksNotAllowed);
@@ -802,7 +805,7 @@ pub fn source_to_codechat_for_web(
mode: lexer.language_lexer.lexer_name.to_string(),
},
version,
- source: if lexer.language_lexer.lexer_name.as_str() == "markdown" {
+ source: if lexer.language_lexer.lexer_name.as_str() == MARKDOWN_MODE {
// Document-only files are easy: just encode the contents.
let html = markdown_to_html(file_contents);
// TODO: process the HTML.
diff --git a/server/src/processing/tests.rs b/server/src/processing/tests.rs
index cda3396a..c5f9c0c2 100644
--- a/server/src/processing/tests.rs
+++ b/server/src/processing/tests.rs
@@ -34,7 +34,10 @@ use super::{
};
use crate::{
cast,
- lexer::{CodeDocBlock, DocBlock, compile_lexers, supported_languages::get_language_lexer_vec},
+ lexer::{
+ CodeDocBlock, DocBlock, compile_lexers,
+ supported_languages::{MARKDOWN_MODE, get_language_lexer_vec},
+ },
prep_test_dir,
processing::{
CodeDocBlockVecToSourceError, CodeMirrorDiffable, CodeMirrorDocBlockDelete,
@@ -510,7 +513,7 @@ fn test_source_to_codechat_for_web_1() {
assert_eq!(
source_to_codechat_for_web("", &"md".to_string(), 0.0, false, false),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
- "markdown",
+ MARKDOWN_MODE,
"",
vec![]
)))
@@ -526,7 +529,7 @@ fn test_source_to_codechat_for_web_1() {
false,
),
Ok(TranslationResults::CodeChat(build_codechat_for_web(
- "markdown",
+ MARKDOWN_MODE,
&format!("{lexer_spec}markdown
\n"),
vec![]
)))
diff --git a/server/tests/overall_core/mod.rs b/server/tests/overall_core/mod.rs
index 349999be..240da8df 100644
--- a/server/tests/overall_core/mod.rs
+++ b/server/tests/overall_core/mod.rs
@@ -678,7 +678,7 @@ async fn test_server_core(
file_path: md_path_str.clone(),
contents: Some(CodeChatForWeb {
metadata: SourceFileMetadata {
- mode: "markdown".to_string()
+ mode: MARKDOWN_MODE.to_string()
},
source: CodeMirrorDiffable::Diff(CodeMirrorDiff {
doc: vec![StringDiff {
From 126d269e2a96977d074a8c1113adb25ffb79fbfd Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Tue, 2 Dec 2025 22:06:19 -0600
Subject: [PATCH 22/38] Fix: add missing awaits. Better error reporting.
Fix sendResult.
---
client/src/CodeChatEditorFramework.mts | 3 ++
extensions/VSCode/src/extension.ts | 46 ++++++++++++++++----------
2 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/client/src/CodeChatEditorFramework.mts b/client/src/CodeChatEditorFramework.mts
index a202b39c..43f26b8e 100644
--- a/client/src/CodeChatEditorFramework.mts
+++ b/client/src/CodeChatEditorFramework.mts
@@ -170,6 +170,9 @@ class WebSocketComm {
contents.source.Diff.version !==
this.version
) {
+ report_error(
+ `Out of sync: Client version ${this.version} !== incoming version ${contents.source.Diff.version}.`,
+ );
this.send_result(id, "OutOfSync");
return;
}
diff --git a/extensions/VSCode/src/extension.ts b/extensions/VSCode/src/extension.ts
index 65e67cbb..20d0295d 100644
--- a/extensions/VSCode/src/extension.ts
+++ b/extensions/VSCode/src/extension.ts
@@ -327,7 +327,7 @@ export const activate = (context: vscode.ExtensionContext) => {
value as UpdateMessageContents;
const doc = get_document(current_update.file_path);
if (doc === undefined) {
- sendResult(id, {
+ await sendResult(id, {
NoOpenDocument: current_update.file_path,
});
break;
@@ -358,7 +358,7 @@ export const activate = (context: vscode.ExtensionContext) => {
assert("Diff" in source);
// If this diff was not made against the text we currently have, reject it.
if (source.Diff.version !== version) {
- sendResult(id, "OutOfSync");
+ await sendResult(id, "OutOfSync");
// Send an `Update` with the full text to re-sync the Client.
send_update(true);
break;
@@ -437,7 +437,7 @@ export const activate = (context: vscode.ExtensionContext) => {
),
];
}
- sendResult(id);
+ await sendResult(id);
break;
}
@@ -452,7 +452,7 @@ export const activate = (context: vscode.ExtensionContext) => {
current_file,
);
} catch (e) {
- sendResult(id, {
+ await sendResult(id, {
OpenFileFailed: [
current_file,
(e as Error).toString(),
@@ -467,7 +467,7 @@ export const activate = (context: vscode.ExtensionContext) => {
current_editor?.viewColumn,
);
ignore_active_editor_change = false;
- sendResult(id);
+ await sendResult(id);
} else {
// TODO: open using a custom document editor.
// See
@@ -489,9 +489,9 @@ export const activate = (context: vscode.ExtensionContext) => {
},
)
.then(
- () => sendResult(id),
- (reason) =>
- sendResult(id, {
+ async () => await sendResult(id),
+ async (reason) =>
+ await sendResult(id, {
OpenFileFailed: [
current_file,
reason,
@@ -499,7 +499,7 @@ export const activate = (context: vscode.ExtensionContext) => {
}),
);
}
- sendResult(id);
+ await sendResult(id);
}
break;
}
@@ -530,7 +530,7 @@ export const activate = (context: vscode.ExtensionContext) => {
console_log(
`CodeChat Editor extension: Result(LoadFile(${format_struct(load_file_result)}))`,
);
- codeChatEditorServer.sendResultLoadfile(
+ await codeChatEditorServer.sendResultLoadfile(
id,
load_file_result,
);
@@ -541,7 +541,7 @@ export const activate = (context: vscode.ExtensionContext) => {
const client_html = value as string;
assert(webview_panel !== undefined);
webview_panel.webview.html = client_html;
- sendResult(id);
+ await sendResult(id);
// Now that the Client is loaded, send the editor's
// current file to the server.
send_update(false);
@@ -576,19 +576,27 @@ export const deactivate = async () => {
// Format a complex data structure as a string when in debug mode.
const format_struct = (complex_data_structure: any): string =>
DEBUG_ENABLED
- ? JSON.stringify(complex_data_structure).substring(
+ // If the struct is `undefined`, print an empty string.
+ ? JSON.stringify(complex_data_structure ?? "").substring(
0,
MAX_MESSAGE_LENGTH,
)
: "";
// Send a result (a response to a message from the server) back to the server.
-const sendResult = (id: number, result: ResultErrTypes | null = null) => {
+const sendResult = async (id: number, result?: ResultErrTypes) => {
assert(codeChatEditorServer);
console_log(
`CodeChat Editor extension: sending Result(id = ${id}, ${format_struct(result)}).`,
);
- codeChatEditorServer.sendResult(id, JSON.stringify(result));
+ try {
+ await codeChatEditorServer.sendResult(
+ id,
+ result === undefined ? undefined : JSON.stringify(result),
+ );
+ } catch (e) {
+ show_error(`Error in sendResult for id ${id}: ${e}.`);
+ }
};
// This is called after an event such as an edit, when the CodeChat panel
@@ -614,9 +622,13 @@ const send_update = (this_is_dirty: boolean) => {
console_log(
`CodeChat Editor extension: sending CurrentFile(${current_file}}).`,
);
- await codeChatEditorServer!.sendMessageCurrentFile(
- current_file,
- );
+ try {
+ await codeChatEditorServer!.sendMessageCurrentFile(
+ current_file,
+ );
+ } catch (e) {
+ show_error(`Error sending CurrentFile message: ${e}.`);
+ }
// Since we just requested a new file, the contents are
// clean by definition.
is_dirty = false;
From ed662cf83eae4689aff54907f49791fd66e070fb Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Tue, 2 Dec 2025 22:07:35 -0600
Subject: [PATCH 23/38] Clean: imports in integration tests.
---
server/tests/overall_core/mod.rs | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/server/tests/overall_core/mod.rs b/server/tests/overall_core/mod.rs
index 240da8df..3cc715c5 100644
--- a/server/tests/overall_core/mod.rs
+++ b/server/tests/overall_core/mod.rs
@@ -72,10 +72,10 @@ use tokio::time::sleep;
use code_chat_editor::{
cast,
ide::CodeChatEditorServer,
+ lexer::supported_languages::MARKDOWN_MODE,
prep_test_dir,
processing::{
- CodeChatForWeb, CodeMirror, CodeMirrorDiff, CodeMirrorDiffable, SourceFileMetadata,
- StringDiff,
+ CodeChatForWeb, CodeMirrorDiff, CodeMirrorDiffable, SourceFileMetadata, StringDiff,
},
webserver::{
EditorMessage, EditorMessageContents, INITIAL_CLIENT_MESSAGE_ID, MESSAGE_ID_INCREMENT,
@@ -193,7 +193,7 @@ macro_rules! harness {
// Get the resulting web page text.
let opened_id = codechat_server.send_message_opened(true).await.unwrap();
- assert_eq!(
+ pretty_assertions::assert_eq!(
codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
EditorMessage {
id: opened_id,
@@ -259,7 +259,6 @@ fn get_version(msg: &EditorMessage) -> f64 {
// CodeChat, plain, PDF), use hyperlinks, perform edits on code and doc blocks.
mod test1 {
use super::*;
- use pretty_assertions::assert_eq;
harness!(test_server_core);
}
@@ -888,7 +887,6 @@ async fn test_server_core(
// all pass.
mod test2 {
use super::*;
- use pretty_assertions::assert_eq;
harness!(test_client_core);
}
@@ -1038,7 +1036,6 @@ async fn test_client_core(
mod test3 {
use super::*;
- use pretty_assertions::assert_eq;
harness!(test_client_updates_core);
}
From fde9b8e7264c72e25c1de15500732eccdbc25596 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Tue, 2 Dec 2025 22:08:53 -0600
Subject: [PATCH 24/38] Fix: correctly break update cycle.
---
client/src/CodeMirror-integration.mts | 56 ++++++++++++++++-----------
1 file changed, 34 insertions(+), 22 deletions(-)
diff --git a/client/src/CodeMirror-integration.mts b/client/src/CodeMirror-integration.mts
index 1eb6892e..08070e34 100644
--- a/client/src/CodeMirror-integration.mts
+++ b/client/src/CodeMirror-integration.mts
@@ -62,6 +62,7 @@ import {
} from "@codemirror/view";
import {
ChangeDesc,
+ Compartment,
EditorState,
Extension,
StateField,
@@ -101,14 +102,22 @@ import { show_toast } from "./show_toast.mjs";
// -----------------------------------------------------------------------------
let current_view: EditorView;
let tinymce_singleton: Editor | undefined;
-// When true, don't update on the next call to `on_dirty`. See that function for
-// more info.
-let ignore_next_dirty = false;
+// When true, this is an IDE edit; when false, it's due to a user edit.
+//
+// There's an inherent cycle produced by edits; this variable breaks the cycle. There are two paths through the cycle: a user edit and an IDE edit. The cycle must be broken just before it loops in both cases; this variable therefore specifies where to break the cycle. The sequence is:
+//
+// 1. The user performs an edit **or** `DocBlockWidget.updateDom()` is called; if `is_ide_change` is false, this function returns; otherwise, it performs an edit.
+// 2. The `addEventListener("input")` for an indent or `TinyMCE.editor.on("Dirty")` callback is triggered, invoking `on_dirty()`.
+// 3. An IDE edit dispatches an `add/delete/updateDocBlock` **or** in `on_dirty()`, if `is_ide_change` is true, `on_dirty()` sets it to false then returns. Otherwise, `on_dirty()` dispatches `updateDocBlock`.
+// 5. This transaction invokes `docBlockField.update()`, which creates a `new DocBlockWidget()`. This loops back to step 1.
+let is_ide_change = false;
// This indicates that a call to `on_dirty` is scheduled, but hasn't run yet.
let on_dirty_scheduled = false;
// True to ignore the next text selection change, since updates to the cursor or
// scroll position from the Client trigged this change.
let ignore_selection_change = false;
+// The compartment used to enable and disable the autosave extension.
+const autosaveCompartment = new Compartment();
// Options used when creating a `Decoration`.
const decorationOptions = {
@@ -417,9 +426,9 @@ class DocBlockWidget extends WidgetType {
eq(other: DocBlockWidget) {
return (
- other.indent == this.indent &&
- other.delimiter == this.delimiter &&
- other.contents == this.contents
+ other.indent === this.indent &&
+ other.delimiter === this.delimiter &&
+ other.contents === this.contents
);
}
@@ -448,11 +457,8 @@ 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 {
- // See if this update was produced by a change in TinyMCE text, which
- // means the DOM is already updated.
- if ((dom as any).update_complete === true) {
- // Yes, so clear this update flag before returning.
- delete (dom as any).update_complete;
+ // If this change was produced by a user edit, then the DOM was already updated. Stop here.
+ if (!is_ide_change) {
return true;
}
(dom.childNodes[0] as HTMLDivElement).innerHTML = this.indent;
@@ -462,9 +468,11 @@ class DocBlockWidget extends WidgetType {
const [contents_div, is_tinymce] = get_contents(dom);
window.MathJax.typesetClear(contents_div);
if (is_tinymce) {
- ignore_next_dirty = true;
+ // Save the cursor location before the update, then restore it afterwards.
+ const bm = tinymce.activeEditor!.selection.getBookmark();
tinymce_singleton!.setContent(this.contents);
tinymce_singleton!.save();
+ tinymce.activeEditor!.selection.moveToBookmark(bm);
} else {
contents_div.innerHTML = this.contents;
}
@@ -568,14 +576,16 @@ const on_dirty = (
// The div that's dirty. It must be a child of the doc block div.
event_target: HTMLElement,
) => {
- if (ignore_next_dirty) {
- ignore_next_dirty = false;
+ // If this change was produced by an IDE edit, then the underlying state is updated. Stop here.
+ if (is_ide_change) {
+ is_ide_change = false;
return;
}
if (on_dirty_scheduled) {
return;
}
+ on_dirty_scheduled = true;
// Only run this after typesetting is done.
window.MathJax.whenReady(() => {
@@ -605,11 +615,6 @@ const on_dirty = (
: contents_div.innerHTML;
// Although this is async, nothing following this call depends on its completion.
mathJaxTypeset(contents_div);
- // Sorta ugly hack: TinyMCE stores its data in the DOM. CodeMirror stores
- // state in external structs. We need to update the CodeMirror state, but
- // not overwrite the DOM with this "new" state, since the DOM is already
- // updated. So, signal that this "update" is already done.
- (target as any).update_complete = true;
let effects: StateEffect[] = [
updateDocBlock.of({
from,
@@ -817,7 +822,7 @@ export const DocBlockPlugin = ViewPlugin.fromClass(
// Setting the content makes TinyMCE consider it dirty
// -- ignore this "dirty" event.
- ignore_next_dirty = true;
+ is_ide_change = true;
tinymce_singleton!.setContent(contents_div.innerHTML);
tinymce_singleton!.save();
contents_div.remove();
@@ -1039,7 +1044,7 @@ export const CodeMirror_load = async (
parser,
basicSetup,
EditorView.lineWrapping,
- autosaveExtension,
+ autosaveCompartment.of(autosaveExtension),
// Make tab an indent per the
// [docs](https://codemirror.net/examples/tab/). TODO:
// document a way to escape the tab key per the same docs.
@@ -1080,12 +1085,14 @@ export const CodeMirror_load = async (
return false;
}
// For some reason, calling this directly omits the most recent edit. Earlier versions of the code didn't have this problem. ???
- setTimeout(() => on_dirty(target_or_false));
+ on_dirty(target_or_false);
});
},
})
)[0];
} else {
+ // Disable autosave when performing these updates.
+ current_view.dispatch({ effects: autosaveCompartment.reconfigure([]) });
// This contains a diff, instead of plain text. Apply the text diff.
//
// First, apply just the text edits. Use an annotation so that the doc
@@ -1121,7 +1128,12 @@ export const CodeMirror_load = async (
}
}
// Update the view with these changes to the state.
+ is_ide_change = true;
current_view.dispatch({ effects: stateEffects });
+ // Resume autosave.
+ current_view.dispatch({
+ effects: autosaveCompartment.reconfigure(autosaveExtension),
+ });
}
scroll_to_line(cursor_line, scroll_line);
};
From 60eb82f52121df86276269bca6b443d54c9a420d Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Wed, 3 Dec 2025 17:20:52 -0600
Subject: [PATCH 25/38] Fix: use whole numbers for version, instead of numbers
with fractional values.
---
client/src/CodeChatEditor.mts | 3 ++-
client/src/shared_types.mts | 5 ++++-
extensions/VSCode/src/extension.ts | 3 ++-
server/src/ide/filewatcher.rs | 4 ++--
server/src/translation.rs | 3 ++-
5 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/client/src/CodeChatEditor.mts b/client/src/CodeChatEditor.mts
index 40bc0852..4ba9d95c 100644
--- a/client/src/CodeChatEditor.mts
+++ b/client/src/CodeChatEditor.mts
@@ -70,6 +70,7 @@ import {
UpdateMessageContents,
CodeMirror,
autosave_timeout_ms,
+ rand,
} from "./shared_types.mjs";
import { show_toast } from "./show_toast.mjs";
@@ -348,7 +349,7 @@ const save_lp = (is_dirty: boolean) => {
update.contents = {
metadata: current_metadata,
source: code_mirror_diffable,
- version: Math.random(),
+ version: rand(),
};
}
diff --git a/client/src/shared_types.mts b/client/src/shared_types.mts
index a80f0754..acb75b55 100644
--- a/client/src/shared_types.mts
+++ b/client/src/shared_types.mts
@@ -18,7 +18,10 @@
// =============================================
// The time, in ms, to wait between the last user edit and sending updated data to the Server.
export const autosave_timeout_ms = 300;
-//
+
+// Produce a whole random number. Fractional numbers aren't consistently converted to the same number. Note that the mantissa of a JavaScript `Number` is 53 bits per the [docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#number_encoding). To be certain, also round the result.
+export const rand = () => Math.round(Math.random() * 2 ** 53);
+
// ### Message types
//
// These mirror the same definitions in the Rust webserver, so that the two can
diff --git a/extensions/VSCode/src/extension.ts b/extensions/VSCode/src/extension.ts
index 20d0295d..d5c7e6e8 100644
--- a/extensions/VSCode/src/extension.ts
+++ b/extensions/VSCode/src/extension.ts
@@ -43,6 +43,7 @@ import {
autosave_timeout_ms,
EditorMessage,
MessageResult,
+ rand,
UpdateMessageContents,
} from "../../../client/src/shared_types.mjs";
import {
@@ -648,7 +649,7 @@ const send_update = (this_is_dirty: boolean) => {
const file_path = ate.document.fileName;
// Send contents only if necessary.
const option_contents: null | [string, number] = is_dirty
- ? [ate.document.getText(), (version = Math.random())]
+ ? [ate.document.getText(), (version = rand())]
: null;
is_dirty = false;
console_log(
diff --git a/server/src/ide/filewatcher.rs b/server/src/ide/filewatcher.rs
index 7074a589..7bc05741 100644
--- a/server/src/ide/filewatcher.rs
+++ b/server/src/ide/filewatcher.rs
@@ -536,8 +536,8 @@ async fn processing_task(
doc: file_contents,
doc_blocks: vec![],
}),
- // The filewatcher doesn't store a version, since it only accepts plain (non-diff) results. Provide a version so the Client stays in sync with any diffs.
- version: random(),
+ // The filewatcher doesn't store a version, since it only accepts plain (non-diff) results. Provide a version so the Client stays in sync with any diffs. Produce a whole number to avoid encoding difference with fractional values.
+ version: random::() as f64,
}),
cursor_position: None,
scroll_position: None,
diff --git a/server/src/translation.rs b/server/src/translation.rs
index 7e544285..9f3ad4c5 100644
--- a/server/src/translation.rs
+++ b/server/src/translation.rs
@@ -1046,7 +1046,8 @@ impl TranslationTask {
self.code_mirror_doc_blocks.as_ref().unwrap(),
)
{
- cfw_version = random();
+ // Use a whole number to avoid encoding differences with fractional values.
+ cfw_version = random::() as f64;
// The Client needs an update.
let client_contents = self.diff_code_mirror(
cfw.metadata.clone(),
From 510bad3f6d060f172467dc09baa3cc95f439653c Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Wed, 3 Dec 2025 17:22:24 -0600
Subject: [PATCH 26/38] Fix: allow external edits when the Client has focus.
---
extensions/VSCode/src/extension.ts | 27 +++++++++++++++------------
1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/extensions/VSCode/src/extension.ts b/extensions/VSCode/src/extension.ts
index d5c7e6e8..f8c658c2 100644
--- a/extensions/VSCode/src/extension.ts
+++ b/extensions/VSCode/src/extension.ts
@@ -577,11 +577,10 @@ export const deactivate = async () => {
// Format a complex data structure as a string when in debug mode.
const format_struct = (complex_data_structure: any): string =>
DEBUG_ENABLED
- // If the struct is `undefined`, print an empty string.
- ? JSON.stringify(complex_data_structure ?? "").substring(
- 0,
- MAX_MESSAGE_LENGTH,
- )
+ ? JSON.stringify(
+ // If the struct is `undefined`, print an empty string.
+ complex_data_structure ?? "",
+ ).substring(0, MAX_MESSAGE_LENGTH)
: "";
// Send a result (a response to a message from the server) back to the server.
@@ -613,8 +612,8 @@ const send_update = (this_is_dirty: boolean) => {
// ... schedule a render after an autosave timeout.
idle_timer = setTimeout(async () => {
if (can_render()) {
- const ate = vscode.window.activeTextEditor!;
- if (ate !== current_editor) {
+ const ate = vscode.window.activeTextEditor;
+ if (ate !== undefined && ate !== current_editor) {
// Send a new current file after a short delay; this allows
// the user to rapidly cycle through several editors without
// needing to reload the Client with each cycle.
@@ -644,12 +643,14 @@ const send_update = (this_is_dirty: boolean) => {
// CodeMirror
// [Text.line](https://codemirror.net/docs/ref/#state.Text.line)
// is 1-based.
- const cursor_position = ate.selection.active.line + 1;
- const scroll_position = ate.visibleRanges[0].start.line + 1;
- const file_path = ate.document.fileName;
+ const cursor_position =
+ current_editor!.selection.active.line + 1;
+ const scroll_position =
+ current_editor!.visibleRanges[0].start.line + 1;
+ const file_path = current_editor!.document.fileName;
// Send contents only if necessary.
const option_contents: null | [string, number] = is_dirty
- ? [ate.document.getText(), (version = rand())]
+ ? [current_editor!.document.getText(), (version = rand())]
: null;
is_dirty = false;
console_log(
@@ -714,8 +715,10 @@ const show_error = (message: string) => {
// client, and the webview is visible.
const can_render = () => {
return (
- vscode.window.activeTextEditor !== undefined &&
+ (vscode.window.activeTextEditor !== undefined ||
+ current_editor !== undefined) &&
codeChatEditorServer !== undefined &&
+ // TODO: I don't think these matter -- the Server is in charge of sending output to the Client.
(codechat_client_location === CodeChatEditorClientLocation.browser ||
webview_panel !== undefined)
);
From 09f79281085719b053449367bc9f22a970186096 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Wed, 3 Dec 2025 17:23:38 -0600
Subject: [PATCH 27/38] Fix: correct handling of IDE and user edits.
Correctly save and restore cursor location when updating TinyMCE text.
---
client/src/CodeMirror-integration.mts | 205 +++++++++++++-------------
1 file changed, 103 insertions(+), 102 deletions(-)
diff --git a/client/src/CodeMirror-integration.mts b/client/src/CodeMirror-integration.mts
index 08070e34..325a2717 100644
--- a/client/src/CodeMirror-integration.mts
+++ b/client/src/CodeMirror-integration.mts
@@ -102,15 +102,8 @@ import { show_toast } from "./show_toast.mjs";
// -----------------------------------------------------------------------------
let current_view: EditorView;
let tinymce_singleton: Editor | undefined;
-// When true, this is an IDE edit; when false, it's due to a user edit.
-//
-// There's an inherent cycle produced by edits; this variable breaks the cycle. There are two paths through the cycle: a user edit and an IDE edit. The cycle must be broken just before it loops in both cases; this variable therefore specifies where to break the cycle. The sequence is:
-//
-// 1. The user performs an edit **or** `DocBlockWidget.updateDom()` is called; if `is_ide_change` is false, this function returns; otherwise, it performs an edit.
-// 2. The `addEventListener("input")` for an indent or `TinyMCE.editor.on("Dirty")` callback is triggered, invoking `on_dirty()`.
-// 3. An IDE edit dispatches an `add/delete/updateDocBlock` **or** in `on_dirty()`, if `is_ide_change` is true, `on_dirty()` sets it to false then returns. Otherwise, `on_dirty()` dispatches `updateDocBlock`.
-// 5. This transaction invokes `docBlockField.update()`, which creates a `new DocBlockWidget()`. This loops back to step 1.
-let is_ide_change = false;
+// True if the change was produce by a user edit, not an IDE update.
+let is_user_change = false;
// This indicates that a call to `on_dirty` is scheduled, but hasn't run yet.
let on_dirty_scheduled = false;
// True to ignore the next text selection change, since updates to the cursor or
@@ -458,7 +451,8 @@ class DocBlockWidget extends WidgetType {
// 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. Stop here.
- if (!is_ide_change) {
+ if (is_user_change) {
+ is_user_change = false;
return true;
}
(dom.childNodes[0] as HTMLDivElement).innerHTML = this.indent;
@@ -469,10 +463,9 @@ class DocBlockWidget extends WidgetType {
window.MathJax.typesetClear(contents_div);
if (is_tinymce) {
// Save the cursor location before the update, then restore it afterwards.
- const bm = tinymce.activeEditor!.selection.getBookmark();
+ const sel = saveSelection();
tinymce_singleton!.setContent(this.contents);
- tinymce_singleton!.save();
- tinymce.activeEditor!.selection.moveToBookmark(bm);
+ restoreSelection(sel);
} else {
contents_div.innerHTML = this.contents;
}
@@ -508,6 +501,97 @@ class DocBlockWidget extends WidgetType {
}
}
+const saveSelection = () => {
+ // Changing the text inside TinyMCE causes it to loose a selection
+ // tied to a specific node. So, instead store the
+ // selection as an array of indices in the childNodes
+ // array of each element: for example, a given selection
+ // is element 10 of the root TinyMCE div's children
+ // (selecting an ol tag), element 5 of the ol's children
+ // (selecting the last li tag), element 0 of the li's
+ // children (a text node where the actual click landed;
+ // the offset in this node is placed in
+ // `selection_offset`.)
+ const sel = window.getSelection();
+ let selection_path = [];
+ const selection_offset = sel?.anchorOffset;
+ if (sel?.anchorNode) {
+ // Find a path from the selection back to the
+ // containing div.
+ for (
+ let current_node = sel.anchorNode, is_first = true;
+ // Continue until we find the div which contains
+ // the doc block contents: either it's not an
+ // element (such as a div), ...
+ current_node.nodeType !== Node.ELEMENT_NODE ||
+ // or it's not the doc block contents div.
+ !(current_node as Element).classList.contains(
+ "CodeChat-doc-contents",
+ );
+ current_node = current_node.parentNode!, is_first = false
+ ) {
+ // Store the index of this node in its' parent
+ // list of child nodes/children. Use
+ // `childNodes` on the first iteration, since
+ // the selection is often in a text node, which
+ // isn't in the `parents` list. However, using
+ // `childNodes` all the time causes trouble when
+ // reversing the selection -- sometimes, the
+ // `childNodes` change based on whether text
+ // nodes (such as a newline) are included are
+ // not after tinyMCE parses the content.
+ let p = current_node.parentNode!;
+ selection_path.unshift(
+ Array.prototype.indexOf.call(
+ is_first ? p.childNodes : p.children,
+ current_node,
+ ),
+ );
+ }
+ }
+ return { selection_path, selection_offset };
+};
+
+// Restore the selection produced by `saveSelection`.
+const restoreSelection = ({
+ selection_path,
+ selection_offset,
+}: {
+ selection_path: number[];
+ selection_offset?: number;
+}) => {
+ // Copy the selection over to TinyMCE by indexing the
+ // selection path to find the selected node.
+ if (selection_path.length && typeof selection_offset === "number") {
+ let selection_node = tinymce_singleton!.getContentAreaContainer();
+ for (
+ ;
+ selection_path.length &&
+ // If something goes wrong, bail out instead of producing exceptions.
+ selection_node !== undefined;
+ selection_node =
+ // As before, use the more-consistent
+ // `children` except for the last element,
+ // where we might be selecting a `text`
+ // node.
+ (
+ selection_path.length > 1
+ ? selection_node.children
+ : selection_node.childNodes
+ )[selection_path.shift()!]! as HTMLElement
+ );
+ // Use that to set the selection.
+ tinymce_singleton!.selection.setCursorLocation(
+ selection_node,
+ // In case of edits, avoid an offset past the end of the node.
+ Math.min(
+ selection_offset,
+ selection_node.nodeValue?.length ?? Number.MAX_VALUE,
+ ),
+ );
+ }
+};
+
// 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 (
@@ -576,11 +660,7 @@ const on_dirty = (
// The div that's dirty. It must be a child of the doc block div.
event_target: HTMLElement,
) => {
- // If this change was produced by an IDE edit, then the underlying state is updated. Stop here.
- if (is_ide_change) {
- is_ide_change = false;
- return;
- }
+ is_user_change = true;
if (on_dirty_scheduled) {
return;
@@ -589,6 +669,7 @@ const on_dirty = (
// Only run this after typesetting is done.
window.MathJax.whenReady(() => {
+ on_dirty_scheduled = false;
// Find the doc block parent div.
const target = (event_target as HTMLDivElement).closest(
".CodeChat-doc",
@@ -625,8 +706,6 @@ const on_dirty = (
];
current_view.dispatch({ effects });
-
- on_dirty_scheduled = false;
});
};
@@ -748,55 +827,8 @@ export const DocBlockPlugin = ViewPlugin.fromClass(
mathJaxUnTypeset(contents_div);
// The code which moves TinyMCE into this div disturbs
// all the nodes, which causes it to loose a selection
- // tied to a specific node. So, instead store the
- // selection as an array of indices in the childNodes
- // array of each element: for example, a given selection
- // is element 10 of the root TinyMCE div's children
- // (selecting an ol tag), element 5 of the ol's children
- // (selecting the last li tag), element 0 of the li's
- // children (a text node where the actual click landed;
- // the offset in this node is placed in
- // `selection_offset`.)
- const sel = window.getSelection();
- let selection_path = [];
- const selection_offset = sel?.anchorOffset;
- if (sel?.anchorNode) {
- // Find a path from the selection back to the
- // containing div.
- for (
- let current_node = sel.anchorNode,
- is_first = true;
- // Continue until we find the div which contains
- // the doc block contents: either it's not an
- // element (such as a div), ...
- current_node.nodeType !== Node.ELEMENT_NODE ||
- // or it's not the doc block contents div.
- !(current_node as Element).classList.contains(
- "CodeChat-doc-contents",
- );
- current_node = current_node.parentNode!,
- is_first = false
- ) {
- // Store the index of this node in its' parent
- // list of child nodes/children. Use
- // `childNodes` on the first iteration, since
- // the selection is often in a text node, which
- // isn't in the `parents` list. However, using
- // `childNodes` all the time causes trouble when
- // reversing the selection -- sometimes, the
- // `childNodes` change based on whether text
- // nodes (such as a newline) are included are
- // not after tinyMCE parses the content.
- let p = current_node.parentNode!;
- selection_path.unshift(
- Array.prototype.indexOf.call(
- is_first ? p.childNodes : p.children,
- current_node,
- ),
- );
- }
- }
-
+ // tied to a specific node.
+ const sel = saveSelection();
// With the selection saved, it's safe to replace the
// contenteditable div with the TinyMCE instance (which
// would otherwise wipe the selection).
@@ -822,9 +854,7 @@ export const DocBlockPlugin = ViewPlugin.fromClass(
// Setting the content makes TinyMCE consider it dirty
// -- ignore this "dirty" event.
- is_ide_change = true;
tinymce_singleton!.setContent(contents_div.innerHTML);
- tinymce_singleton!.save();
contents_div.remove();
// The new div is now a TinyMCE editor. Retypeset this.
mathJaxTypeset(tinymce_div);
@@ -836,34 +866,7 @@ export const DocBlockPlugin = ViewPlugin.fromClass(
// Copy the selection over to TinyMCE by indexing the
// selection path to find the selected node.
- if (
- selection_path.length &&
- typeof selection_offset === "number"
- ) {
- let selection_node =
- tinymce_singleton!.getContentAreaContainer();
- for (
- ;
- selection_path.length &&
- // If something goes wrong, bail out instead of producing exceptions.
- selection_node !== undefined;
- selection_node =
- // As before, use the more-consistent
- // `children` except for the last element,
- // where we might be selecting a `text`
- // node.
- (
- selection_path.length > 1
- ? selection_node.children
- : selection_node.childNodes
- )[selection_path.shift()!]! as HTMLElement
- );
- // Use that to set the selection.
- tinymce_singleton!.selection.setCursorLocation(
- selection_node,
- selection_offset,
- );
- }
+ restoreSelection(sel);
}, 0);
}
return false;
@@ -1084,8 +1087,7 @@ export const CodeMirror_load = async (
if (target_or_false == null) {
return false;
}
- // For some reason, calling this directly omits the most recent edit. Earlier versions of the code didn't have this problem. ???
- on_dirty(target_or_false);
+ setTimeout(() => on_dirty(target_or_false));
});
},
})
@@ -1128,7 +1130,6 @@ export const CodeMirror_load = async (
}
}
// Update the view with these changes to the state.
- is_ide_change = true;
current_view.dispatch({ effects: stateEffects });
// Resume autosave.
current_view.dispatch({
From 1d07a0df1d2d90e49f6169e12388c72efc34b175 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Wed, 3 Dec 2025 18:28:18 -0600
Subject: [PATCH 28/38] Fix: handle rapid user edits.
---
client/src/CodeMirror-integration.mts | 116 +++++++++++++++-----------
1 file changed, 65 insertions(+), 51 deletions(-)
diff --git a/client/src/CodeMirror-integration.mts b/client/src/CodeMirror-integration.mts
index 325a2717..a7e2839f 100644
--- a/client/src/CodeMirror-integration.mts
+++ b/client/src/CodeMirror-integration.mts
@@ -62,7 +62,6 @@ import {
} from "@codemirror/view";
import {
ChangeDesc,
- Compartment,
EditorState,
Extension,
StateField,
@@ -102,15 +101,8 @@ import { show_toast } from "./show_toast.mjs";
// -----------------------------------------------------------------------------
let current_view: EditorView;
let tinymce_singleton: Editor | undefined;
-// True if the change was produce by a user edit, not an IDE update.
-let is_user_change = false;
// This indicates that a call to `on_dirty` is scheduled, but hasn't run yet.
let on_dirty_scheduled = false;
-// True to ignore the next text selection change, since updates to the cursor or
-// scroll position from the Client trigged this change.
-let ignore_selection_change = false;
-// The compartment used to enable and disable the autosave extension.
-const autosaveCompartment = new Compartment();
// Options used when creating a `Decoration`.
const decorationOptions = {
@@ -124,8 +116,12 @@ declare global {
}
}
+// When this is included in a transaction, don't update from/to of doc blocks.
const docBlockFreezeAnnotation = Annotation.define();
+// When this is included in a transaction, don't send autosave scroll/cursor location updates.
+const noAutosaveAnnotation = Annotation.define();
+
// Doc blocks in CodeMirror
// -----------------------------------------------------------------------------
//
@@ -193,6 +189,7 @@ export const docBlockField = StateField.define({
effect.value.indent,
effect.value.delimiter,
effect.value.content,
+ false,
),
...decorationOptions,
}).range(effect.value.from, effect.value.to),
@@ -279,6 +276,8 @@ export const docBlockField = StateField.define({
prev.spec.widget.contents,
effect.value.contents,
),
+ // Assume this isn't a user change unless it's specified.
+ effect.value.is_user_change ?? false,
),
...decorationOptions,
}).range(from, to),
@@ -329,7 +328,12 @@ export const docBlockField = StateField.define({
contents,
]: CodeMirrorDocBlockTuple) =>
Decoration.replace({
- widget: new DocBlockWidget(indent, delimiter, contents),
+ widget: new DocBlockWidget(
+ indent,
+ delimiter,
+ contents,
+ false,
+ ),
...decorationOptions,
}).range(from, to),
),
@@ -369,6 +373,8 @@ type updateDocBlockType = {
indent?: string;
delimiter?: string;
contents: string | StringDiff[];
+ // True if this update comes from a user change, as opposed to an update received from the IDE.
+ is_user_change?: boolean;
};
// Define an update.
@@ -411,6 +417,7 @@ class DocBlockWidget extends WidgetType {
readonly indent: string,
readonly delimiter: string,
readonly contents: string,
+ readonly is_user_change: boolean,
) {
// TODO: I don't understand why I don't need to store the provided
// parameters in the object: `this.indent = indent;`, etc.
@@ -449,10 +456,10 @@ class DocBlockWidget extends WidgetType {
// [docs](https://codemirror.net/docs/ref/#view.WidgetType.updateDOM),
// "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 {
+ updateDOM(dom: HTMLElement, _view: EditorView): boolean {
// If this change was produced by a user edit, then the DOM was already updated. Stop here.
- if (is_user_change) {
- is_user_change = false;
+ if (this.is_user_change) {
+ console.log("user change -- skipping DOM update.");
return true;
}
(dom.childNodes[0] as HTMLDivElement).innerHTML = this.indent;
@@ -462,10 +469,14 @@ class DocBlockWidget extends WidgetType {
const [contents_div, is_tinymce] = get_contents(dom);
window.MathJax.typesetClear(contents_div);
if (is_tinymce) {
- // Save the cursor location before the update, then restore it afterwards.
- const sel = saveSelection();
+ // Save the cursor location before the update, then restore it afterwards, if TinyMCE has focus.
+ const sel = tinymce_singleton!.hasFocus()
+ ? saveSelection()
+ : undefined;
tinymce_singleton!.setContent(this.contents);
- restoreSelection(sel);
+ if (sel !== undefined) {
+ restoreSelection(sel);
+ }
} else {
contents_div.innerHTML = this.contents;
}
@@ -552,7 +563,7 @@ const saveSelection = () => {
return { selection_path, selection_offset };
};
-// Restore the selection produced by `saveSelection`.
+// Restore the selection produced by `saveSelection` to the active TinyMCE instance.
const restoreSelection = ({
selection_path,
selection_offset,
@@ -651,24 +662,22 @@ const element_is_in_doc_block = (
// untypeset, then the dirty ignored.
// 3. When MathJax typesets math on a TinyMCE focus out event, the dirty flag
// gets set. This should be ignored. However, typesetting is an async
-// operation, so we assume it's OK to await the typeset completion, then
-// clear the `ignore_next_dirty flag`. This will lead to nasty bugs at some
-// point.
+// operation, so we assume it's OK to await the typeset completion.
+// This will lead to nasty bugs at some point.
// 4. When an HTML doc block is assigned to the TinyMCE instance for editing,
// the dirty flag is set. This must be ignored.
const on_dirty = (
// The div that's dirty. It must be a child of the doc block div.
event_target: HTMLElement,
) => {
- is_user_change = true;
-
if (on_dirty_scheduled) {
return;
}
on_dirty_scheduled = true;
// Only run this after typesetting is done.
- window.MathJax.whenReady(() => {
+ window.MathJax.whenReady(async () => {
+ console.log("Starting update for user change.");
on_dirty_scheduled = false;
// Find the doc block parent div.
const target = (event_target as HTMLDivElement).closest(
@@ -694,18 +703,17 @@ const on_dirty = (
const contents = is_tinymce
? tinymce_singleton!.save()
: contents_div.innerHTML;
- // Although this is async, nothing following this call depends on its completion.
- mathJaxTypeset(contents_div);
- let effects: StateEffect[] = [
- updateDocBlock.of({
- from,
- indent,
- delimiter,
- contents,
- }),
- ];
-
- current_view.dispatch({ effects });
+ await mathJaxTypeset(contents_div);
+ current_view.dispatch({
+ effects: [
+ updateDocBlock.of({
+ from,
+ indent,
+ delimiter,
+ contents,
+ }),
+ ],
+ });
});
};
@@ -819,7 +827,7 @@ export const DocBlockPlugin = ViewPlugin.fromClass(
// Wait until the focus event completes; this causes the
// cursor position (the selection) to be set in the
// contenteditable div. Then, save that location.
- setTimeout(() => {
+ setTimeout(async () => {
// Untypeset math in the old doc block and the current doc block before moving its contents around.
const tinymce_div =
document.getElementById("TinyMCE-inst")!;
@@ -847,7 +855,7 @@ export const DocBlockPlugin = ViewPlugin.fromClass(
null,
);
// The previous content edited by TinyMCE is now a div. Retypeset this after the transition.
- mathJaxTypeset(old_contents_div);
+ await mathJaxTypeset(old_contents_div);
// Move TinyMCE to the new location, then remove the old
// div it will replace.
target.insertBefore(tinymce_div, null);
@@ -857,7 +865,7 @@ export const DocBlockPlugin = ViewPlugin.fromClass(
tinymce_singleton!.setContent(contents_div.innerHTML);
contents_div.remove();
// The new div is now a TinyMCE editor. Retypeset this.
- mathJaxTypeset(tinymce_div);
+ await mathJaxTypeset(tinymce_div);
// This process causes TinyMCE to lose focus. Restore
// that. However, this causes TinyMCE to lose the
@@ -895,6 +903,15 @@ const autosaveExtension = EditorView.updateListener.of(
// [ViewUpdate](https://codemirror.net/docs/ref/#view.ViewUpdate) which
// describes a change being made to the document.
(v: ViewUpdate) => {
+ // Ignore any transaction group marked with a `noAutosaveAnnotation`.
+ if (
+ v.transactions.some(
+ (tr) => tr.annotation(noAutosaveAnnotation) === true,
+ )
+ ) {
+ return true;
+ }
+
// The
// [docChanged](https://codemirror.net/docs/ref/#view.ViewUpdate.docChanged)
// flag is the relevant part of this change description. However, this
@@ -919,10 +936,6 @@ const autosaveExtension = EditorView.updateListener.of(
set_is_dirty();
startAutosaveTimer();
} else if (v.selectionSet) {
- if (ignore_selection_change) {
- ignore_selection_change = false;
- return;
- }
// Send an update if only the selection changed.
startAutosaveTimer();
}
@@ -1047,7 +1060,7 @@ export const CodeMirror_load = async (
parser,
basicSetup,
EditorView.lineWrapping,
- autosaveCompartment.of(autosaveExtension),
+ autosaveExtension,
// Make tab an indent per the
// [docs](https://codemirror.net/examples/tab/). TODO:
// document a way to escape the tab key per the same docs.
@@ -1093,8 +1106,6 @@ export const CodeMirror_load = async (
})
)[0];
} else {
- // Disable autosave when performing these updates.
- current_view.dispatch({ effects: autosaveCompartment.reconfigure([]) });
// This contains a diff, instead of plain text. Apply the text diff.
//
// First, apply just the text edits. Use an annotation so that the doc
@@ -1102,7 +1113,10 @@ export const CodeMirror_load = async (
// from/to values of doc blocks are changed by unfrozen text edits).
current_view.dispatch({
changes: codechat_for_web.source.Diff.doc,
- annotations: docBlockFreezeAnnotation.of(true),
+ annotations: [
+ docBlockFreezeAnnotation.of(true),
+ noAutosaveAnnotation.of(true),
+ ],
});
// Now, apply the diff in a separate transaction. Applying them in the
// same transaction causes the text edits to modify from/to values in
@@ -1130,10 +1144,9 @@ export const CodeMirror_load = async (
}
}
// Update the view with these changes to the state.
- current_view.dispatch({ effects: stateEffects });
- // Resume autosave.
current_view.dispatch({
- effects: autosaveCompartment.reconfigure(autosaveExtension),
+ effects: stateEffects,
+ annotations: noAutosaveAnnotation.of(true),
});
}
scroll_to_line(cursor_line, scroll_line);
@@ -1145,8 +1158,10 @@ export const scroll_to_line = (cursor_line?: number, scroll_line?: number) => {
return;
}
- // Create a transaction to set the cursor and scroll position.
- const dispatch_data: TransactionSpec = {};
+ // Create a transaction to set the cursor and scroll position. Avoid an autosave that sends updated cursor/scroll positions produced by this transaction.
+ const dispatch_data: TransactionSpec = {
+ annotations: noAutosaveAnnotation.of(true),
+ };
if (cursor_line !== undefined) {
// Translate the line numbers to a position.
const cursor_pos = current_view?.state.doc.line(cursor_line).from;
@@ -1169,7 +1184,6 @@ export const scroll_to_line = (cursor_line?: number, scroll_line?: number) => {
}
// Run it.
- ignore_selection_change = true;
current_view?.dispatch(dispatch_data);
};
From 0d23d05192f936d0dd83f6dc067d35904aaa7faf Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Wed, 3 Dec 2025 21:15:31 -0600
Subject: [PATCH 29/38] UI: show errors longer.
---
client/src/show_toast.mts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/client/src/show_toast.mts b/client/src/show_toast.mts
index 0d859382..af6472ba 100644
--- a/client/src/show_toast.mts
+++ b/client/src/show_toast.mts
@@ -22,7 +22,7 @@ import "toastify-js/src/toastify.css";
export const show_toast = (text: string) =>
Toastify({
text,
- duration: 3000,
+ duration: 10000,
newWindow: true,
close: true,
gravity: "top",
From b29ff9ea8aabee5b04e87136c409e659bc6ca0ca Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Wed, 3 Dec 2025 21:15:52 -0600
Subject: [PATCH 30/38] Fix: avoid sending selection updates after receiving
one.
---
extensions/VSCode/src/extension.ts | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/extensions/VSCode/src/extension.ts b/extensions/VSCode/src/extension.ts
index f8c658c2..81f049e7 100644
--- a/extensions/VSCode/src/extension.ts
+++ b/extensions/VSCode/src/extension.ts
@@ -335,13 +335,15 @@ export const activate = (context: vscode.ExtensionContext) => {
}
if (current_update.contents !== undefined) {
const source = current_update.contents.source;
- // Is this plain text, or a diff? This will
- // produce a change event, which we'll ignore.
+ // This will
+ // produce a change event, which we'll ignore. The change may also produce a selection change, which should also be ignored.
ignore_text_document_change = true;
+ ignore_selection_change = true;
// Use a workspace edit, since calls to
// `TextEditor.edit` must be made to the active
// editor only.
const wse = new vscode.WorkspaceEdit();
+ // Is this plain text, or a diff?
if ("Plain" in source) {
wse.replace(
doc.uri,
@@ -389,12 +391,10 @@ export const activate = (context: vscode.ExtensionContext) => {
}
}
}
- vscode.workspace
- .applyEdit(wse)
- .then(
- () =>
- (ignore_text_document_change = false),
- );
+ vscode.workspace.applyEdit(wse).then(() => {
+ ignore_text_document_change = false;
+ ignore_selection_change = false;
+ });
// Now that we've updated our text, update the associated version as well.
version = current_update.contents.version;
}
@@ -420,6 +420,7 @@ export const activate = (context: vscode.ExtensionContext) => {
// viewport, but a bit below it.
TextEditorRevealType.AtTop,
);
+ ignore_selection_change = false;
}
let cursor_line = current_update.cursor_position;
@@ -437,6 +438,7 @@ export const activate = (context: vscode.ExtensionContext) => {
cursor_position,
),
];
+ ignore_selection_change = false;
}
await sendResult(id);
break;
From 32bdd9e981fe4eb9c3c336080c2bf3497d08b946 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Wed, 3 Dec 2025 21:16:26 -0600
Subject: [PATCH 31/38] Fix: update tests.
---
server/tests/overall_core/mod.rs | 45 ++++++++++----------------------
1 file changed, 14 insertions(+), 31 deletions(-)
diff --git a/server/tests/overall_core/mod.rs b/server/tests/overall_core/mod.rs
index 3cc715c5..37378e53 100644
--- a/server/tests/overall_core/mod.rs
+++ b/server/tests/overall_core/mod.rs
@@ -535,7 +535,7 @@ async fn test_server_core(
let doc_block_contents = driver_ref.find(By::Css(contents_css)).await.unwrap();
assert_eq!(
doc_block_contents.inner_html().await.unwrap(),
- "Testfood
\n"
+ "Testfood
"
);
let code_line = driver_ref.find(By::Css(code_line_css)).await.unwrap();
assert_eq!(code_line.inner_html().await.unwrap(), "code()bark");
@@ -564,7 +564,7 @@ async fn test_server_core(
let doc_block_contents = driver_ref.find(By::Css(contents_css)).await.unwrap();
assert_eq!(
doc_block_contents.inner_html().await.unwrap(),
- "food
\n"
+ "food
"
);
let code_line = driver_ref.find(By::Css(code_line_css)).await.unwrap();
assert_eq!(code_line.inner_html().await.unwrap(), "bark");
@@ -579,33 +579,6 @@ async fn test_server_core(
.await
.unwrap();
- // Before changing files, the current file will be updated.
- client_id += MESSAGE_ID_INCREMENT;
- let msg = codechat_server.get_message_timeout(TIMEOUT).await.unwrap();
- let client_version = get_version(&msg);
- assert_eq!(
- msg,
- EditorMessage {
- id: client_id,
- message: EditorMessageContents::Update(UpdateMessageContents {
- file_path: path_str.clone(),
- contents: Some(CodeChatForWeb {
- metadata: SourceFileMetadata {
- mode: "python".to_string()
- },
- source: CodeMirrorDiffable::Plain(CodeMirror {
- doc: " # food\nbark".to_string(),
- doc_blocks: vec![]
- }),
- version: client_version,
- }),
- cursor_position: Some(1),
- scroll_position: Some(1.0),
- })
- }
- );
- codechat_server.send_result(client_id, None).await.unwrap();
-
// These next two messages can come in either order. Work around this.
expected_messages.insert(EditorMessage {
id: current_file_id,
@@ -1126,6 +1099,7 @@ async fn test_client_updates_core(
message: EditorMessageContents::Result(Ok(ResultOkTypes::Void))
}
);
+ server_id += MESSAGE_ID_INCREMENT * 2.0;
// Target the iframe containing the Client.
let codechat_iframe = driver_ref.find(By::Css("#CodeChat-iframe")).await.unwrap();
@@ -1174,6 +1148,15 @@ async fn test_client_updates_core(
}
);
codechat_server.send_result(client_id, None).await.unwrap();
+ // The Server sends the Client a wrapped version of the text; the Client replies with a Result(Ok).
+ assert_eq!(
+ codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
+ EditorMessage {
+ id: server_id,
+ message: EditorMessageContents::Result(Ok(ResultOkTypes::Void))
+ }
+ );
+ server_id += MESSAGE_ID_INCREMENT;
// Insert a character to check the insertion point.
let code_line_css = ".CodeChat-CodeMirror .cm-line";
@@ -1209,8 +1192,8 @@ async fn test_client_updates_core(
},
source: CodeMirrorDiffable::Diff(CodeMirrorDiff {
doc: vec![StringDiff {
- from: 115,
- to: Some(131),
+ from: 100,
+ to: Some(114),
insert: " # A comment\n".to_string()
}],
doc_blocks: vec![],
From 76cb8330249fe64ee378bfb1abcbd17c813cf074 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Wed, 3 Dec 2025 21:19:16 -0600
Subject: [PATCH 32/38] Clean: remove debug code.
---
server/src/translation.rs | 3 ---
1 file changed, 3 deletions(-)
diff --git a/server/src/translation.rs b/server/src/translation.rs
index 9f3ad4c5..912d5087 100644
--- a/server/src/translation.rs
+++ b/server/src/translation.rs
@@ -1055,9 +1055,6 @@ impl TranslationTask {
cfw_version,
code_mirror_translated,
);
- println!(
- "Sending client re-translation update:\nBefore:\n{debug_cm:#?}\nAfter:\n{code_mirror_translated:#?}\nDiff:\n{client_contents:#?}"
- );
queue_send_func!(self.to_client_tx.send(EditorMessage {
id: self.id,
message: EditorMessageContents::Update(
From 3058639017352612d81369f88b1e59badd11fb00 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Wed, 3 Dec 2025 22:03:44 -0600
Subject: [PATCH 33/38] Clean: lints.
---
server/src/translation.rs | 1 -
server/tests/overall_core/mod.rs | 1 -
2 files changed, 2 deletions(-)
diff --git a/server/src/translation.rs b/server/src/translation.rs
index 912d5087..4fa64f59 100644
--- a/server/src/translation.rs
+++ b/server/src/translation.rs
@@ -1017,7 +1017,6 @@ impl TranslationTask {
// TODO: support diffable!
panic!("Diff not supported.");
};
- let debug_cm = code_mirror.clone();
self.code_mirror_doc = code_mirror.doc;
self.code_mirror_doc_blocks = Some(code_mirror.doc_blocks);
// We may need to change this version if we send a diff back to the Client.
diff --git a/server/tests/overall_core/mod.rs b/server/tests/overall_core/mod.rs
index 37378e53..94a3b1c5 100644
--- a/server/tests/overall_core/mod.rs
+++ b/server/tests/overall_core/mod.rs
@@ -1156,7 +1156,6 @@ async fn test_client_updates_core(
message: EditorMessageContents::Result(Ok(ResultOkTypes::Void))
}
);
- server_id += MESSAGE_ID_INCREMENT;
// Insert a character to check the insertion point.
let code_line_css = ".CodeChat-CodeMirror .cm-line";
From bd0501c9635872a6251b595f69d6f1ba648b1156 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Wed, 3 Dec 2025 22:15:45 -0600
Subject: [PATCH 34/38] Freeze for release.
---
CHANGELOG.md | 9 +-
builder/Cargo.lock | 20 +-
client/package.json5 | 12 +-
client/pnpm-lock.yaml | 830 +++++++++++++-----------------
extensions/VSCode/Cargo.lock | 209 ++++----
extensions/VSCode/package.json | 14 +-
extensions/VSCode/pnpm-lock.yaml | 845 ++++++++++++++++---------------
server/Cargo.lock | 281 +++++-----
server/Cargo.toml | 2 +-
9 files changed, 1062 insertions(+), 1160 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8ecd277a..c87e8502 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,12 +26,19 @@ Changelog
* Send sync data when doc blocks receive focus.
* Improve error handling.
* Improve method used to keep Client and IDE contents in sync.
+* Correctly sync when IDE files are updated when editing in the Client.
+* Fix data corruption bug when creating new doc blocks in the Client --
+ whitespace was lost.
+* Update line numbering in the Client when word wraps occur in a doc block.
+* Avoid unnecessary saves from the Client just after receiving new data.
+* Reduce delay between Client edits and IDE updates.
+* Increase time errors messages are displayed in the Client.
Version 0.1.41 -- 2025-Nov-17
--------------------------------------------------------------------------------
* Math now renders in the active doc block, as shown below.
-* Math is now protected from accidental edits in the Client:\
+* Math is now protected from accidental edits in the Client:

* Improved synchronization between the cursor and scroll position of the Client
and IDE.
diff --git a/builder/Cargo.lock b/builder/Cargo.lock
index 24c5ff75..7f60f02c 100644
--- a/builder/Cargo.lock
+++ b/builder/Cargo.lock
@@ -81,9 +81,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.51"
+version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
+checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
dependencies = [
"clap_builder",
"clap_derive",
@@ -91,9 +91,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.51"
+version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
+checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
dependencies = [
"anstream",
"anstyle",
@@ -234,15 +234,15 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.177"
+version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
+checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]]
name = "log"
-version = "0.4.28"
+version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "memchr"
@@ -384,9 +384,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
-version = "2.0.110"
+version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
+checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [
"proc-macro2",
"quote",
diff --git a/client/package.json5 b/client/package.json5
index f94747cc..b6d22ae4 100644
--- a/client/package.json5
+++ b/client/package.json5
@@ -66,9 +66,9 @@
codemirror: '^6.0.2',
'graphviz-webcomponent': 'github:bjones1/graphviz-webcomponent#dist',
mathjax: '4.0.0',
- mermaid: '^11.12.1',
+ mermaid: '^11.12.2',
'npm-check-updates': '^19.1.2',
- 'pdfjs-dist': '^5.4.394',
+ 'pdfjs-dist': '^5.4.449',
tinymce: '^8.2.2',
'toastify-js': '^1.12.0',
},
@@ -78,16 +78,16 @@
'@types/mocha': '^10.0.10',
'@types/node': '^24.10.1',
'@types/toastify-js': '^1.12.4',
- '@typescript-eslint/eslint-plugin': '^8.46.4',
- '@typescript-eslint/parser': '^8.46.4',
+ '@typescript-eslint/eslint-plugin': '^8.48.1',
+ '@typescript-eslint/parser': '^8.48.1',
chai: '^6.2.1',
- esbuild: '^0.27.0',
+ esbuild: '^0.27.1',
eslint: '^9.39.1',
'eslint-config-prettier': '^10.1.8',
'eslint-plugin-import': '^2.32.0',
'eslint-plugin-prettier': '^5.5.4',
mocha: '^11.7.5',
- prettier: '^3.6.2',
+ prettier: '^3.7.4',
typescript: '^5.9.3',
},
scripts: {
diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml
index ac137ef1..b54152e3 100644
--- a/client/pnpm-lock.yaml
+++ b/client/pnpm-lock.yaml
@@ -72,14 +72,14 @@ importers:
specifier: 4.0.0
version: 4.0.0
mermaid:
- specifier: ^11.12.1
- version: 11.12.1
+ specifier: ^11.12.2
+ version: 11.12.2
npm-check-updates:
specifier: ^19.1.2
version: 19.1.2
pdfjs-dist:
- specifier: ^5.4.394
- version: 5.4.394
+ specifier: ^5.4.449
+ version: 5.4.449
tinymce:
specifier: ^8.2.2
version: 8.2.2
@@ -103,17 +103,17 @@ importers:
specifier: ^1.12.4
version: 1.12.4
'@typescript-eslint/eslint-plugin':
- specifier: ^8.46.4
- version: 8.46.4(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
+ specifier: ^8.48.1
+ version: 8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/parser':
- specifier: ^8.46.4
- version: 8.46.4(eslint@9.39.1)(typescript@5.9.3)
+ specifier: ^8.48.1
+ version: 8.48.1(eslint@9.39.1)(typescript@5.9.3)
chai:
specifier: ^6.2.1
version: 6.2.1
esbuild:
- specifier: ^0.27.0
- version: 0.27.0
+ specifier: ^0.27.1
+ version: 0.27.1
eslint:
specifier: ^9.39.1
version: 9.39.1
@@ -122,16 +122,16 @@ importers:
version: 10.1.8(eslint@9.39.1)
eslint-plugin-import:
specifier: ^2.32.0
- version: 2.32.0(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)
+ version: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)
eslint-plugin-prettier:
specifier: ^5.5.4
- version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.6.2)
+ version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.7.4)
mocha:
specifier: ^11.7.5
version: 11.7.5
prettier:
- specifier: ^3.6.2
- version: 3.6.2
+ specifier: ^3.7.4
+ version: 3.7.4
typescript:
specifier: ^5.9.3
version: 5.9.3
@@ -141,9 +141,6 @@ packages:
'@antfu/install-pkg@1.1.0':
resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}
- '@antfu/utils@9.3.0':
- resolution: {integrity: sha512-9hFT4RauhcUzqOE4f1+frMKLZrgNog5b06I7VmZQV1BkvwvqrbC8EBZf3L1eEL2AKb6rNKjER0sEvJiSP1FXEA==}
-
'@braintree/sanitize-url@7.1.1':
resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==}
@@ -162,8 +159,8 @@ packages:
'@chevrotain/utils@11.0.3':
resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==}
- '@codemirror/autocomplete@6.19.1':
- resolution: {integrity: sha512-q6NenYkEy2fn9+JyjIxMWcNjzTL/IhwqfzOut1/G3PrIFkrbl4AL7Wkse5tLrQUUyqGoAKU5+Pi5jnnXxH5HGw==}
+ '@codemirror/autocomplete@6.20.0':
+ resolution: {integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==}
'@codemirror/commands@6.10.0':
resolution: {integrity: sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w==}
@@ -225,158 +222,158 @@ packages:
'@codemirror/view@6.38.8':
resolution: {integrity: sha512-XcE9fcnkHCbWkjeKyi0lllwXmBLtyYb5dt89dJyx23I9+LSh5vZDIuk7OLG4VM1lgrXZQcY6cxyZyk5WVPRv/A==}
- '@esbuild/aix-ppc64@0.27.0':
- resolution: {integrity: sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==}
+ '@esbuild/aix-ppc64@0.27.1':
+ resolution: {integrity: sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
- '@esbuild/android-arm64@0.27.0':
- resolution: {integrity: sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==}
+ '@esbuild/android-arm64@0.27.1':
+ resolution: {integrity: sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
- '@esbuild/android-arm@0.27.0':
- resolution: {integrity: sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==}
+ '@esbuild/android-arm@0.27.1':
+ resolution: {integrity: sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
- '@esbuild/android-x64@0.27.0':
- resolution: {integrity: sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==}
+ '@esbuild/android-x64@0.27.1':
+ resolution: {integrity: sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
- '@esbuild/darwin-arm64@0.27.0':
- resolution: {integrity: sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==}
+ '@esbuild/darwin-arm64@0.27.1':
+ resolution: {integrity: sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-x64@0.27.0':
- resolution: {integrity: sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==}
+ '@esbuild/darwin-x64@0.27.1':
+ resolution: {integrity: sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
- '@esbuild/freebsd-arm64@0.27.0':
- resolution: {integrity: sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==}
+ '@esbuild/freebsd-arm64@0.27.1':
+ resolution: {integrity: sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.27.0':
- resolution: {integrity: sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==}
+ '@esbuild/freebsd-x64@0.27.1':
+ resolution: {integrity: sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
- '@esbuild/linux-arm64@0.27.0':
- resolution: {integrity: sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==}
+ '@esbuild/linux-arm64@0.27.1':
+ resolution: {integrity: sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm@0.27.0':
- resolution: {integrity: sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==}
+ '@esbuild/linux-arm@0.27.1':
+ resolution: {integrity: sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
- '@esbuild/linux-ia32@0.27.0':
- resolution: {integrity: sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==}
+ '@esbuild/linux-ia32@0.27.1':
+ resolution: {integrity: sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
- '@esbuild/linux-loong64@0.27.0':
- resolution: {integrity: sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==}
+ '@esbuild/linux-loong64@0.27.1':
+ resolution: {integrity: sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
- '@esbuild/linux-mips64el@0.27.0':
- resolution: {integrity: sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==}
+ '@esbuild/linux-mips64el@0.27.1':
+ resolution: {integrity: sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-ppc64@0.27.0':
- resolution: {integrity: sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==}
+ '@esbuild/linux-ppc64@0.27.1':
+ resolution: {integrity: sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-riscv64@0.27.0':
- resolution: {integrity: sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==}
+ '@esbuild/linux-riscv64@0.27.1':
+ resolution: {integrity: sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-s390x@0.27.0':
- resolution: {integrity: sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==}
+ '@esbuild/linux-s390x@0.27.1':
+ resolution: {integrity: sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
- '@esbuild/linux-x64@0.27.0':
- resolution: {integrity: sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==}
+ '@esbuild/linux-x64@0.27.1':
+ resolution: {integrity: sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
- '@esbuild/netbsd-arm64@0.27.0':
- resolution: {integrity: sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==}
+ '@esbuild/netbsd-arm64@0.27.1':
+ resolution: {integrity: sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.27.0':
- resolution: {integrity: sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==}
+ '@esbuild/netbsd-x64@0.27.1':
+ resolution: {integrity: sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
- '@esbuild/openbsd-arm64@0.27.0':
- resolution: {integrity: sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==}
+ '@esbuild/openbsd-arm64@0.27.1':
+ resolution: {integrity: sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.27.0':
- resolution: {integrity: sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==}
+ '@esbuild/openbsd-x64@0.27.1':
+ resolution: {integrity: sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
- '@esbuild/openharmony-arm64@0.27.0':
- resolution: {integrity: sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==}
+ '@esbuild/openharmony-arm64@0.27.1':
+ resolution: {integrity: sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
- '@esbuild/sunos-x64@0.27.0':
- resolution: {integrity: sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==}
+ '@esbuild/sunos-x64@0.27.1':
+ resolution: {integrity: sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
- '@esbuild/win32-arm64@0.27.0':
- resolution: {integrity: sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==}
+ '@esbuild/win32-arm64@0.27.1':
+ resolution: {integrity: sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
- '@esbuild/win32-ia32@0.27.0':
- resolution: {integrity: sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==}
+ '@esbuild/win32-ia32@0.27.1':
+ resolution: {integrity: sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
- '@esbuild/win32-x64@0.27.0':
- resolution: {integrity: sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==}
+ '@esbuild/win32-x64@0.27.1':
+ resolution: {integrity: sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
@@ -403,8 +400,8 @@ packages:
resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/eslintrc@3.3.1':
- resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
+ '@eslint/eslintrc@3.3.3':
+ resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/js@9.39.1':
@@ -438,15 +435,15 @@ packages:
'@iconify/types@2.0.0':
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
- '@iconify/utils@3.0.2':
- resolution: {integrity: sha512-EfJS0rLfVuRuJRn4psJHtK2A9TqVnkxPpHY6lYHiB9+8eSuudsxbwMiavocG45ujOo6FJ+CIRlRnlOGinzkaGQ==}
+ '@iconify/utils@3.1.0':
+ resolution: {integrity: sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==}
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
- '@lezer/common@1.3.0':
- resolution: {integrity: sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ==}
+ '@lezer/common@1.4.0':
+ resolution: {integrity: sha512-DVeMRoGrgn/k45oQNu189BoW4SZwgZFzJ1+1TV5j2NJ/KFC83oa/enRqZSGshyeMk5cPWMhsKs9nx+8o0unwGg==}
'@lezer/cpp@1.1.3':
resolution: {integrity: sha512-ykYvuFQKGsRi6IcE+/hCSGUhb/I4WPjd3ELhEblm2wS2cOznDFzO+ubK2c+ioysOnlZ3EduV+MVQFCPzAIoY3w==}
@@ -472,8 +469,8 @@ packages:
'@lezer/json@1.0.3':
resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==}
- '@lezer/lr@1.4.3':
- resolution: {integrity: sha512-yenN5SqAxAPv/qMnpWW0AT7l+SxVrgG+u0tNsRQWqbrz66HIl8DnEbBObvy21J5K7+I1v7gsAnlE2VQ5yYVSeA==}
+ '@lezer/lr@1.4.4':
+ resolution: {integrity: sha512-LHL17Mq0OcFXm1pGQssuGTQFPPdxARjKM8f7GA5+sGtHi0K3R84YaSbmche0+RKWHnCsx9asEe5OWOI4FHfe4A==}
'@lezer/markdown@1.6.0':
resolution: {integrity: sha512-AXb98u3M6BEzTnreBnGtQaF7xFTiMA92Dsy5tqEjpacbjRxDSFdN4bKJo9uvU4cEEOS7D2B9MT7kvDgOEIzJSw==}
@@ -502,82 +499,70 @@ packages:
'@mermaid-js/parser@0.6.3':
resolution: {integrity: sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==}
- '@napi-rs/canvas-android-arm64@0.1.82':
- resolution: {integrity: sha512-bvZhN0iI54ouaQOrgJV96H2q7J3ZoufnHf4E1fUaERwW29Rz4rgicohnAg4venwBJZYjGl5Yl3CGmlAl1LZowQ==}
+ '@napi-rs/canvas-android-arm64@0.1.83':
+ resolution: {integrity: sha512-TbKM2fh9zXjqFIU8bgMfzG7rkrIYdLKMafgPhFoPwKrpWk1glGbWP7LEu8Y/WrMDqTGFdRqUmuX89yQEzZbkiw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [android]
- '@napi-rs/canvas-darwin-arm64@0.1.82':
- resolution: {integrity: sha512-InuBHKCyuFqhNwNr4gpqazo5Xp6ltKflqOLiROn4hqAS8u21xAHyYCJRgHwd+a5NKmutFTaRWeUIT/vxWbU/iw==}
+ '@napi-rs/canvas-darwin-arm64@0.1.83':
+ resolution: {integrity: sha512-gp8IDVUloPUmkepHly4xRUOfUJSFNvA4jR7ZRF5nk3YcGzegSFGeICiT4PnYyPgSKEhYAFe1Y2XNy0Mp6Tu8mQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
- '@napi-rs/canvas-darwin-x64@0.1.82':
- resolution: {integrity: sha512-aQGV5Ynn96onSXcuvYb2y7TRXD/t4CL2EGmnGqvLyeJX1JLSNisKQlWN/1bPDDXymZYSdUqbXehj5qzBlOx+RQ==}
+ '@napi-rs/canvas-darwin-x64@0.1.83':
+ resolution: {integrity: sha512-r4ZJxiP9OgUbdGZhPDEXD3hQ0aIPcVaywtcTXvamYxTU/SWKAbKVhFNTtpRe1J30oQ25gWyxTkUKSBgUkNzdnw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
- '@napi-rs/canvas-linux-arm-gnueabihf@0.1.82':
- resolution: {integrity: sha512-YIUpmHWeHGGRhWitT1KJkgj/JPXPfc9ox8oUoyaGPxolLGPp5AxJkq8wIg8CdFGtutget968dtwmx71m8o3h5g==}
+ '@napi-rs/canvas-linux-arm-gnueabihf@0.1.83':
+ resolution: {integrity: sha512-Uc6aSB05qH1r+9GUDxIE6F5ZF7L0nTFyyzq8ublWUZhw8fEGK8iy931ff1ByGFT04+xHJad1kBcL4R1ZEV8z7Q==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
- '@napi-rs/canvas-linux-arm64-gnu@0.1.82':
- resolution: {integrity: sha512-AwLzwLBgmvk7kWeUgItOUor/QyG31xqtD26w1tLpf4yE0hiXTGp23yc669aawjB6FzgIkjh1NKaNS52B7/qEBQ==}
+ '@napi-rs/canvas-linux-arm64-gnu@0.1.83':
+ resolution: {integrity: sha512-eEeaJA7V5KOFq7W0GtoRVbd3ak8UZpK+XLkCgUiFGtlunNw+ZZW9Cr/92MXflGe7o3SqqMUg+f975LPxO/vsOQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
- '@napi-rs/canvas-linux-arm64-musl@0.1.82':
- resolution: {integrity: sha512-moZWuqepAwWBffdF4JDadt8TgBD02iMhG6I1FHZf8xO20AsIp9rB+p0B8Zma2h2vAF/YMjeFCDmW5un6+zZz9g==}
+ '@napi-rs/canvas-linux-arm64-musl@0.1.83':
+ resolution: {integrity: sha512-cAvonp5XpbatVGegF9lMQNchs3z5RH6EtamRVnQvtoRtwbzOMcdzwuLBqDBQxQF79MFbuZNkWj3YRJjZCjHVzw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
- '@napi-rs/canvas-linux-riscv64-gnu@0.1.82':
- resolution: {integrity: sha512-w9++2df2kG9eC9LWYIHIlMLuhIrKGQYfUxs97CwgxYjITeFakIRazI9LYWgVzEc98QZ9x9GQvlicFsrROV59MQ==}
+ '@napi-rs/canvas-linux-riscv64-gnu@0.1.83':
+ resolution: {integrity: sha512-WFUPQ9qZy31vmLxIJ3MfmHw+R2g/mLCgk8zmh7maJW8snV3vLPA7pZfIS65Dc61EVDp1vaBskwQ2RqPPzwkaew==}
engines: {node: '>= 10'}
cpu: [riscv64]
os: [linux]
- '@napi-rs/canvas-linux-x64-gnu@0.1.82':
- resolution: {integrity: sha512-lZulOPwrRi6hEg/17CaqdwWEUfOlIJuhXxincx1aVzsVOCmyHf+xFq4i6liJl1P+x2v6Iz2Z/H5zHvXJCC7Bwg==}
+ '@napi-rs/canvas-linux-x64-gnu@0.1.83':
+ resolution: {integrity: sha512-X9YwIjsuy50WwOyYeNhEHjKHO8rrfH9M4U8vNqLuGmqsZdKua/GrUhdQGdjq7lTgdY3g4+Ta5jF8MzAa7UAs/g==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
- '@napi-rs/canvas-linux-x64-musl@0.1.82':
- resolution: {integrity: sha512-Be9Wf5RTv1w6GXlTph55K3PH3vsAh1Ax4T1FQY1UYM0QfD0yrwGdnJ8/fhqw7dEgMjd59zIbjJQC8C3msbGn5g==}
+ '@napi-rs/canvas-linux-x64-musl@0.1.83':
+ resolution: {integrity: sha512-Vv2pLWQS8EnlSM1bstJ7vVhKA+mL4+my4sKUIn/bgIxB5O90dqiDhQjUDLP+5xn9ZMestRWDt3tdQEkGAmzq/A==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
- '@napi-rs/canvas-win32-x64-msvc@0.1.82':
- resolution: {integrity: sha512-LN/i8VrvxTDmEEK1c10z2cdOTkWT76LlTGtyZe5Kr1sqoSomKeExAjbilnu1+oee5lZUgS5yfZ2LNlVhCeARuw==}
+ '@napi-rs/canvas-win32-x64-msvc@0.1.83':
+ resolution: {integrity: sha512-K1TtjbScfRNYhq8dengLLufXGbtEtWdUXPV505uLFPovyGHzDUGXLFP/zUJzj6xWXwgUjHNLgEPIt7mye0zr6Q==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
- '@napi-rs/canvas@0.1.82':
- resolution: {integrity: sha512-FGjyUBoF0sl1EenSiE4UV2WYu76q6F9GSYedq5EiOCOyGYoQ/Owulcv6rd7v/tWOpljDDtefXXIaOCJrVKem4w==}
+ '@napi-rs/canvas@0.1.83':
+ resolution: {integrity: sha512-f9GVB9VNc9vn/nroc9epXRNkVpvNPZh69+qzLJIm9DfruxFqX0/jsXG46OGWAJgkO4mN0HvFHjRROMXKVmPszg==}
engines: {node: '>= 10'}
- '@nodelib/fs.scandir@2.1.5':
- resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
- engines: {node: '>= 8'}
-
- '@nodelib/fs.stat@2.0.5':
- resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
- engines: {node: '>= 8'}
-
- '@nodelib/fs.walk@1.2.8':
- resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
- engines: {node: '>= 8'}
-
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
@@ -715,63 +700,63 @@ packages:
'@types/trusted-types@2.0.7':
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
- '@typescript-eslint/eslint-plugin@8.46.4':
- resolution: {integrity: sha512-R48VhmTJqplNyDxCyqqVkFSZIx1qX6PzwqgcXn1olLrzxcSBDlOsbtcnQuQhNtnNiJ4Xe5gREI1foajYaYU2Vg==}
+ '@typescript-eslint/eslint-plugin@8.48.1':
+ resolution: {integrity: sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
- '@typescript-eslint/parser': ^8.46.4
+ '@typescript-eslint/parser': ^8.48.1
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
- '@typescript-eslint/parser@8.46.4':
- resolution: {integrity: sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w==}
+ '@typescript-eslint/parser@8.48.1':
+ resolution: {integrity: sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
- '@typescript-eslint/project-service@8.46.4':
- resolution: {integrity: sha512-nPiRSKuvtTN+no/2N1kt2tUh/HoFzeEgOm9fQ6XQk4/ApGqjx0zFIIaLJ6wooR1HIoozvj2j6vTi/1fgAz7UYQ==}
+ '@typescript-eslint/project-service@8.48.1':
+ resolution: {integrity: sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
- '@typescript-eslint/scope-manager@8.46.4':
- resolution: {integrity: sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==}
+ '@typescript-eslint/scope-manager@8.48.1':
+ resolution: {integrity: sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@typescript-eslint/tsconfig-utils@8.46.4':
- resolution: {integrity: sha512-+/XqaZPIAk6Cjg7NWgSGe27X4zMGqrFqZ8atJsX3CWxH/jACqWnrWI68h7nHQld0y+k9eTTjb9r+KU4twLoo9A==}
+ '@typescript-eslint/tsconfig-utils@8.48.1':
+ resolution: {integrity: sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
- '@typescript-eslint/type-utils@8.46.4':
- resolution: {integrity: sha512-V4QC8h3fdT5Wro6vANk6eojqfbv5bpwHuMsBcJUJkqs2z5XnYhJzyz9Y02eUmF9u3PgXEUiOt4w4KHR3P+z0PQ==}
+ '@typescript-eslint/type-utils@8.48.1':
+ resolution: {integrity: sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
- '@typescript-eslint/types@8.46.4':
- resolution: {integrity: sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w==}
+ '@typescript-eslint/types@8.48.1':
+ resolution: {integrity: sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@typescript-eslint/typescript-estree@8.46.4':
- resolution: {integrity: sha512-7oV2qEOr1d4NWNmpXLR35LvCfOkTNymY9oyW+lUHkmCno7aOmIf/hMaydnJBUTBMRCOGZh8YjkFOc8dadEoNGA==}
+ '@typescript-eslint/typescript-estree@8.48.1':
+ resolution: {integrity: sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
- '@typescript-eslint/utils@8.46.4':
- resolution: {integrity: sha512-AbSv11fklGXV6T28dp2Me04Uw90R2iJ30g2bgLz529Koehrmkbs1r7paFqr1vPCZi7hHwYxYtxfyQMRC8QaVSg==}
+ '@typescript-eslint/utils@8.48.1':
+ resolution: {integrity: sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
- '@typescript-eslint/visitor-keys@8.46.4':
- resolution: {integrity: sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==}
+ '@typescript-eslint/visitor-keys@8.48.1':
+ resolution: {integrity: sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
acorn-jsx@5.3.2:
@@ -851,10 +836,6 @@ packages:
brace-expansion@2.0.2:
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
- braces@3.0.3:
- resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
- engines: {node: '>=8'}
-
browser-stdout@1.3.1:
resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==}
@@ -926,9 +907,6 @@ packages:
confbox@0.1.8:
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
- confbox@0.2.2:
- resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==}
-
cose-base@1.0.3:
resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==}
@@ -1200,8 +1178,8 @@ packages:
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
engines: {node: '>= 0.4'}
- esbuild@0.27.0:
- resolution: {integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==}
+ esbuild@0.27.1:
+ resolution: {integrity: sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==}
engines: {node: '>=18'}
hasBin: true
@@ -1309,36 +1287,31 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
- exsolve@1.0.8:
- resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
-
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
fast-diff@1.3.0:
resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
- fast-glob@3.3.3:
- resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
- engines: {node: '>=8.6.0'}
-
fast-json-stable-stringify@2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
- fastq@1.19.1:
- resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
file-entry-cache@8.0.0:
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
engines: {node: '>=16.0.0'}
- fill-range@7.1.1:
- resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
- engines: {node: '>=8'}
-
find-up@5.0.0:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
@@ -1392,26 +1365,18 @@ packages:
resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
engines: {node: '>= 0.4'}
- glob-parent@5.1.2:
- resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
- engines: {node: '>= 6'}
-
glob-parent@6.0.2:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
- glob@10.4.5:
- resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
+ glob@10.5.0:
+ resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
hasBin: true
globals@14.0.0:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
- globals@15.15.0:
- resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==}
- engines: {node: '>=18'}
-
globalthis@1.0.4:
resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
engines: {node: '>= 0.4'}
@@ -1557,10 +1522,6 @@ packages:
resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
engines: {node: '>= 0.4'}
- is-number@7.0.0:
- resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
- engines: {node: '>=0.12.0'}
-
is-path-inside@3.0.3:
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
engines: {node: '>=8'}
@@ -1645,9 +1606,6 @@ packages:
khroma@2.1.0:
resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==}
- kolorist@1.8.0:
- resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
-
langium@3.3.1:
resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==}
engines: {node: '>=16.0.0'}
@@ -1662,10 +1620,6 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
- local-pkg@1.1.2:
- resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==}
- engines: {node: '>=14'}
-
locate-path@6.0.0:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'}
@@ -1695,16 +1649,8 @@ packages:
mathjax@4.0.0:
resolution: {integrity: sha512-ThMPHiPl9ibZBInAmfoTCNq9MgCdH7ChIQ9YhKFc325noJ4DMzy9/Q14qdcuPzVJjEmC3kyXhwnERZWX3hbWzQ==}
- merge2@1.4.1:
- resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
- engines: {node: '>= 8'}
-
- mermaid@11.12.1:
- resolution: {integrity: sha512-UlIZrRariB11TY1RtTgUWp65tphtBv4CSq7vyS2ZZ2TgoMjs2nloq+wFqxiwcxlhHUvs7DPGgMjs2aeQxz5h9g==}
-
- micromatch@4.0.8:
- resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
- engines: {node: '>=8.6'}
+ mermaid@11.12.2:
+ resolution: {integrity: sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w==}
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@@ -1782,8 +1728,8 @@ packages:
package-json-from-dist@1.0.1:
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
- package-manager-detector@1.5.0:
- resolution: {integrity: sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw==}
+ package-manager-detector@1.6.0:
+ resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==}
parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
@@ -1810,23 +1756,20 @@ packages:
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
- pdfjs-dist@5.4.394:
- resolution: {integrity: sha512-9ariAYGqUJzx+V/1W4jHyiyCep6IZALmDzoaTLZ6VNu8q9LWi1/ukhzHgE2Xsx96AZi0mbZuK4/ttIbqSbLypg==}
+ pdfjs-dist@5.4.449:
+ resolution: {integrity: sha512-CegnUaT0QwAyQMS+7o2POr4wWUNNe8VaKKlcuoRHeYo98cVnqPpwOXNSx6Trl6szH02JrRcsPgletV6GmF3LtQ==}
engines: {node: '>=20.16.0 || >=22.3.0'}
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
- picomatch@2.3.1:
- resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
- engines: {node: '>=8.6'}
+ picomatch@4.0.3:
+ resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
+ engines: {node: '>=12'}
pkg-types@1.3.1:
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
- pkg-types@2.3.0:
- resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==}
-
points-on-curve@0.2.0:
resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==}
@@ -1845,8 +1788,8 @@ packages:
resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
engines: {node: '>=6.0.0'}
- prettier@3.6.2:
- resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
+ prettier@3.7.4:
+ resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==}
engines: {node: '>=14'}
hasBin: true
@@ -1854,12 +1797,6 @@ packages:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
- quansync@0.2.11:
- resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
-
- queue-microtask@1.2.3:
- resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
-
randombytes@2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
@@ -1888,19 +1825,12 @@ packages:
engines: {node: '>= 0.4'}
hasBin: true
- reusify@1.1.0:
- resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
- engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
-
robust-predicates@3.0.2:
resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==}
roughjs@4.6.6:
resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==}
- run-parallel@1.2.0:
- resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
-
rw@1.3.3:
resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==}
@@ -2040,13 +1970,13 @@ packages:
resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==}
engines: {node: '>=18'}
+ tinyglobby@0.2.15:
+ resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
+ engines: {node: '>=12.0.0'}
+
tinymce@8.2.2:
resolution: {integrity: sha512-CFDSZwciMvFGW2czK/Xig1HcOGpXI0qcQMIqaIcG2F4RuuTdf+LQTreyEZunAJoFTQ9L0KAugOqL7OA5TJkoAA==}
- to-regex-range@5.0.1:
- resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
- engines: {node: '>=8.0'}
-
toastify-js@1.12.0:
resolution: {integrity: sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ==}
@@ -2188,11 +2118,9 @@ snapshots:
'@antfu/install-pkg@1.1.0':
dependencies:
- package-manager-detector: 1.5.0
+ package-manager-detector: 1.6.0
tinyexec: 1.0.2
- '@antfu/utils@9.3.0': {}
-
'@braintree/sanitize-url@7.1.1': {}
'@chevrotain/cst-dts-gen@11.0.3':
@@ -2212,19 +2140,19 @@ snapshots:
'@chevrotain/utils@11.0.3': {}
- '@codemirror/autocomplete@6.19.1':
+ '@codemirror/autocomplete@6.20.0':
dependencies:
'@codemirror/language': 6.11.3
'@codemirror/state': 6.5.2
'@codemirror/view': 6.38.8
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@codemirror/commands@6.10.0':
dependencies:
'@codemirror/language': 6.11.3
'@codemirror/state': 6.5.2
'@codemirror/view': 6.38.8
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@codemirror/lang-cpp@6.0.3':
dependencies:
@@ -2233,29 +2161,29 @@ snapshots:
'@codemirror/lang-css@6.3.1':
dependencies:
- '@codemirror/autocomplete': 6.19.1
+ '@codemirror/autocomplete': 6.20.0
'@codemirror/language': 6.11.3
'@codemirror/state': 6.5.2
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/css': 1.3.0
'@codemirror/lang-go@6.0.1':
dependencies:
- '@codemirror/autocomplete': 6.19.1
+ '@codemirror/autocomplete': 6.20.0
'@codemirror/language': 6.11.3
'@codemirror/state': 6.5.2
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/go': 1.0.1
'@codemirror/lang-html@6.4.11':
dependencies:
- '@codemirror/autocomplete': 6.19.1
+ '@codemirror/autocomplete': 6.20.0
'@codemirror/lang-css': 6.3.1
'@codemirror/lang-javascript': 6.2.4
'@codemirror/language': 6.11.3
'@codemirror/state': 6.5.2
'@codemirror/view': 6.38.8
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/css': 1.3.0
'@lezer/html': 1.3.12
@@ -2266,12 +2194,12 @@ snapshots:
'@codemirror/lang-javascript@6.2.4':
dependencies:
- '@codemirror/autocomplete': 6.19.1
+ '@codemirror/autocomplete': 6.20.0
'@codemirror/language': 6.11.3
'@codemirror/lint': 6.9.2
'@codemirror/state': 6.5.2
'@codemirror/view': 6.38.8
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/javascript': 1.5.4
'@codemirror/lang-json@6.0.2':
@@ -2281,12 +2209,12 @@ snapshots:
'@codemirror/lang-markdown@6.5.0':
dependencies:
- '@codemirror/autocomplete': 6.19.1
+ '@codemirror/autocomplete': 6.20.0
'@codemirror/lang-html': 6.4.11
'@codemirror/language': 6.11.3
'@codemirror/state': 6.5.2
'@codemirror/view': 6.38.8
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/markdown': 1.6.0
'@codemirror/lang-php@6.0.2':
@@ -2294,15 +2222,15 @@ snapshots:
'@codemirror/lang-html': 6.4.11
'@codemirror/language': 6.11.3
'@codemirror/state': 6.5.2
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/php': 1.0.5
'@codemirror/lang-python@6.2.1':
dependencies:
- '@codemirror/autocomplete': 6.19.1
+ '@codemirror/autocomplete': 6.20.0
'@codemirror/language': 6.11.3
'@codemirror/state': 6.5.2
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/python': 1.1.18
'@codemirror/lang-rust@6.0.2':
@@ -2312,39 +2240,39 @@ snapshots:
'@codemirror/lang-sql@6.10.0':
dependencies:
- '@codemirror/autocomplete': 6.19.1
+ '@codemirror/autocomplete': 6.20.0
'@codemirror/language': 6.11.3
'@codemirror/state': 6.5.2
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
'@codemirror/lang-xml@6.1.0':
dependencies:
- '@codemirror/autocomplete': 6.19.1
+ '@codemirror/autocomplete': 6.20.0
'@codemirror/language': 6.11.3
'@codemirror/state': 6.5.2
'@codemirror/view': 6.38.8
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/xml': 1.0.6
'@codemirror/lang-yaml@6.1.2':
dependencies:
- '@codemirror/autocomplete': 6.19.1
+ '@codemirror/autocomplete': 6.20.0
'@codemirror/language': 6.11.3
'@codemirror/state': 6.5.2
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
'@lezer/yaml': 1.0.3
'@codemirror/language@6.11.3':
dependencies:
'@codemirror/state': 6.5.2
'@codemirror/view': 6.38.8
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
style-mod: 4.1.3
'@codemirror/lint@6.9.2':
@@ -2370,82 +2298,82 @@ snapshots:
style-mod: 4.1.3
w3c-keyname: 2.2.8
- '@esbuild/aix-ppc64@0.27.0':
+ '@esbuild/aix-ppc64@0.27.1':
optional: true
- '@esbuild/android-arm64@0.27.0':
+ '@esbuild/android-arm64@0.27.1':
optional: true
- '@esbuild/android-arm@0.27.0':
+ '@esbuild/android-arm@0.27.1':
optional: true
- '@esbuild/android-x64@0.27.0':
+ '@esbuild/android-x64@0.27.1':
optional: true
- '@esbuild/darwin-arm64@0.27.0':
+ '@esbuild/darwin-arm64@0.27.1':
optional: true
- '@esbuild/darwin-x64@0.27.0':
+ '@esbuild/darwin-x64@0.27.1':
optional: true
- '@esbuild/freebsd-arm64@0.27.0':
+ '@esbuild/freebsd-arm64@0.27.1':
optional: true
- '@esbuild/freebsd-x64@0.27.0':
+ '@esbuild/freebsd-x64@0.27.1':
optional: true
- '@esbuild/linux-arm64@0.27.0':
+ '@esbuild/linux-arm64@0.27.1':
optional: true
- '@esbuild/linux-arm@0.27.0':
+ '@esbuild/linux-arm@0.27.1':
optional: true
- '@esbuild/linux-ia32@0.27.0':
+ '@esbuild/linux-ia32@0.27.1':
optional: true
- '@esbuild/linux-loong64@0.27.0':
+ '@esbuild/linux-loong64@0.27.1':
optional: true
- '@esbuild/linux-mips64el@0.27.0':
+ '@esbuild/linux-mips64el@0.27.1':
optional: true
- '@esbuild/linux-ppc64@0.27.0':
+ '@esbuild/linux-ppc64@0.27.1':
optional: true
- '@esbuild/linux-riscv64@0.27.0':
+ '@esbuild/linux-riscv64@0.27.1':
optional: true
- '@esbuild/linux-s390x@0.27.0':
+ '@esbuild/linux-s390x@0.27.1':
optional: true
- '@esbuild/linux-x64@0.27.0':
+ '@esbuild/linux-x64@0.27.1':
optional: true
- '@esbuild/netbsd-arm64@0.27.0':
+ '@esbuild/netbsd-arm64@0.27.1':
optional: true
- '@esbuild/netbsd-x64@0.27.0':
+ '@esbuild/netbsd-x64@0.27.1':
optional: true
- '@esbuild/openbsd-arm64@0.27.0':
+ '@esbuild/openbsd-arm64@0.27.1':
optional: true
- '@esbuild/openbsd-x64@0.27.0':
+ '@esbuild/openbsd-x64@0.27.1':
optional: true
- '@esbuild/openharmony-arm64@0.27.0':
+ '@esbuild/openharmony-arm64@0.27.1':
optional: true
- '@esbuild/sunos-x64@0.27.0':
+ '@esbuild/sunos-x64@0.27.1':
optional: true
- '@esbuild/win32-arm64@0.27.0':
+ '@esbuild/win32-arm64@0.27.1':
optional: true
- '@esbuild/win32-ia32@0.27.0':
+ '@esbuild/win32-ia32@0.27.1':
optional: true
- '@esbuild/win32-x64@0.27.0':
+ '@esbuild/win32-x64@0.27.1':
optional: true
'@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)':
@@ -2471,7 +2399,7 @@ snapshots:
dependencies:
'@types/json-schema': 7.0.15
- '@eslint/eslintrc@3.3.1':
+ '@eslint/eslintrc@3.3.3':
dependencies:
ajv: 6.12.6
debug: 4.4.3(supports-color@8.1.1)
@@ -2507,18 +2435,11 @@ snapshots:
'@iconify/types@2.0.0': {}
- '@iconify/utils@3.0.2':
+ '@iconify/utils@3.1.0':
dependencies:
'@antfu/install-pkg': 1.1.0
- '@antfu/utils': 9.3.0
'@iconify/types': 2.0.0
- debug: 4.4.3(supports-color@8.1.1)
- globals: 15.15.0
- kolorist: 1.8.0
- local-pkg: 1.1.2
mlly: 1.8.0
- transitivePeerDependencies:
- - supports-color
'@isaacs/cliui@8.0.2':
dependencies:
@@ -2529,92 +2450,92 @@ snapshots:
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
- '@lezer/common@1.3.0': {}
+ '@lezer/common@1.4.0': {}
'@lezer/cpp@1.1.3':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
'@lezer/css@1.3.0':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
'@lezer/go@1.0.1':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
'@lezer/highlight@1.2.3':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/html@1.3.12':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
'@lezer/java@1.1.3':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
'@lezer/javascript@1.5.4':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
'@lezer/json@1.0.3':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
- '@lezer/lr@1.4.3':
+ '@lezer/lr@1.4.4':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/markdown@1.6.0':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
'@lezer/php@1.0.5':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
'@lezer/python@1.1.18':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
'@lezer/rust@1.0.2':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
'@lezer/xml@1.0.6':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
'@lezer/yaml@1.0.3':
dependencies:
- '@lezer/common': 1.3.0
+ '@lezer/common': 1.4.0
'@lezer/highlight': 1.2.3
- '@lezer/lr': 1.4.3
+ '@lezer/lr': 1.4.4
'@marijn/find-cluster-break@1.0.2': {}
@@ -2624,62 +2545,50 @@ snapshots:
dependencies:
langium: 3.3.1
- '@napi-rs/canvas-android-arm64@0.1.82':
+ '@napi-rs/canvas-android-arm64@0.1.83':
optional: true
- '@napi-rs/canvas-darwin-arm64@0.1.82':
+ '@napi-rs/canvas-darwin-arm64@0.1.83':
optional: true
- '@napi-rs/canvas-darwin-x64@0.1.82':
+ '@napi-rs/canvas-darwin-x64@0.1.83':
optional: true
- '@napi-rs/canvas-linux-arm-gnueabihf@0.1.82':
+ '@napi-rs/canvas-linux-arm-gnueabihf@0.1.83':
optional: true
- '@napi-rs/canvas-linux-arm64-gnu@0.1.82':
+ '@napi-rs/canvas-linux-arm64-gnu@0.1.83':
optional: true
- '@napi-rs/canvas-linux-arm64-musl@0.1.82':
+ '@napi-rs/canvas-linux-arm64-musl@0.1.83':
optional: true
- '@napi-rs/canvas-linux-riscv64-gnu@0.1.82':
+ '@napi-rs/canvas-linux-riscv64-gnu@0.1.83':
optional: true
- '@napi-rs/canvas-linux-x64-gnu@0.1.82':
+ '@napi-rs/canvas-linux-x64-gnu@0.1.83':
optional: true
- '@napi-rs/canvas-linux-x64-musl@0.1.82':
+ '@napi-rs/canvas-linux-x64-musl@0.1.83':
optional: true
- '@napi-rs/canvas-win32-x64-msvc@0.1.82':
+ '@napi-rs/canvas-win32-x64-msvc@0.1.83':
optional: true
- '@napi-rs/canvas@0.1.82':
+ '@napi-rs/canvas@0.1.83':
optionalDependencies:
- '@napi-rs/canvas-android-arm64': 0.1.82
- '@napi-rs/canvas-darwin-arm64': 0.1.82
- '@napi-rs/canvas-darwin-x64': 0.1.82
- '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.82
- '@napi-rs/canvas-linux-arm64-gnu': 0.1.82
- '@napi-rs/canvas-linux-arm64-musl': 0.1.82
- '@napi-rs/canvas-linux-riscv64-gnu': 0.1.82
- '@napi-rs/canvas-linux-x64-gnu': 0.1.82
- '@napi-rs/canvas-linux-x64-musl': 0.1.82
- '@napi-rs/canvas-win32-x64-msvc': 0.1.82
+ '@napi-rs/canvas-android-arm64': 0.1.83
+ '@napi-rs/canvas-darwin-arm64': 0.1.83
+ '@napi-rs/canvas-darwin-x64': 0.1.83
+ '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.83
+ '@napi-rs/canvas-linux-arm64-gnu': 0.1.83
+ '@napi-rs/canvas-linux-arm64-musl': 0.1.83
+ '@napi-rs/canvas-linux-riscv64-gnu': 0.1.83
+ '@napi-rs/canvas-linux-x64-gnu': 0.1.83
+ '@napi-rs/canvas-linux-x64-musl': 0.1.83
+ '@napi-rs/canvas-win32-x64-msvc': 0.1.83
optional: true
- '@nodelib/fs.scandir@2.1.5':
- dependencies:
- '@nodelib/fs.stat': 2.0.5
- run-parallel: 1.2.0
-
- '@nodelib/fs.stat@2.0.5': {}
-
- '@nodelib/fs.walk@1.2.8':
- dependencies:
- '@nodelib/fs.scandir': 2.1.5
- fastq: 1.19.1
-
'@pkgjs/parseargs@0.11.0':
optional: true
@@ -2832,14 +2741,14 @@ snapshots:
'@types/trusted-types@2.0.7':
optional: true
- '@typescript-eslint/eslint-plugin@8.46.4(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)':
+ '@typescript-eslint/eslint-plugin@8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
- '@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
- '@typescript-eslint/scope-manager': 8.46.4
- '@typescript-eslint/type-utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
- '@typescript-eslint/utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
- '@typescript-eslint/visitor-keys': 8.46.4
+ '@typescript-eslint/parser': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/scope-manager': 8.48.1
+ '@typescript-eslint/type-utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/visitor-keys': 8.48.1
eslint: 9.39.1
graphemer: 1.4.0
ignore: 7.0.5
@@ -2849,41 +2758,41 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3)':
+ '@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
- '@typescript-eslint/scope-manager': 8.46.4
- '@typescript-eslint/types': 8.46.4
- '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
- '@typescript-eslint/visitor-keys': 8.46.4
+ '@typescript-eslint/scope-manager': 8.48.1
+ '@typescript-eslint/types': 8.48.1
+ '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3)
+ '@typescript-eslint/visitor-keys': 8.48.1
debug: 4.4.3(supports-color@8.1.1)
eslint: 9.39.1
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/project-service@8.46.4(typescript@5.9.3)':
+ '@typescript-eslint/project-service@8.48.1(typescript@5.9.3)':
dependencies:
- '@typescript-eslint/tsconfig-utils': 8.46.4(typescript@5.9.3)
- '@typescript-eslint/types': 8.46.4
+ '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3)
+ '@typescript-eslint/types': 8.48.1
debug: 4.4.3(supports-color@8.1.1)
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/scope-manager@8.46.4':
+ '@typescript-eslint/scope-manager@8.48.1':
dependencies:
- '@typescript-eslint/types': 8.46.4
- '@typescript-eslint/visitor-keys': 8.46.4
+ '@typescript-eslint/types': 8.48.1
+ '@typescript-eslint/visitor-keys': 8.48.1
- '@typescript-eslint/tsconfig-utils@8.46.4(typescript@5.9.3)':
+ '@typescript-eslint/tsconfig-utils@8.48.1(typescript@5.9.3)':
dependencies:
typescript: 5.9.3
- '@typescript-eslint/type-utils@8.46.4(eslint@9.39.1)(typescript@5.9.3)':
+ '@typescript-eslint/type-utils@8.48.1(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
- '@typescript-eslint/types': 8.46.4
- '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
- '@typescript-eslint/utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/types': 8.48.1
+ '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
debug: 4.4.3(supports-color@8.1.1)
eslint: 9.39.1
ts-api-utils: 2.1.0(typescript@5.9.3)
@@ -2891,38 +2800,37 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/types@8.46.4': {}
+ '@typescript-eslint/types@8.48.1': {}
- '@typescript-eslint/typescript-estree@8.46.4(typescript@5.9.3)':
+ '@typescript-eslint/typescript-estree@8.48.1(typescript@5.9.3)':
dependencies:
- '@typescript-eslint/project-service': 8.46.4(typescript@5.9.3)
- '@typescript-eslint/tsconfig-utils': 8.46.4(typescript@5.9.3)
- '@typescript-eslint/types': 8.46.4
- '@typescript-eslint/visitor-keys': 8.46.4
+ '@typescript-eslint/project-service': 8.48.1(typescript@5.9.3)
+ '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3)
+ '@typescript-eslint/types': 8.48.1
+ '@typescript-eslint/visitor-keys': 8.48.1
debug: 4.4.3(supports-color@8.1.1)
- fast-glob: 3.3.3
- is-glob: 4.0.3
minimatch: 9.0.5
semver: 7.7.3
+ tinyglobby: 0.2.15
ts-api-utils: 2.1.0(typescript@5.9.3)
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/utils@8.46.4(eslint@9.39.1)(typescript@5.9.3)':
+ '@typescript-eslint/utils@8.48.1(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1)
- '@typescript-eslint/scope-manager': 8.46.4
- '@typescript-eslint/types': 8.46.4
- '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
+ '@typescript-eslint/scope-manager': 8.48.1
+ '@typescript-eslint/types': 8.48.1
+ '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3)
eslint: 9.39.1
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/visitor-keys@8.46.4':
+ '@typescript-eslint/visitor-keys@8.48.1':
dependencies:
- '@typescript-eslint/types': 8.46.4
+ '@typescript-eslint/types': 8.48.1
eslint-visitor-keys: 4.2.1
acorn-jsx@5.3.2(acorn@8.15.0):
@@ -3019,10 +2927,6 @@ snapshots:
dependencies:
balanced-match: 1.0.2
- braces@3.0.3:
- dependencies:
- fill-range: 7.1.1
-
browser-stdout@1.3.1: {}
call-bind-apply-helpers@1.0.2:
@@ -3079,7 +2983,7 @@ snapshots:
codemirror@6.0.2:
dependencies:
- '@codemirror/autocomplete': 6.19.1
+ '@codemirror/autocomplete': 6.20.0
'@codemirror/commands': 6.10.0
'@codemirror/language': 6.11.3
'@codemirror/lint': 6.9.2
@@ -3101,8 +3005,6 @@ snapshots:
confbox@0.1.8: {}
- confbox@0.2.2: {}
-
cose-base@1.0.3:
dependencies:
layout-base: 1.0.2
@@ -3457,34 +3359,34 @@ snapshots:
is-date-object: 1.1.0
is-symbol: 1.1.1
- esbuild@0.27.0:
+ esbuild@0.27.1:
optionalDependencies:
- '@esbuild/aix-ppc64': 0.27.0
- '@esbuild/android-arm': 0.27.0
- '@esbuild/android-arm64': 0.27.0
- '@esbuild/android-x64': 0.27.0
- '@esbuild/darwin-arm64': 0.27.0
- '@esbuild/darwin-x64': 0.27.0
- '@esbuild/freebsd-arm64': 0.27.0
- '@esbuild/freebsd-x64': 0.27.0
- '@esbuild/linux-arm': 0.27.0
- '@esbuild/linux-arm64': 0.27.0
- '@esbuild/linux-ia32': 0.27.0
- '@esbuild/linux-loong64': 0.27.0
- '@esbuild/linux-mips64el': 0.27.0
- '@esbuild/linux-ppc64': 0.27.0
- '@esbuild/linux-riscv64': 0.27.0
- '@esbuild/linux-s390x': 0.27.0
- '@esbuild/linux-x64': 0.27.0
- '@esbuild/netbsd-arm64': 0.27.0
- '@esbuild/netbsd-x64': 0.27.0
- '@esbuild/openbsd-arm64': 0.27.0
- '@esbuild/openbsd-x64': 0.27.0
- '@esbuild/openharmony-arm64': 0.27.0
- '@esbuild/sunos-x64': 0.27.0
- '@esbuild/win32-arm64': 0.27.0
- '@esbuild/win32-ia32': 0.27.0
- '@esbuild/win32-x64': 0.27.0
+ '@esbuild/aix-ppc64': 0.27.1
+ '@esbuild/android-arm': 0.27.1
+ '@esbuild/android-arm64': 0.27.1
+ '@esbuild/android-x64': 0.27.1
+ '@esbuild/darwin-arm64': 0.27.1
+ '@esbuild/darwin-x64': 0.27.1
+ '@esbuild/freebsd-arm64': 0.27.1
+ '@esbuild/freebsd-x64': 0.27.1
+ '@esbuild/linux-arm': 0.27.1
+ '@esbuild/linux-arm64': 0.27.1
+ '@esbuild/linux-ia32': 0.27.1
+ '@esbuild/linux-loong64': 0.27.1
+ '@esbuild/linux-mips64el': 0.27.1
+ '@esbuild/linux-ppc64': 0.27.1
+ '@esbuild/linux-riscv64': 0.27.1
+ '@esbuild/linux-s390x': 0.27.1
+ '@esbuild/linux-x64': 0.27.1
+ '@esbuild/netbsd-arm64': 0.27.1
+ '@esbuild/netbsd-x64': 0.27.1
+ '@esbuild/openbsd-arm64': 0.27.1
+ '@esbuild/openbsd-x64': 0.27.1
+ '@esbuild/openharmony-arm64': 0.27.1
+ '@esbuild/sunos-x64': 0.27.1
+ '@esbuild/win32-arm64': 0.27.1
+ '@esbuild/win32-ia32': 0.27.1
+ '@esbuild/win32-x64': 0.27.1
escalade@3.2.0: {}
@@ -3502,17 +3404,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-module-utils@2.12.1(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1):
+ eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1):
dependencies:
debug: 3.2.7
optionalDependencies:
- '@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/parser': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
eslint: 9.39.1
eslint-import-resolver-node: 0.3.9
transitivePeerDependencies:
- supports-color
- eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1):
+ eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.9
@@ -3523,7 +3425,7 @@ snapshots:
doctrine: 2.1.0
eslint: 9.39.1
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1)
+ eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1)
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -3535,16 +3437,16 @@ snapshots:
string.prototype.trimend: 1.0.9
tsconfig-paths: 3.15.0
optionalDependencies:
- '@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/parser': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
- supports-color
- eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.6.2):
+ eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.7.4):
dependencies:
eslint: 9.39.1
- prettier: 3.6.2
+ prettier: 3.7.4
prettier-linter-helpers: 1.0.0
synckit: 0.11.11
optionalDependencies:
@@ -3566,7 +3468,7 @@ snapshots:
'@eslint/config-array': 0.21.1
'@eslint/config-helpers': 0.4.2
'@eslint/core': 0.17.0
- '@eslint/eslintrc': 3.3.1
+ '@eslint/eslintrc': 3.3.3
'@eslint/js': 9.39.1
'@eslint/plugin-kit': 0.4.1
'@humanfs/node': 0.16.7
@@ -3616,36 +3518,22 @@ snapshots:
esutils@2.0.3: {}
- exsolve@1.0.8: {}
-
fast-deep-equal@3.1.3: {}
fast-diff@1.3.0: {}
- fast-glob@3.3.3:
- dependencies:
- '@nodelib/fs.stat': 2.0.5
- '@nodelib/fs.walk': 1.2.8
- glob-parent: 5.1.2
- merge2: 1.4.1
- micromatch: 4.0.8
-
fast-json-stable-stringify@2.1.0: {}
fast-levenshtein@2.0.6: {}
- fastq@1.19.1:
- dependencies:
- reusify: 1.1.0
+ fdir@6.5.0(picomatch@4.0.3):
+ optionalDependencies:
+ picomatch: 4.0.3
file-entry-cache@8.0.0:
dependencies:
flat-cache: 4.0.1
- fill-range@7.1.1:
- dependencies:
- to-regex-range: 5.0.1
-
find-up@5.0.0:
dependencies:
locate-path: 6.0.0
@@ -3710,15 +3598,11 @@ snapshots:
es-errors: 1.3.0
get-intrinsic: 1.3.0
- glob-parent@5.1.2:
- dependencies:
- is-glob: 4.0.3
-
glob-parent@6.0.2:
dependencies:
is-glob: 4.0.3
- glob@10.4.5:
+ glob@10.5.0:
dependencies:
foreground-child: 3.3.1
jackspeak: 3.4.3
@@ -3729,8 +3613,6 @@ snapshots:
globals@14.0.0: {}
- globals@15.15.0: {}
-
globalthis@1.0.4:
dependencies:
define-properties: 1.2.1
@@ -3862,8 +3744,6 @@ snapshots:
call-bound: 1.0.4
has-tostringtag: 1.0.2
- is-number@7.0.0: {}
-
is-path-inside@3.0.3: {}
is-plain-obj@2.1.0: {}
@@ -3943,8 +3823,6 @@ snapshots:
khroma@2.1.0: {}
- kolorist@1.8.0: {}
-
langium@3.3.1:
dependencies:
chevrotain: 11.0.3
@@ -3962,12 +3840,6 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
- local-pkg@1.1.2:
- dependencies:
- mlly: 1.8.0
- pkg-types: 2.3.0
- quansync: 0.2.11
-
locate-path@6.0.0:
dependencies:
p-locate: 5.0.0
@@ -3991,12 +3863,10 @@ snapshots:
dependencies:
'@mathjax/mathjax-newcm-font': 4.0.0
- merge2@1.4.1: {}
-
- mermaid@11.12.1:
+ mermaid@11.12.2:
dependencies:
'@braintree/sanitize-url': 7.1.1
- '@iconify/utils': 3.0.2
+ '@iconify/utils': 3.1.0
'@mermaid-js/parser': 0.6.3
'@types/d3': 7.4.3
cytoscape: 3.33.1
@@ -4015,13 +3885,6 @@ snapshots:
stylis: 4.3.6
ts-dedent: 2.2.0
uuid: 11.1.0
- transitivePeerDependencies:
- - supports-color
-
- micromatch@4.0.8:
- dependencies:
- braces: 3.0.3
- picomatch: 2.3.1
minimatch@3.1.2:
dependencies:
@@ -4050,7 +3913,7 @@ snapshots:
diff: 7.0.0
escape-string-regexp: 4.0.0
find-up: 5.0.0
- glob: 10.4.5
+ glob: 10.5.0
he: 1.2.0
is-path-inside: 3.0.3
js-yaml: 4.1.1
@@ -4130,7 +3993,7 @@ snapshots:
package-json-from-dist@1.0.1: {}
- package-manager-detector@1.5.0: {}
+ package-manager-detector@1.6.0: {}
parent-module@1.0.1:
dependencies:
@@ -4151,13 +4014,13 @@ snapshots:
pathe@2.0.3: {}
- pdfjs-dist@5.4.394:
+ pdfjs-dist@5.4.449:
optionalDependencies:
- '@napi-rs/canvas': 0.1.82
+ '@napi-rs/canvas': 0.1.83
picocolors@1.1.1: {}
- picomatch@2.3.1: {}
+ picomatch@4.0.3: {}
pkg-types@1.3.1:
dependencies:
@@ -4165,12 +4028,6 @@ snapshots:
mlly: 1.8.0
pathe: 2.0.3
- pkg-types@2.3.0:
- dependencies:
- confbox: 0.2.2
- exsolve: 1.0.8
- pathe: 2.0.3
-
points-on-curve@0.2.0: {}
points-on-path@0.2.1:
@@ -4186,14 +4043,10 @@ snapshots:
dependencies:
fast-diff: 1.3.0
- prettier@3.6.2: {}
+ prettier@3.7.4: {}
punycode@2.3.1: {}
- quansync@0.2.11: {}
-
- queue-microtask@1.2.3: {}
-
randombytes@2.1.0:
dependencies:
safe-buffer: 5.2.1
@@ -4230,8 +4083,6 @@ snapshots:
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
- reusify@1.1.0: {}
-
robust-predicates@3.0.2: {}
roughjs@4.6.6:
@@ -4241,10 +4092,6 @@ snapshots:
points-on-curve: 0.2.0
points-on-path: 0.2.1
- run-parallel@1.2.0:
- dependencies:
- queue-microtask: 1.2.3
-
rw@1.3.3: {}
safe-array-concat@1.1.3:
@@ -4408,11 +4255,12 @@ snapshots:
tinyexec@1.0.2: {}
- tinymce@8.2.2: {}
-
- to-regex-range@5.0.1:
+ tinyglobby@0.2.15:
dependencies:
- is-number: 7.0.0
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+
+ tinymce@8.2.2: {}
toastify-js@1.12.0: {}
diff --git a/extensions/VSCode/Cargo.lock b/extensions/VSCode/Cargo.lock
index 8032fca6..ca59d901 100644
--- a/extensions/VSCode/Cargo.lock
+++ b/extensions/VSCode/Cargo.lock
@@ -21,9 +21,9 @@ dependencies = [
[[package]]
name = "actix-files"
-version = "0.6.8"
+version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c0d87f10d70e2948ad40e8edea79c8e77c6c66e0250a4c1f09b690465199576"
+checksum = "4009a8beb4dc78a58286ac9d58969ee0a8acecb7912d5ce898b4da4335579341"
dependencies = [
"actix-http",
"actix-service",
@@ -88,7 +88,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
dependencies = [
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -156,9 +156,9 @@ dependencies = [
[[package]]
name = "actix-web"
-version = "4.12.0"
+version = "4.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2233f53f6cb18ae038ce1f0713ca0c72ca0c4b71fe9aaeb59924ce2c89c6dd85"
+checksum = "1654a77ba142e37f049637a3e5685f864514af11fcbc51cb51eb6596afe5b8d6"
dependencies = [
"actix-codec",
"actix-http",
@@ -206,7 +206,7 @@ dependencies = [
"actix-router",
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -353,7 +353,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -445,9 +445,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.2.46"
+version = "1.2.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36"
+checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a"
dependencies = [
"find-msvc-tools",
"jobserver",
@@ -482,9 +482,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.51"
+version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
+checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
dependencies = [
"clap_builder",
"clap_derive",
@@ -492,9 +492,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.51"
+version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
+checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
dependencies = [
"anstream",
"anstyle",
@@ -511,7 +511,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -532,6 +532,7 @@ dependencies = [
"actix-web",
"actix-web-httpauth",
"actix-ws",
+ "anyhow",
"bytes",
"chrono",
"clap",
@@ -603,9 +604,9 @@ checksum = "fb58b6451e8c2a812ad979ed1d83378caa5e927eef2622017a45f251457c2c9d"
[[package]]
name = "convert_case"
-version = "0.9.0"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db05ffb6856bf0ecdf6367558a76a0e8a77b1713044eb92845c692100ed50190"
+checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
dependencies = [
"unicode-segmentation",
]
@@ -667,9 +668,9 @@ dependencies = [
[[package]]
name = "ctor"
-version = "0.6.1"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ffc71fcdcdb40d6f087edddf7f8f1f8f79e6cf922f555a9ee8779752d4819bd"
+checksum = "eb230974aaf0aca4d71665bed0aca156cf43b764fcb9583b69c6c3e686f35e72"
dependencies = [
"ctor-proc-macro",
"dtor",
@@ -692,22 +693,24 @@ dependencies = [
[[package]]
name = "derive_more"
-version = "2.0.1"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
+checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618"
dependencies = [
"derive_more-impl",
]
[[package]]
name = "derive_more-impl"
-version = "2.0.1"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
+checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b"
dependencies = [
+ "convert_case",
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "rustc_version",
+ "syn 2.0.111",
"unicode-xid",
]
@@ -736,7 +739,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -947,7 +950,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -1034,9 +1037,9 @@ dependencies = [
[[package]]
name = "hashbrown"
-version = "0.16.0"
+version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]]
name = "heck"
@@ -1055,8 +1058,9 @@ dependencies = [
[[package]]
name = "htmd"
-version = "0.3.2"
-source = "git+https://github.com/bjones1/htmd.git?branch=fix-faithful-serialization#e13d5a5ed195163c60b0c59974fc5bb521bdd70b"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60ae59466542f2346e43d4a5e9b4432a1fc915b279c9fc0484e9ed7379121454"
dependencies = [
"html5ever",
"markup5ever_rcdom",
@@ -1253,12 +1257,12 @@ checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2"
[[package]]
name = "indexmap"
-version = "2.12.0"
+version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
+checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
dependencies = [
"equivalent",
- "hashbrown 0.16.0",
+ "hashbrown 0.16.1",
"serde",
"serde_core",
]
@@ -1338,9 +1342,9 @@ dependencies = [
[[package]]
name = "js-sys"
-version = "0.3.82"
+version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
+checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
dependencies = [
"once_cell",
"wasm-bindgen",
@@ -1380,9 +1384,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
-version = "0.2.177"
+version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
+checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]]
name = "libloading"
@@ -1439,11 +1443,11 @@ dependencies = [
[[package]]
name = "log"
-version = "0.4.28"
+version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
dependencies = [
- "serde",
+ "serde_core",
]
[[package]]
@@ -1518,7 +1522,7 @@ checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -1589,9 +1593,9 @@ checksum = "dce6dd36094cac388f119d2e9dc82dc730ef91c32a6222170d630e5414b956e6"
[[package]]
name = "napi"
-version = "3.5.2"
+version = "3.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e917a98ac74187a5d486604a269ed69cd7901dd4824453d5573fb051f69b1b3"
+checksum = "3af30fe8e799dda3a555c496c59e960e4cff1e931b63acbaf3a3b25d9fad22b6"
dependencies = [
"bitflags 2.10.0",
"ctor",
@@ -1611,36 +1615,36 @@ checksum = "d376940fd5b723c6893cd1ee3f33abbfd86acb1cd1ec079f3ab04a2a3bc4d3b1"
[[package]]
name = "napi-derive"
-version = "3.3.3"
+version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a258a6521951715e00568b258b8fb7a44c6087f588c371dc6b84a413f2728fdb"
+checksum = "47cffa09ea668c4cc5d7b1198780882e28780ed1804a903b80680725426223d9"
dependencies = [
"convert_case",
"ctor",
"napi-derive-backend",
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
name = "napi-derive-backend"
-version = "3.0.2"
+version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77c36636292fe04366a1eec028adc25bc72f4fd7cce35bdcc310499ef74fb7de"
+checksum = "5e186227ec22f4675267a176d98dffecb27e6cc88926cbb7efb5427268565c0f"
dependencies = [
"convert_case",
"proc-macro2",
"quote",
"semver",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
name = "napi-sys"
-version = "3.1.1"
+version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50ef9c1086f16aea2417c3788dbefed7591c3bccd800b827f4dfb271adff1149"
+checksum = "8eb602b84d7c1edae45e50bbf1374696548f36ae179dfa667f577e384bb90c2b"
dependencies = [
"libloading",
]
@@ -1804,9 +1808,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "pest"
-version = "2.8.3"
+version = "2.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4"
+checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22"
dependencies = [
"memchr",
"ucd-trie",
@@ -1814,9 +1818,9 @@ dependencies = [
[[package]]
name = "pest_derive"
-version = "2.8.3"
+version = "2.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de"
+checksum = "51f72981ade67b1ca6adc26ec221be9f463f2b5839c7508998daa17c23d94d7f"
dependencies = [
"pest",
"pest_generator",
@@ -1824,22 +1828,22 @@ dependencies = [
[[package]]
name = "pest_generator"
-version = "2.8.3"
+version = "2.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843"
+checksum = "dee9efd8cdb50d719a80088b76f81aec7c41ed6d522ee750178f83883d271625"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
name = "pest_meta"
-version = "2.8.3"
+version = "2.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a"
+checksum = "bf1d70880e76bdc13ba52eafa6239ce793d85c8e43896507e43dd8984ff05b82"
dependencies = [
"pest",
"sha2",
@@ -1905,7 +1909,7 @@ dependencies = [
"phf_shared 0.13.1",
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -2151,6 +2155,15 @@ version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
[[package]]
name = "rustversion"
version = "1.0.22"
@@ -2221,7 +2234,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -2292,9 +2305,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook-registry"
-version = "1.4.6"
+version = "1.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
+checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad"
dependencies = [
"libc",
]
@@ -2410,9 +2423,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.110"
+version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
+checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [
"proc-macro2",
"quote",
@@ -2427,7 +2440,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -2476,7 +2489,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -2487,7 +2500,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -2581,7 +2594,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -2625,9 +2638,9 @@ dependencies = [
[[package]]
name = "tracing"
-version = "0.1.41"
+version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647"
dependencies = [
"log",
"pin-project-lite",
@@ -2637,20 +2650,20 @@ dependencies = [
[[package]]
name = "tracing-attributes"
-version = "0.1.30"
+version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
name = "tracing-core"
-version = "0.1.34"
+version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
+checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c"
dependencies = [
"once_cell",
]
@@ -2673,7 +2686,7 @@ checksum = "ee6ff59666c9cbaec3533964505d39154dc4e0a56151fdea30a09ed0301f62e2"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
"termcolor",
]
@@ -2851,9 +2864,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
[[package]]
name = "wasm-bindgen"
-version = "0.2.105"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
+checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
dependencies = [
"cfg-if",
"once_cell",
@@ -2864,9 +2877,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.105"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
+checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -2874,31 +2887,31 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.105"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
+checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.105"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
+checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
dependencies = [
"unicode-ident",
]
[[package]]
name = "web-sys"
-version = "0.3.82"
+version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1"
+checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -3015,7 +3028,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -3026,7 +3039,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -3341,28 +3354,28 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
"synstructure",
]
[[package]]
name = "zerocopy"
-version = "0.8.27"
+version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
+checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
-version = "0.8.27"
+version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
+checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -3382,7 +3395,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
"synstructure",
]
@@ -3416,7 +3429,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
diff --git a/extensions/VSCode/package.json b/extensions/VSCode/package.json
index 8723d3cd..9a52f24e 100644
--- a/extensions/VSCode/package.json
+++ b/extensions/VSCode/package.json
@@ -81,23 +81,23 @@
"devDependencies": {
"@emnapi/core": "^1.7.1",
"@emnapi/runtime": "^1.7.1",
- "@napi-rs/cli": "^3.4.1",
+ "@napi-rs/cli": "^3.5.0",
"@tybys/wasm-util": "^0.10.1",
"@types/escape-html": "^1.0.4",
"@types/node": "^24.10.1",
"@types/vscode": "1.61.0",
- "@typescript-eslint/eslint-plugin": "^8.46.4",
- "@typescript-eslint/parser": "^8.46.4",
- "@vscode/vsce": "^3.7.0",
+ "@typescript-eslint/eslint-plugin": "^8.48.1",
+ "@typescript-eslint/parser": "^8.48.1",
+ "@vscode/vsce": "^3.7.1",
"chalk": "^5.6.2",
- "esbuild": "^0.27.0",
+ "esbuild": "^0.27.1",
"eslint": "^9.39.1",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-node": "^11.1.0",
"npm-run-all2": "^8.0.4",
- "ovsx": "^0.10.6",
- "prettier": "^3.6.2",
+ "ovsx": "^0.10.7",
+ "prettier": "^3.7.4",
"typescript": "^5.9.3"
},
"optionalDependencies": {
diff --git a/extensions/VSCode/pnpm-lock.yaml b/extensions/VSCode/pnpm-lock.yaml
index a02d9e62..8c3838d7 100644
--- a/extensions/VSCode/pnpm-lock.yaml
+++ b/extensions/VSCode/pnpm-lock.yaml
@@ -19,8 +19,8 @@ importers:
specifier: ^1.7.1
version: 1.7.1
'@napi-rs/cli':
- specifier: ^3.4.1
- version: 3.4.1(@emnapi/runtime@1.7.1)(@types/node@24.10.1)
+ specifier: ^3.5.0
+ version: 3.5.0(@emnapi/runtime@1.7.1)(@types/node@24.10.1)
'@tybys/wasm-util':
specifier: ^0.10.1
version: 0.10.1
@@ -34,20 +34,20 @@ importers:
specifier: 1.61.0
version: 1.61.0
'@typescript-eslint/eslint-plugin':
- specifier: ^8.46.4
- version: 8.46.4(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
+ specifier: ^8.48.1
+ version: 8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
'@typescript-eslint/parser':
- specifier: ^8.46.4
- version: 8.46.4(eslint@9.39.1)(typescript@5.9.3)
+ specifier: ^8.48.1
+ version: 8.48.1(eslint@9.39.1)(typescript@5.9.3)
'@vscode/vsce':
- specifier: ^3.7.0
- version: 3.7.0
+ specifier: ^3.7.1
+ version: 3.7.1
chalk:
specifier: ^5.6.2
version: 5.6.2
esbuild:
- specifier: ^0.27.0
- version: 0.27.0
+ specifier: ^0.27.1
+ version: 0.27.1
eslint:
specifier: ^9.39.1
version: 9.39.1
@@ -56,7 +56,7 @@ importers:
version: 10.1.8(eslint@9.39.1)
eslint-plugin-import:
specifier: ^2.32.0
- version: 2.32.0(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)
+ version: 2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)
eslint-plugin-node:
specifier: ^11.1.0
version: 11.1.0(eslint@9.39.1)
@@ -64,11 +64,11 @@ importers:
specifier: ^8.0.4
version: 8.0.4
ovsx:
- specifier: ^0.10.6
- version: 0.10.6
+ specifier: ^0.10.7
+ version: 0.10.7
prettier:
- specifier: ^3.6.2
- version: 3.6.2
+ specifier: ^3.7.4
+ version: 3.7.4
typescript:
specifier: ^5.9.3
version: 5.9.3
@@ -117,16 +117,16 @@ packages:
resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==}
engines: {node: '>=20.0.0'}
- '@azure/msal-browser@4.26.1':
- resolution: {integrity: sha512-GGCIsZXxyNm5QcQZ4maA9q+9UWmM+/87G+ybvPkrE32el1URSa9WYt0t67ks3/P0gspZX9RoEqyLqJ/X/JDnBQ==}
+ '@azure/msal-browser@4.26.2':
+ resolution: {integrity: sha512-F2U1mEAFsYGC5xzo1KuWc/Sy3CRglU9Ql46cDUx8x/Y3KnAIr1QAq96cIKCk/ZfnVxlvprXWRjNKoEpgLJXLhg==}
engines: {node: '>=0.8.0'}
- '@azure/msal-common@15.13.1':
- resolution: {integrity: sha512-vQYQcG4J43UWgo1lj7LcmdsGUKWYo28RfEvDQAEMmQIMjSFufvb+pS0FJ3KXmrPmnWlt1vHDl3oip6mIDUQ4uA==}
+ '@azure/msal-common@15.13.2':
+ resolution: {integrity: sha512-cNwUoCk3FF8VQ7Ln/MdcJVIv3sF73/OT86cRH81ECsydh7F4CNfIo2OAx6Cegtg8Yv75x4506wN4q+Emo6erOA==}
engines: {node: '>=0.8.0'}
- '@azure/msal-node@3.8.2':
- resolution: {integrity: sha512-dQrex2LiXwlCe9WuBHnCsY+xxLyuMXSd2SDEYJuhqB7cE8u6QafiC1xy8j8eBjGO30AsRi2M6amH0ZKk7vJpjA==}
+ '@azure/msal-node@3.8.3':
+ resolution: {integrity: sha512-Ul7A4gwmaHzYWj2Z5xBDly/W8JSC1vnKgJ898zPMZr0oSf1ah0tiL15sytjycU/PMhDZAlkWtEL1+MzNMU6uww==}
engines: {node: '>=16'}
'@babel/code-frame@7.27.1':
@@ -146,158 +146,158 @@ packages:
'@emnapi/wasi-threads@1.1.0':
resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
- '@esbuild/aix-ppc64@0.27.0':
- resolution: {integrity: sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==}
+ '@esbuild/aix-ppc64@0.27.1':
+ resolution: {integrity: sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
- '@esbuild/android-arm64@0.27.0':
- resolution: {integrity: sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==}
+ '@esbuild/android-arm64@0.27.1':
+ resolution: {integrity: sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
- '@esbuild/android-arm@0.27.0':
- resolution: {integrity: sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==}
+ '@esbuild/android-arm@0.27.1':
+ resolution: {integrity: sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
- '@esbuild/android-x64@0.27.0':
- resolution: {integrity: sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==}
+ '@esbuild/android-x64@0.27.1':
+ resolution: {integrity: sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
- '@esbuild/darwin-arm64@0.27.0':
- resolution: {integrity: sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==}
+ '@esbuild/darwin-arm64@0.27.1':
+ resolution: {integrity: sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-x64@0.27.0':
- resolution: {integrity: sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==}
+ '@esbuild/darwin-x64@0.27.1':
+ resolution: {integrity: sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
- '@esbuild/freebsd-arm64@0.27.0':
- resolution: {integrity: sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==}
+ '@esbuild/freebsd-arm64@0.27.1':
+ resolution: {integrity: sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.27.0':
- resolution: {integrity: sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==}
+ '@esbuild/freebsd-x64@0.27.1':
+ resolution: {integrity: sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
- '@esbuild/linux-arm64@0.27.0':
- resolution: {integrity: sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==}
+ '@esbuild/linux-arm64@0.27.1':
+ resolution: {integrity: sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm@0.27.0':
- resolution: {integrity: sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==}
+ '@esbuild/linux-arm@0.27.1':
+ resolution: {integrity: sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
- '@esbuild/linux-ia32@0.27.0':
- resolution: {integrity: sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==}
+ '@esbuild/linux-ia32@0.27.1':
+ resolution: {integrity: sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
- '@esbuild/linux-loong64@0.27.0':
- resolution: {integrity: sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==}
+ '@esbuild/linux-loong64@0.27.1':
+ resolution: {integrity: sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
- '@esbuild/linux-mips64el@0.27.0':
- resolution: {integrity: sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==}
+ '@esbuild/linux-mips64el@0.27.1':
+ resolution: {integrity: sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-ppc64@0.27.0':
- resolution: {integrity: sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==}
+ '@esbuild/linux-ppc64@0.27.1':
+ resolution: {integrity: sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-riscv64@0.27.0':
- resolution: {integrity: sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==}
+ '@esbuild/linux-riscv64@0.27.1':
+ resolution: {integrity: sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-s390x@0.27.0':
- resolution: {integrity: sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==}
+ '@esbuild/linux-s390x@0.27.1':
+ resolution: {integrity: sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
- '@esbuild/linux-x64@0.27.0':
- resolution: {integrity: sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==}
+ '@esbuild/linux-x64@0.27.1':
+ resolution: {integrity: sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
- '@esbuild/netbsd-arm64@0.27.0':
- resolution: {integrity: sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==}
+ '@esbuild/netbsd-arm64@0.27.1':
+ resolution: {integrity: sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.27.0':
- resolution: {integrity: sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==}
+ '@esbuild/netbsd-x64@0.27.1':
+ resolution: {integrity: sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
- '@esbuild/openbsd-arm64@0.27.0':
- resolution: {integrity: sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==}
+ '@esbuild/openbsd-arm64@0.27.1':
+ resolution: {integrity: sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.27.0':
- resolution: {integrity: sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==}
+ '@esbuild/openbsd-x64@0.27.1':
+ resolution: {integrity: sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
- '@esbuild/openharmony-arm64@0.27.0':
- resolution: {integrity: sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==}
+ '@esbuild/openharmony-arm64@0.27.1':
+ resolution: {integrity: sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
- '@esbuild/sunos-x64@0.27.0':
- resolution: {integrity: sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==}
+ '@esbuild/sunos-x64@0.27.1':
+ resolution: {integrity: sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
- '@esbuild/win32-arm64@0.27.0':
- resolution: {integrity: sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==}
+ '@esbuild/win32-arm64@0.27.1':
+ resolution: {integrity: sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
- '@esbuild/win32-ia32@0.27.0':
- resolution: {integrity: sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==}
+ '@esbuild/win32-ia32@0.27.1':
+ resolution: {integrity: sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
- '@esbuild/win32-x64@0.27.0':
- resolution: {integrity: sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==}
+ '@esbuild/win32-x64@0.27.1':
+ resolution: {integrity: sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
@@ -324,8 +324,8 @@ packages:
resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/eslintrc@3.3.1':
- resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
+ '@eslint/eslintrc@3.3.3':
+ resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/js@9.39.1':
@@ -356,134 +356,134 @@ packages:
resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
engines: {node: '>=18.18'}
- '@inquirer/ansi@1.0.2':
- resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==}
- engines: {node: '>=18'}
+ '@inquirer/ansi@2.0.2':
+ resolution: {integrity: sha512-SYLX05PwJVnW+WVegZt1T4Ip1qba1ik+pNJPDiqvk6zS5Y/i8PhRzLpGEtVd7sW0G8cMtkD8t4AZYhQwm8vnww==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
- '@inquirer/checkbox@4.3.2':
- resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==}
- engines: {node: '>=18'}
+ '@inquirer/checkbox@5.0.2':
+ resolution: {integrity: sha512-iTPV4tMMct7iOpwer5qmTP7gjnk1VQJjsNfAaC2b8Q3qiuHM3K2yjjDr5u1MKfkrvp2JD4Flf8sIPpF21pmZmw==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
- '@inquirer/confirm@5.1.21':
- resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==}
- engines: {node: '>=18'}
+ '@inquirer/confirm@6.0.2':
+ resolution: {integrity: sha512-A0/13Wyi+8iFeNDX6D4zZYKPoBLIEbE4K/219qHcnpXMer2weWvaTo63+2c7mQPPA206DEMSYVOPnEw3meOlCw==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
- '@inquirer/core@10.3.2':
- resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==}
- engines: {node: '>=18'}
+ '@inquirer/core@11.0.2':
+ resolution: {integrity: sha512-lgMRx/n02ciiNELBvFLHtmcjbV5tf5D/I0UYfCg2YbTZWmBZ10/niLd3IjWBxz8LtM27xP+4oLEa06Slmb7p7A==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
- '@inquirer/editor@4.2.23':
- resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==}
- engines: {node: '>=18'}
+ '@inquirer/editor@5.0.2':
+ resolution: {integrity: sha512-pXQ4Nf0qmFcJuYB6NlcIIxH6l6zKOwNg1Jh/ZRdKd2dTqBB4OXKUFbFwR2K4LVXVtq15ZFFatBVT+rerYR8hWQ==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
- '@inquirer/expand@4.0.23':
- resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==}
- engines: {node: '>=18'}
+ '@inquirer/expand@5.0.2':
+ resolution: {integrity: sha512-siFG1swxfjFIOxIcehtZkh+KUNB/YCpyfHNEGu+nC/SBXIbgUWibvThLn/WesSxLRGOeSKdNKoTm+GQCKFm6Ww==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
- '@inquirer/external-editor@1.0.3':
- resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==}
- engines: {node: '>=18'}
+ '@inquirer/external-editor@2.0.2':
+ resolution: {integrity: sha512-X/fMXK7vXomRWEex1j8mnj7s1mpnTeP4CO/h2gysJhHLT2WjBnLv4ZQEGpm/kcYI8QfLZ2fgW+9kTKD+jeopLg==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
- '@inquirer/figures@1.0.15':
- resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==}
- engines: {node: '>=18'}
+ '@inquirer/figures@2.0.2':
+ resolution: {integrity: sha512-qXm6EVvQx/FmnSrCWCIGtMHwqeLgxABP8XgcaAoywsL0NFga9gD5kfG0gXiv80GjK9Hsoz4pgGwF/+CjygyV9A==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
- '@inquirer/input@4.3.1':
- resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==}
- engines: {node: '>=18'}
+ '@inquirer/input@5.0.2':
+ resolution: {integrity: sha512-hN2YRo1QiEc9lD3mK+CPnTS4TK2RhCMmMmP4nCWwTkmQL2vx9jPJWYk+rbUZpwR1D583ZJk1FI3i9JZXIpi/qg==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
- '@inquirer/number@3.0.23':
- resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==}
- engines: {node: '>=18'}
+ '@inquirer/number@4.0.2':
+ resolution: {integrity: sha512-4McnjTSYrlthNW1ojkkmP75WLRYhQs7GXm6pDDoIrHqJuV5uUYwfdbB0geHdaKMarAqJQgoOVjzIT0jdWCsKew==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
- '@inquirer/password@4.0.23':
- resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==}
- engines: {node: '>=18'}
+ '@inquirer/password@5.0.2':
+ resolution: {integrity: sha512-oSDziMKiw4G2e4zS+0JRfxuPFFGh6N/9yUaluMgEHp2/Yyj2JGwfDO7XbwtOrxVrz+XsP/iaGyWXdQb9d8A0+g==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
- '@inquirer/prompts@7.10.1':
- resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==}
- engines: {node: '>=18'}
+ '@inquirer/prompts@8.0.2':
+ resolution: {integrity: sha512-2zK5zY48fZcl6+gG4eqOC/UzZsJckHCRvjXoLuW4D8LKOCVGdcJiSKkLnumSZjR/6PXPINDGOrGHqNxb+sxJDg==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
- '@inquirer/rawlist@4.1.11':
- resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==}
- engines: {node: '>=18'}
+ '@inquirer/rawlist@5.0.2':
+ resolution: {integrity: sha512-AcNALEdQKUQDeJcpC1a3YC53m1MLv+sMUS+vRZ8Qigs1Yg3Dcdtmi82rscJplogKOY8CXkKW4wvVwHS2ZjCIBQ==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
- '@inquirer/search@3.2.2':
- resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==}
- engines: {node: '>=18'}
+ '@inquirer/search@4.0.2':
+ resolution: {integrity: sha512-hg63w5toohdzE65S3LiGhdfIL0kT+yisbZARf7zw65PvyMUTutTN3eMAvD/B6y/25z88vTrB7kSB45Vz5CbrXg==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
- '@inquirer/select@4.4.2':
- resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==}
- engines: {node: '>=18'}
+ '@inquirer/select@5.0.2':
+ resolution: {integrity: sha512-JygTohvQxSNnvt7IKANVlg/eds+yN5sLRilYeGc4ri/9Aqi/2QPoXBMV5Cz/L1VtQv63SnTbPXJZeCK2pSwsOA==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
'@types/node':
optional: true
- '@inquirer/type@3.0.10':
- resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==}
- engines: {node: '>=18'}
+ '@inquirer/type@4.0.2':
+ resolution: {integrity: sha512-cae7mzluplsjSdgFA6ACLygb5jC8alO0UUnFPyu0E7tNRPrL+q/f8VcSXp+cjZQ7l5CMpDpi2G1+IQvkOiL1Lw==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
peerDependencies:
'@types/node': '>=18'
peerDependenciesMeta:
@@ -502,12 +502,12 @@ packages:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
- '@napi-rs/cli@3.4.1':
- resolution: {integrity: sha512-ayhm+NfrP5Hmh7vy5pfyYm/ktYtLh2PrgdLuqHTAubO7RoO2JkUE4F991AtgYxNewwXI8+guZLxU8itV7QnDrQ==}
+ '@napi-rs/cli@3.5.0':
+ resolution: {integrity: sha512-bJsDvAa9qK9VMkFhr780XWfQlK+GDlAX8qpK20buSmA0ld6nxCtiZ5a0J45zbd0FWT+VTZE1/u8VPH2vLfnVvw==}
engines: {node: '>= 16'}
hasBin: true
peerDependencies:
- '@emnapi/runtime': ^1.5.0
+ '@emnapi/runtime': ^1.7.1
peerDependenciesMeta:
'@emnapi/runtime':
optional: true
@@ -754,8 +754,8 @@ packages:
'@napi-rs/wasm-runtime@0.2.12':
resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==}
- '@napi-rs/wasm-runtime@1.0.7':
- resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==}
+ '@napi-rs/wasm-runtime@1.1.0':
+ resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==}
'@napi-rs/wasm-tools-android-arm-eabi@1.0.1':
resolution: {integrity: sha512-lr07E/l571Gft5v4aA1dI8koJEmF1F0UigBbsqg9OWNzg80H3lDPO+auv85y3T/NHE3GirDk7x/D3sLO57vayw==}
@@ -1041,20 +1041,20 @@ packages:
resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==}
engines: {node: '>=18'}
- '@textlint/ast-node-types@15.4.0':
- resolution: {integrity: sha512-IqY8i7IOGuvy05wZxISB7Me1ZyrvhaQGgx6DavfQjH3cfwpPFdDbDYmMXMuSv2xLS1kDB1kYKBV7fL2Vi16lRA==}
+ '@textlint/ast-node-types@15.4.1':
+ resolution: {integrity: sha512-XifMpBMdo0E1Fuh85YdcYAgy+okNg9WKBzIPIO4JUDnSWUVFihnogrM4cjDapeHkgzSgulwR8oJVJ17eyxI1bA==}
- '@textlint/linter-formatter@15.4.0':
- resolution: {integrity: sha512-rfqOZmnI1Wwc/Pa4LK+vagvVPmvxf9oRsBRqIOB04DwhucingZyAIJI/TyG18DIDYbP2aFXBZ3oOvyAxHe/8PQ==}
+ '@textlint/linter-formatter@15.4.1':
+ resolution: {integrity: sha512-kAV7Sup3vwvqxKvBbf9lx/JaPHkRybQp/LLvA73U1AorPZE6XyfBAFG24BbMiCs4OX1ax4g7kXRuFPgMLWRf+g==}
- '@textlint/module-interop@15.4.0':
- resolution: {integrity: sha512-uGf+SFIfzOLCbZI0gp+2NLsrkSArsvEWulPP6lJuKp7yRHadmy7Xf/YHORe46qhNyyxc8PiAfiixHJSaHGUrGg==}
+ '@textlint/module-interop@15.4.1':
+ resolution: {integrity: sha512-jHtM2E5CR68P3z/+FGrEU5pml2fQVzEo2sez9FEjrVHSPCrHtqHcPaKfsYbQJjc9C48ObwaWrCzRNaL3KedNCQ==}
- '@textlint/resolver@15.4.0':
- resolution: {integrity: sha512-Vh/QceKZQHFJFG4GxxIsKM1Xhwv93mbtKHmFE5/ybal1mIKHdqF03Z9Guaqt6Sx/AeNUshq0hkMOEhEyEWnehQ==}
+ '@textlint/resolver@15.4.1':
+ resolution: {integrity: sha512-uVssyG3XXXKNY+O7NOajGvQZTyOuhPviwlq7Xek6ZT9K1eDQtA8074cPkAQoLMYhi/TUyOE5P5kpz42UF8Lmdw==}
- '@textlint/types@15.4.0':
- resolution: {integrity: sha512-ZMwJgw/xjxJufOD+IB7I2Enl9Si4Hxo04B76RwUZ5cKBKzOPcmd6WvGe2F7jqdgmTdGnfMU+Bo/joQrjPNIWqg==}
+ '@textlint/types@15.4.1':
+ resolution: {integrity: sha512-WByVZ3zblbvuI+voWQplUP7seSTKXI9z6TMVXEB3dY3JFrZCIXWKNfLbETX5lZV7fYkCMaDtILO1l6s11wdbQA==}
'@tybys/wasm-util@0.10.1':
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
@@ -1083,63 +1083,63 @@ packages:
'@types/vscode@1.61.0':
resolution: {integrity: sha512-9k5Nwq45hkRwdfCFY+eKXeQQSbPoA114mF7U/4uJXRBJeGIO7MuJdhF1PnaDN+lllL9iKGQtd6FFXShBXMNaFg==}
- '@typescript-eslint/eslint-plugin@8.46.4':
- resolution: {integrity: sha512-R48VhmTJqplNyDxCyqqVkFSZIx1qX6PzwqgcXn1olLrzxcSBDlOsbtcnQuQhNtnNiJ4Xe5gREI1foajYaYU2Vg==}
+ '@typescript-eslint/eslint-plugin@8.48.1':
+ resolution: {integrity: sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
- '@typescript-eslint/parser': ^8.46.4
+ '@typescript-eslint/parser': ^8.48.1
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
- '@typescript-eslint/parser@8.46.4':
- resolution: {integrity: sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w==}
+ '@typescript-eslint/parser@8.48.1':
+ resolution: {integrity: sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
- '@typescript-eslint/project-service@8.46.4':
- resolution: {integrity: sha512-nPiRSKuvtTN+no/2N1kt2tUh/HoFzeEgOm9fQ6XQk4/ApGqjx0zFIIaLJ6wooR1HIoozvj2j6vTi/1fgAz7UYQ==}
+ '@typescript-eslint/project-service@8.48.1':
+ resolution: {integrity: sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
- '@typescript-eslint/scope-manager@8.46.4':
- resolution: {integrity: sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==}
+ '@typescript-eslint/scope-manager@8.48.1':
+ resolution: {integrity: sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@typescript-eslint/tsconfig-utils@8.46.4':
- resolution: {integrity: sha512-+/XqaZPIAk6Cjg7NWgSGe27X4zMGqrFqZ8atJsX3CWxH/jACqWnrWI68h7nHQld0y+k9eTTjb9r+KU4twLoo9A==}
+ '@typescript-eslint/tsconfig-utils@8.48.1':
+ resolution: {integrity: sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
- '@typescript-eslint/type-utils@8.46.4':
- resolution: {integrity: sha512-V4QC8h3fdT5Wro6vANk6eojqfbv5bpwHuMsBcJUJkqs2z5XnYhJzyz9Y02eUmF9u3PgXEUiOt4w4KHR3P+z0PQ==}
+ '@typescript-eslint/type-utils@8.48.1':
+ resolution: {integrity: sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
- '@typescript-eslint/types@8.46.4':
- resolution: {integrity: sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w==}
+ '@typescript-eslint/types@8.48.1':
+ resolution: {integrity: sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@typescript-eslint/typescript-estree@8.46.4':
- resolution: {integrity: sha512-7oV2qEOr1d4NWNmpXLR35LvCfOkTNymY9oyW+lUHkmCno7aOmIf/hMaydnJBUTBMRCOGZh8YjkFOc8dadEoNGA==}
+ '@typescript-eslint/typescript-estree@8.48.1':
+ resolution: {integrity: sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
- '@typescript-eslint/utils@8.46.4':
- resolution: {integrity: sha512-AbSv11fklGXV6T28dp2Me04Uw90R2iJ30g2bgLz529Koehrmkbs1r7paFqr1vPCZi7hHwYxYtxfyQMRC8QaVSg==}
+ '@typescript-eslint/utils@8.48.1':
+ resolution: {integrity: sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
- '@typescript-eslint/visitor-keys@8.46.4':
- resolution: {integrity: sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==}
+ '@typescript-eslint/visitor-keys@8.48.1':
+ resolution: {integrity: sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typespec/ts-http-runtime@0.3.2':
@@ -1194,8 +1194,8 @@ packages:
'@vscode/vsce-sign@2.0.9':
resolution: {integrity: sha512-8IvaRvtFyzUnGGl3f5+1Cnor3LqaUWvhaUjAYO8Y39OUYlOf3cRd+dowuQYLpZcP3uwSG+mURwjEBOSq4SOJ0g==}
- '@vscode/vsce@3.7.0':
- resolution: {integrity: sha512-LY9r2T4joszRjz4d92ZPl6LTBUPS4IWH9gG/3JUv+1QyBJrveZlcVISuiaq0EOpmcgFh0GgVgKD4rD/21Tu8sA==}
+ '@vscode/vsce@3.7.1':
+ resolution: {integrity: sha512-OTm2XdMt2YkpSn2Nx7z2EJtSuhRHsTPYsSK59hr3v8jRArK+2UEoju4Jumn1CmpgoBLGI6ReHLJ/czYltNUW3g==}
engines: {node: '>= 20'}
hasBin: true
@@ -1239,9 +1239,6 @@ packages:
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
engines: {node: '>=12'}
- argparse@1.0.10:
- resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
-
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@@ -1532,6 +1529,9 @@ packages:
node-addon-api:
optional: true
+ emoji-regex@10.6.0:
+ resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
+
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -1587,8 +1587,8 @@ packages:
es-toolkit@1.42.0:
resolution: {integrity: sha512-SLHIyY7VfDJBM8clz4+T2oquwTQxEzu263AyhVK4jREOAwJ+8eebaa4wM3nlvnAqhDrMm2EsA6hWHaQsMPQ1nA==}
- esbuild@0.27.0:
- resolution: {integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==}
+ esbuild@0.27.1:
+ resolution: {integrity: sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==}
engines: {node: '>=18'}
hasBin: true
@@ -1685,11 +1685,6 @@ packages:
resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- esprima@4.0.1:
- resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
- engines: {node: '>=4'}
- hasBin: true
-
esquery@1.6.0:
resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
engines: {node: '>=0.10'}
@@ -1735,6 +1730,15 @@ packages:
fd-slicer@1.1.0:
resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
file-entry-cache@8.0.0:
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
engines: {node: '>=16.0.0'}
@@ -1796,6 +1800,10 @@ packages:
resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==}
engines: {node: '>= 0.4'}
+ get-east-asian-width@1.4.0:
+ resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==}
+ engines: {node: '>=18'}
+
get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
@@ -1819,8 +1827,8 @@ packages:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
- glob@11.0.3:
- resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==}
+ glob@11.1.0:
+ resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==}
engines: {node: 20 || >=22}
hasBin: true
@@ -2080,10 +2088,6 @@ packages:
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
- js-yaml@3.14.2:
- resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==}
- hasBin: true
-
js-yaml@4.1.1:
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
hasBin: true
@@ -2183,8 +2187,8 @@ packages:
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
- lru-cache@11.2.2:
- resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==}
+ lru-cache@11.2.4:
+ resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==}
engines: {node: 20 || >=22}
lru-cache@6.0.0:
@@ -2258,9 +2262,9 @@ packages:
mute-stream@0.0.8:
resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
- mute-stream@2.0.0:
- resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==}
- engines: {node: ^18.17.0 || >=20.5.0}
+ mute-stream@3.0.0:
+ resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==}
+ engines: {node: ^20.17.0 || >=22.9.0}
napi-build-utils@2.0.0:
resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==}
@@ -2279,8 +2283,8 @@ packages:
resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==}
hasBin: true
- node-sarif-builder@3.3.0:
- resolution: {integrity: sha512-8taRy2nQs1xNs8iO2F0XbkZJEliiijpKgFVcyiwKjJ2+3X59LVI3wY84qRdJwRDpIo5GK8wvb1pxcJ+JVu3jrg==}
+ node-sarif-builder@3.3.1:
+ resolution: {integrity: sha512-8z5dAbhpxmk/WRQHXlv4V0h+9Y4Ugk+w08lyhV/7E/CQX9yDdBc3025/EG+RSMJU2aPFh/IQ7XDV7Ti5TLt/TA==}
engines: {node: '>=20'}
normalize-package-data@6.0.2:
@@ -2323,6 +2327,9 @@ packages:
resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
engines: {node: '>= 0.4'}
+ obug@2.1.1:
+ resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==}
+
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
@@ -2334,8 +2341,8 @@ packages:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
- ovsx@0.10.6:
- resolution: {integrity: sha512-MZ7pgQ+IS5kumAfZGnhEjmdOUwW0UlmlekMwuA5DeUJeft7jFu9fTIEhH71ypjdUSpdqchodoKgb5y/ilh7b5g==}
+ ovsx@0.10.7:
+ resolution: {integrity: sha512-UjBQlB5xSDD+biAylCZ8Q/k3An9K3y9FYa+hT/HTbJkzOQP+gaNHX20CaOo4lrYT1iJXdiePH9zS2uvCXdDNDA==}
engines: {node: '>= 20'}
hasBin: true
@@ -2436,8 +2443,8 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
- prettier@3.6.2:
- resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
+ prettier@3.7.4:
+ resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==}
engines: {node: '>=14'}
hasBin: true
@@ -2631,9 +2638,6 @@ packages:
spdx-license-ids@3.0.22:
resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==}
- sprintf-js@1.0.3:
- resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
-
stop-iteration-iterator@1.1.0:
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
engines: {node: '>= 0.4'}
@@ -2646,6 +2650,10 @@ packages:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
engines: {node: '>=12'}
+ string-width@7.2.0:
+ resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==}
+ engines: {node: '>=18'}
+
string.prototype.trim@1.2.10:
resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
engines: {node: '>= 0.4'}
@@ -2718,6 +2726,10 @@ packages:
resolution: {integrity: sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==}
engines: {node: '>=4'}
+ tinyglobby@0.2.15:
+ resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
+ engines: {node: '>=12.0.0'}
+
tmp@0.2.5:
resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==}
engines: {node: '>=14.14'}
@@ -2870,10 +2882,6 @@ packages:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'}
- wrap-ansi@6.2.0:
- resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
- engines: {node: '>=8'}
-
wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
@@ -2882,6 +2890,10 @@ packages:
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
engines: {node: '>=12'}
+ wrap-ansi@9.0.2:
+ resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==}
+ engines: {node: '>=18'}
+
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
@@ -2914,10 +2926,6 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
- yoctocolors-cjs@2.1.3:
- resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==}
- engines: {node: '>=18'}
-
snapshots:
'@azu/format-text@1.0.2': {}
@@ -2983,8 +2991,8 @@ snapshots:
'@azure/core-tracing': 1.3.1
'@azure/core-util': 1.13.1
'@azure/logger': 1.3.0
- '@azure/msal-browser': 4.26.1
- '@azure/msal-node': 3.8.2
+ '@azure/msal-browser': 4.26.2
+ '@azure/msal-node': 3.8.3
open: 10.2.0
tslib: 2.8.1
transitivePeerDependencies:
@@ -2997,15 +3005,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@azure/msal-browser@4.26.1':
+ '@azure/msal-browser@4.26.2':
dependencies:
- '@azure/msal-common': 15.13.1
+ '@azure/msal-common': 15.13.2
- '@azure/msal-common@15.13.1': {}
+ '@azure/msal-common@15.13.2': {}
- '@azure/msal-node@3.8.2':
+ '@azure/msal-node@3.8.3':
dependencies:
- '@azure/msal-common': 15.13.1
+ '@azure/msal-common': 15.13.2
jsonwebtoken: 9.0.2
uuid: 8.3.2
@@ -3030,82 +3038,82 @@ snapshots:
dependencies:
tslib: 2.8.1
- '@esbuild/aix-ppc64@0.27.0':
+ '@esbuild/aix-ppc64@0.27.1':
optional: true
- '@esbuild/android-arm64@0.27.0':
+ '@esbuild/android-arm64@0.27.1':
optional: true
- '@esbuild/android-arm@0.27.0':
+ '@esbuild/android-arm@0.27.1':
optional: true
- '@esbuild/android-x64@0.27.0':
+ '@esbuild/android-x64@0.27.1':
optional: true
- '@esbuild/darwin-arm64@0.27.0':
+ '@esbuild/darwin-arm64@0.27.1':
optional: true
- '@esbuild/darwin-x64@0.27.0':
+ '@esbuild/darwin-x64@0.27.1':
optional: true
- '@esbuild/freebsd-arm64@0.27.0':
+ '@esbuild/freebsd-arm64@0.27.1':
optional: true
- '@esbuild/freebsd-x64@0.27.0':
+ '@esbuild/freebsd-x64@0.27.1':
optional: true
- '@esbuild/linux-arm64@0.27.0':
+ '@esbuild/linux-arm64@0.27.1':
optional: true
- '@esbuild/linux-arm@0.27.0':
+ '@esbuild/linux-arm@0.27.1':
optional: true
- '@esbuild/linux-ia32@0.27.0':
+ '@esbuild/linux-ia32@0.27.1':
optional: true
- '@esbuild/linux-loong64@0.27.0':
+ '@esbuild/linux-loong64@0.27.1':
optional: true
- '@esbuild/linux-mips64el@0.27.0':
+ '@esbuild/linux-mips64el@0.27.1':
optional: true
- '@esbuild/linux-ppc64@0.27.0':
+ '@esbuild/linux-ppc64@0.27.1':
optional: true
- '@esbuild/linux-riscv64@0.27.0':
+ '@esbuild/linux-riscv64@0.27.1':
optional: true
- '@esbuild/linux-s390x@0.27.0':
+ '@esbuild/linux-s390x@0.27.1':
optional: true
- '@esbuild/linux-x64@0.27.0':
+ '@esbuild/linux-x64@0.27.1':
optional: true
- '@esbuild/netbsd-arm64@0.27.0':
+ '@esbuild/netbsd-arm64@0.27.1':
optional: true
- '@esbuild/netbsd-x64@0.27.0':
+ '@esbuild/netbsd-x64@0.27.1':
optional: true
- '@esbuild/openbsd-arm64@0.27.0':
+ '@esbuild/openbsd-arm64@0.27.1':
optional: true
- '@esbuild/openbsd-x64@0.27.0':
+ '@esbuild/openbsd-x64@0.27.1':
optional: true
- '@esbuild/openharmony-arm64@0.27.0':
+ '@esbuild/openharmony-arm64@0.27.1':
optional: true
- '@esbuild/sunos-x64@0.27.0':
+ '@esbuild/sunos-x64@0.27.1':
optional: true
- '@esbuild/win32-arm64@0.27.0':
+ '@esbuild/win32-arm64@0.27.1':
optional: true
- '@esbuild/win32-ia32@0.27.0':
+ '@esbuild/win32-ia32@0.27.1':
optional: true
- '@esbuild/win32-x64@0.27.0':
+ '@esbuild/win32-x64@0.27.1':
optional: true
'@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)':
@@ -3131,7 +3139,7 @@ snapshots:
dependencies:
'@types/json-schema': 7.0.15
- '@eslint/eslintrc@3.3.1':
+ '@eslint/eslintrc@3.3.3':
dependencies:
ajv: 6.12.6
debug: 4.4.3
@@ -3165,128 +3173,122 @@ snapshots:
'@humanwhocodes/retry@0.4.3': {}
- '@inquirer/ansi@1.0.2': {}
+ '@inquirer/ansi@2.0.2': {}
- '@inquirer/checkbox@4.3.2(@types/node@24.10.1)':
+ '@inquirer/checkbox@5.0.2(@types/node@24.10.1)':
dependencies:
- '@inquirer/ansi': 1.0.2
- '@inquirer/core': 10.3.2(@types/node@24.10.1)
- '@inquirer/figures': 1.0.15
- '@inquirer/type': 3.0.10(@types/node@24.10.1)
- yoctocolors-cjs: 2.1.3
+ '@inquirer/ansi': 2.0.2
+ '@inquirer/core': 11.0.2(@types/node@24.10.1)
+ '@inquirer/figures': 2.0.2
+ '@inquirer/type': 4.0.2(@types/node@24.10.1)
optionalDependencies:
'@types/node': 24.10.1
- '@inquirer/confirm@5.1.21(@types/node@24.10.1)':
+ '@inquirer/confirm@6.0.2(@types/node@24.10.1)':
dependencies:
- '@inquirer/core': 10.3.2(@types/node@24.10.1)
- '@inquirer/type': 3.0.10(@types/node@24.10.1)
+ '@inquirer/core': 11.0.2(@types/node@24.10.1)
+ '@inquirer/type': 4.0.2(@types/node@24.10.1)
optionalDependencies:
'@types/node': 24.10.1
- '@inquirer/core@10.3.2(@types/node@24.10.1)':
+ '@inquirer/core@11.0.2(@types/node@24.10.1)':
dependencies:
- '@inquirer/ansi': 1.0.2
- '@inquirer/figures': 1.0.15
- '@inquirer/type': 3.0.10(@types/node@24.10.1)
+ '@inquirer/ansi': 2.0.2
+ '@inquirer/figures': 2.0.2
+ '@inquirer/type': 4.0.2(@types/node@24.10.1)
cli-width: 4.1.0
- mute-stream: 2.0.0
+ mute-stream: 3.0.0
signal-exit: 4.1.0
- wrap-ansi: 6.2.0
- yoctocolors-cjs: 2.1.3
+ wrap-ansi: 9.0.2
optionalDependencies:
'@types/node': 24.10.1
- '@inquirer/editor@4.2.23(@types/node@24.10.1)':
+ '@inquirer/editor@5.0.2(@types/node@24.10.1)':
dependencies:
- '@inquirer/core': 10.3.2(@types/node@24.10.1)
- '@inquirer/external-editor': 1.0.3(@types/node@24.10.1)
- '@inquirer/type': 3.0.10(@types/node@24.10.1)
+ '@inquirer/core': 11.0.2(@types/node@24.10.1)
+ '@inquirer/external-editor': 2.0.2(@types/node@24.10.1)
+ '@inquirer/type': 4.0.2(@types/node@24.10.1)
optionalDependencies:
'@types/node': 24.10.1
- '@inquirer/expand@4.0.23(@types/node@24.10.1)':
+ '@inquirer/expand@5.0.2(@types/node@24.10.1)':
dependencies:
- '@inquirer/core': 10.3.2(@types/node@24.10.1)
- '@inquirer/type': 3.0.10(@types/node@24.10.1)
- yoctocolors-cjs: 2.1.3
+ '@inquirer/core': 11.0.2(@types/node@24.10.1)
+ '@inquirer/type': 4.0.2(@types/node@24.10.1)
optionalDependencies:
'@types/node': 24.10.1
- '@inquirer/external-editor@1.0.3(@types/node@24.10.1)':
+ '@inquirer/external-editor@2.0.2(@types/node@24.10.1)':
dependencies:
chardet: 2.1.1
iconv-lite: 0.7.0
optionalDependencies:
'@types/node': 24.10.1
- '@inquirer/figures@1.0.15': {}
+ '@inquirer/figures@2.0.2': {}
- '@inquirer/input@4.3.1(@types/node@24.10.1)':
+ '@inquirer/input@5.0.2(@types/node@24.10.1)':
dependencies:
- '@inquirer/core': 10.3.2(@types/node@24.10.1)
- '@inquirer/type': 3.0.10(@types/node@24.10.1)
+ '@inquirer/core': 11.0.2(@types/node@24.10.1)
+ '@inquirer/type': 4.0.2(@types/node@24.10.1)
optionalDependencies:
'@types/node': 24.10.1
- '@inquirer/number@3.0.23(@types/node@24.10.1)':
+ '@inquirer/number@4.0.2(@types/node@24.10.1)':
dependencies:
- '@inquirer/core': 10.3.2(@types/node@24.10.1)
- '@inquirer/type': 3.0.10(@types/node@24.10.1)
+ '@inquirer/core': 11.0.2(@types/node@24.10.1)
+ '@inquirer/type': 4.0.2(@types/node@24.10.1)
optionalDependencies:
'@types/node': 24.10.1
- '@inquirer/password@4.0.23(@types/node@24.10.1)':
+ '@inquirer/password@5.0.2(@types/node@24.10.1)':
dependencies:
- '@inquirer/ansi': 1.0.2
- '@inquirer/core': 10.3.2(@types/node@24.10.1)
- '@inquirer/type': 3.0.10(@types/node@24.10.1)
+ '@inquirer/ansi': 2.0.2
+ '@inquirer/core': 11.0.2(@types/node@24.10.1)
+ '@inquirer/type': 4.0.2(@types/node@24.10.1)
optionalDependencies:
'@types/node': 24.10.1
- '@inquirer/prompts@7.10.1(@types/node@24.10.1)':
- dependencies:
- '@inquirer/checkbox': 4.3.2(@types/node@24.10.1)
- '@inquirer/confirm': 5.1.21(@types/node@24.10.1)
- '@inquirer/editor': 4.2.23(@types/node@24.10.1)
- '@inquirer/expand': 4.0.23(@types/node@24.10.1)
- '@inquirer/input': 4.3.1(@types/node@24.10.1)
- '@inquirer/number': 3.0.23(@types/node@24.10.1)
- '@inquirer/password': 4.0.23(@types/node@24.10.1)
- '@inquirer/rawlist': 4.1.11(@types/node@24.10.1)
- '@inquirer/search': 3.2.2(@types/node@24.10.1)
- '@inquirer/select': 4.4.2(@types/node@24.10.1)
+ '@inquirer/prompts@8.0.2(@types/node@24.10.1)':
+ dependencies:
+ '@inquirer/checkbox': 5.0.2(@types/node@24.10.1)
+ '@inquirer/confirm': 6.0.2(@types/node@24.10.1)
+ '@inquirer/editor': 5.0.2(@types/node@24.10.1)
+ '@inquirer/expand': 5.0.2(@types/node@24.10.1)
+ '@inquirer/input': 5.0.2(@types/node@24.10.1)
+ '@inquirer/number': 4.0.2(@types/node@24.10.1)
+ '@inquirer/password': 5.0.2(@types/node@24.10.1)
+ '@inquirer/rawlist': 5.0.2(@types/node@24.10.1)
+ '@inquirer/search': 4.0.2(@types/node@24.10.1)
+ '@inquirer/select': 5.0.2(@types/node@24.10.1)
optionalDependencies:
'@types/node': 24.10.1
- '@inquirer/rawlist@4.1.11(@types/node@24.10.1)':
+ '@inquirer/rawlist@5.0.2(@types/node@24.10.1)':
dependencies:
- '@inquirer/core': 10.3.2(@types/node@24.10.1)
- '@inquirer/type': 3.0.10(@types/node@24.10.1)
- yoctocolors-cjs: 2.1.3
+ '@inquirer/core': 11.0.2(@types/node@24.10.1)
+ '@inquirer/type': 4.0.2(@types/node@24.10.1)
optionalDependencies:
'@types/node': 24.10.1
- '@inquirer/search@3.2.2(@types/node@24.10.1)':
+ '@inquirer/search@4.0.2(@types/node@24.10.1)':
dependencies:
- '@inquirer/core': 10.3.2(@types/node@24.10.1)
- '@inquirer/figures': 1.0.15
- '@inquirer/type': 3.0.10(@types/node@24.10.1)
- yoctocolors-cjs: 2.1.3
+ '@inquirer/core': 11.0.2(@types/node@24.10.1)
+ '@inquirer/figures': 2.0.2
+ '@inquirer/type': 4.0.2(@types/node@24.10.1)
optionalDependencies:
'@types/node': 24.10.1
- '@inquirer/select@4.4.2(@types/node@24.10.1)':
+ '@inquirer/select@5.0.2(@types/node@24.10.1)':
dependencies:
- '@inquirer/ansi': 1.0.2
- '@inquirer/core': 10.3.2(@types/node@24.10.1)
- '@inquirer/figures': 1.0.15
- '@inquirer/type': 3.0.10(@types/node@24.10.1)
- yoctocolors-cjs: 2.1.3
+ '@inquirer/ansi': 2.0.2
+ '@inquirer/core': 11.0.2(@types/node@24.10.1)
+ '@inquirer/figures': 2.0.2
+ '@inquirer/type': 4.0.2(@types/node@24.10.1)
optionalDependencies:
'@types/node': 24.10.1
- '@inquirer/type@3.0.10(@types/node@24.10.1)':
+ '@inquirer/type@4.0.2(@types/node@24.10.1)':
optionalDependencies:
'@types/node': 24.10.1
@@ -3305,18 +3307,18 @@ snapshots:
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
- '@napi-rs/cli@3.4.1(@emnapi/runtime@1.7.1)(@types/node@24.10.1)':
+ '@napi-rs/cli@3.5.0(@emnapi/runtime@1.7.1)(@types/node@24.10.1)':
dependencies:
- '@inquirer/prompts': 7.10.1(@types/node@24.10.1)
+ '@inquirer/prompts': 8.0.2(@types/node@24.10.1)
'@napi-rs/cross-toolchain': 1.0.3
'@napi-rs/wasm-tools': 1.0.1
'@octokit/rest': 22.0.1
clipanion: 4.0.0-rc.4(typanion@3.14.0)
colorette: 2.0.20
- debug: 4.4.3
emnapi: 1.7.1
es-toolkit: 1.42.0
js-yaml: 4.1.1
+ obug: 2.1.1
semver: 7.7.3
typanion: 3.14.0
optionalDependencies:
@@ -3385,7 +3387,7 @@ snapshots:
'@napi-rs/lzma-wasm32-wasi@1.4.5':
dependencies:
- '@napi-rs/wasm-runtime': 1.0.7
+ '@napi-rs/wasm-runtime': 1.1.0
optional: true
'@napi-rs/lzma-win32-arm64-msvc@1.4.5':
@@ -3455,7 +3457,7 @@ snapshots:
'@napi-rs/tar-wasm32-wasi@1.1.0':
dependencies:
- '@napi-rs/wasm-runtime': 1.0.7
+ '@napi-rs/wasm-runtime': 1.1.0
optional: true
'@napi-rs/tar-win32-arm64-msvc@1.1.0':
@@ -3493,7 +3495,7 @@ snapshots:
'@tybys/wasm-util': 0.10.1
optional: true
- '@napi-rs/wasm-runtime@1.0.7':
+ '@napi-rs/wasm-runtime@1.1.0':
dependencies:
'@emnapi/core': 1.7.1
'@emnapi/runtime': 1.7.1
@@ -3529,7 +3531,7 @@ snapshots:
'@napi-rs/wasm-tools-wasm32-wasi@1.0.1':
dependencies:
- '@napi-rs/wasm-runtime': 1.0.7
+ '@napi-rs/wasm-runtime': 1.1.0
optional: true
'@napi-rs/wasm-tools-win32-arm64-msvc@1.0.1':
@@ -3722,9 +3724,9 @@ snapshots:
dependencies:
'@secretlint/resolver': 10.2.2
'@secretlint/types': 10.2.2
- '@textlint/linter-formatter': 15.4.0
- '@textlint/module-interop': 15.4.0
- '@textlint/types': 15.4.0
+ '@textlint/linter-formatter': 15.4.1
+ '@textlint/module-interop': 15.4.1
+ '@textlint/types': 15.4.1
chalk: 5.6.2
debug: 4.4.3
pluralize: 8.0.0
@@ -3753,7 +3755,7 @@ snapshots:
'@secretlint/secretlint-formatter-sarif@10.2.2':
dependencies:
- node-sarif-builder: 3.3.0
+ node-sarif-builder: 3.3.1
'@secretlint/secretlint-rule-no-dotenv@10.2.2':
dependencies:
@@ -3770,18 +3772,18 @@ snapshots:
'@sindresorhus/merge-streams@2.3.0': {}
- '@textlint/ast-node-types@15.4.0': {}
+ '@textlint/ast-node-types@15.4.1': {}
- '@textlint/linter-formatter@15.4.0':
+ '@textlint/linter-formatter@15.4.1':
dependencies:
'@azu/format-text': 1.0.2
'@azu/style-format': 1.0.1
- '@textlint/module-interop': 15.4.0
- '@textlint/resolver': 15.4.0
- '@textlint/types': 15.4.0
+ '@textlint/module-interop': 15.4.1
+ '@textlint/resolver': 15.4.1
+ '@textlint/types': 15.4.1
chalk: 4.1.2
debug: 4.4.3
- js-yaml: 3.14.2
+ js-yaml: 4.1.1
lodash: 4.17.21
pluralize: 2.0.0
string-width: 4.2.3
@@ -3791,13 +3793,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@textlint/module-interop@15.4.0': {}
+ '@textlint/module-interop@15.4.1': {}
- '@textlint/resolver@15.4.0': {}
+ '@textlint/resolver@15.4.1': {}
- '@textlint/types@15.4.0':
+ '@textlint/types@15.4.1':
dependencies:
- '@textlint/ast-node-types': 15.4.0
+ '@textlint/ast-node-types': 15.4.1
'@tybys/wasm-util@0.10.1':
dependencies:
@@ -3821,14 +3823,14 @@ snapshots:
'@types/vscode@1.61.0': {}
- '@typescript-eslint/eslint-plugin@8.46.4(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)':
+ '@typescript-eslint/eslint-plugin@8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
- '@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
- '@typescript-eslint/scope-manager': 8.46.4
- '@typescript-eslint/type-utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
- '@typescript-eslint/utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
- '@typescript-eslint/visitor-keys': 8.46.4
+ '@typescript-eslint/parser': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/scope-manager': 8.48.1
+ '@typescript-eslint/type-utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/visitor-keys': 8.48.1
eslint: 9.39.1
graphemer: 1.4.0
ignore: 7.0.5
@@ -3838,41 +3840,41 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3)':
+ '@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
- '@typescript-eslint/scope-manager': 8.46.4
- '@typescript-eslint/types': 8.46.4
- '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
- '@typescript-eslint/visitor-keys': 8.46.4
+ '@typescript-eslint/scope-manager': 8.48.1
+ '@typescript-eslint/types': 8.48.1
+ '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3)
+ '@typescript-eslint/visitor-keys': 8.48.1
debug: 4.4.3
eslint: 9.39.1
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/project-service@8.46.4(typescript@5.9.3)':
+ '@typescript-eslint/project-service@8.48.1(typescript@5.9.3)':
dependencies:
- '@typescript-eslint/tsconfig-utils': 8.46.4(typescript@5.9.3)
- '@typescript-eslint/types': 8.46.4
+ '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3)
+ '@typescript-eslint/types': 8.48.1
debug: 4.4.3
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/scope-manager@8.46.4':
+ '@typescript-eslint/scope-manager@8.48.1':
dependencies:
- '@typescript-eslint/types': 8.46.4
- '@typescript-eslint/visitor-keys': 8.46.4
+ '@typescript-eslint/types': 8.48.1
+ '@typescript-eslint/visitor-keys': 8.48.1
- '@typescript-eslint/tsconfig-utils@8.46.4(typescript@5.9.3)':
+ '@typescript-eslint/tsconfig-utils@8.48.1(typescript@5.9.3)':
dependencies:
typescript: 5.9.3
- '@typescript-eslint/type-utils@8.46.4(eslint@9.39.1)(typescript@5.9.3)':
+ '@typescript-eslint/type-utils@8.48.1(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
- '@typescript-eslint/types': 8.46.4
- '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
- '@typescript-eslint/utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/types': 8.48.1
+ '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
debug: 4.4.3
eslint: 9.39.1
ts-api-utils: 2.1.0(typescript@5.9.3)
@@ -3880,38 +3882,37 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/types@8.46.4': {}
+ '@typescript-eslint/types@8.48.1': {}
- '@typescript-eslint/typescript-estree@8.46.4(typescript@5.9.3)':
+ '@typescript-eslint/typescript-estree@8.48.1(typescript@5.9.3)':
dependencies:
- '@typescript-eslint/project-service': 8.46.4(typescript@5.9.3)
- '@typescript-eslint/tsconfig-utils': 8.46.4(typescript@5.9.3)
- '@typescript-eslint/types': 8.46.4
- '@typescript-eslint/visitor-keys': 8.46.4
+ '@typescript-eslint/project-service': 8.48.1(typescript@5.9.3)
+ '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3)
+ '@typescript-eslint/types': 8.48.1
+ '@typescript-eslint/visitor-keys': 8.48.1
debug: 4.4.3
- fast-glob: 3.3.3
- is-glob: 4.0.3
minimatch: 9.0.5
semver: 7.7.3
+ tinyglobby: 0.2.15
ts-api-utils: 2.1.0(typescript@5.9.3)
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/utils@8.46.4(eslint@9.39.1)(typescript@5.9.3)':
+ '@typescript-eslint/utils@8.48.1(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1)
- '@typescript-eslint/scope-manager': 8.46.4
- '@typescript-eslint/types': 8.46.4
- '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
+ '@typescript-eslint/scope-manager': 8.48.1
+ '@typescript-eslint/types': 8.48.1
+ '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3)
eslint: 9.39.1
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/visitor-keys@8.46.4':
+ '@typescript-eslint/visitor-keys@8.48.1':
dependencies:
- '@typescript-eslint/types': 8.46.4
+ '@typescript-eslint/types': 8.48.1
eslint-visitor-keys: 4.2.1
'@typespec/ts-http-runtime@0.3.2':
@@ -3961,7 +3962,7 @@ snapshots:
'@vscode/vsce-sign-win32-arm64': 2.0.6
'@vscode/vsce-sign-win32-x64': 2.0.6
- '@vscode/vsce@3.7.0':
+ '@vscode/vsce@3.7.1':
dependencies:
'@azure/identity': 4.13.0
'@secretlint/node': 10.2.2
@@ -3975,7 +3976,7 @@ snapshots:
cockatiel: 3.2.1
commander: 12.1.0
form-data: 4.0.5
- glob: 11.0.3
+ glob: 11.1.0
hosted-git-info: 4.1.0
jsonc-parser: 3.3.1
leven: 3.1.0
@@ -4033,10 +4034,6 @@ snapshots:
ansi-styles@6.2.3: {}
- argparse@1.0.10:
- dependencies:
- sprintf-js: 1.0.3
-
argparse@2.0.1: {}
array-buffer-byte-length@1.0.2:
@@ -4358,6 +4355,8 @@ snapshots:
emnapi@1.7.1: {}
+ emoji-regex@10.6.0: {}
+
emoji-regex@8.0.0: {}
emoji-regex@9.2.2: {}
@@ -4462,34 +4461,34 @@ snapshots:
es-toolkit@1.42.0: {}
- esbuild@0.27.0:
+ esbuild@0.27.1:
optionalDependencies:
- '@esbuild/aix-ppc64': 0.27.0
- '@esbuild/android-arm': 0.27.0
- '@esbuild/android-arm64': 0.27.0
- '@esbuild/android-x64': 0.27.0
- '@esbuild/darwin-arm64': 0.27.0
- '@esbuild/darwin-x64': 0.27.0
- '@esbuild/freebsd-arm64': 0.27.0
- '@esbuild/freebsd-x64': 0.27.0
- '@esbuild/linux-arm': 0.27.0
- '@esbuild/linux-arm64': 0.27.0
- '@esbuild/linux-ia32': 0.27.0
- '@esbuild/linux-loong64': 0.27.0
- '@esbuild/linux-mips64el': 0.27.0
- '@esbuild/linux-ppc64': 0.27.0
- '@esbuild/linux-riscv64': 0.27.0
- '@esbuild/linux-s390x': 0.27.0
- '@esbuild/linux-x64': 0.27.0
- '@esbuild/netbsd-arm64': 0.27.0
- '@esbuild/netbsd-x64': 0.27.0
- '@esbuild/openbsd-arm64': 0.27.0
- '@esbuild/openbsd-x64': 0.27.0
- '@esbuild/openharmony-arm64': 0.27.0
- '@esbuild/sunos-x64': 0.27.0
- '@esbuild/win32-arm64': 0.27.0
- '@esbuild/win32-ia32': 0.27.0
- '@esbuild/win32-x64': 0.27.0
+ '@esbuild/aix-ppc64': 0.27.1
+ '@esbuild/android-arm': 0.27.1
+ '@esbuild/android-arm64': 0.27.1
+ '@esbuild/android-x64': 0.27.1
+ '@esbuild/darwin-arm64': 0.27.1
+ '@esbuild/darwin-x64': 0.27.1
+ '@esbuild/freebsd-arm64': 0.27.1
+ '@esbuild/freebsd-x64': 0.27.1
+ '@esbuild/linux-arm': 0.27.1
+ '@esbuild/linux-arm64': 0.27.1
+ '@esbuild/linux-ia32': 0.27.1
+ '@esbuild/linux-loong64': 0.27.1
+ '@esbuild/linux-mips64el': 0.27.1
+ '@esbuild/linux-ppc64': 0.27.1
+ '@esbuild/linux-riscv64': 0.27.1
+ '@esbuild/linux-s390x': 0.27.1
+ '@esbuild/linux-x64': 0.27.1
+ '@esbuild/netbsd-arm64': 0.27.1
+ '@esbuild/netbsd-x64': 0.27.1
+ '@esbuild/openbsd-arm64': 0.27.1
+ '@esbuild/openbsd-x64': 0.27.1
+ '@esbuild/openharmony-arm64': 0.27.1
+ '@esbuild/sunos-x64': 0.27.1
+ '@esbuild/win32-arm64': 0.27.1
+ '@esbuild/win32-ia32': 0.27.1
+ '@esbuild/win32-x64': 0.27.1
escape-html@1.0.3: {}
@@ -4507,11 +4506,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-module-utils@2.12.1(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1):
+ eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1):
dependencies:
debug: 3.2.7
optionalDependencies:
- '@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/parser': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
eslint: 9.39.1
eslint-import-resolver-node: 0.3.9
transitivePeerDependencies:
@@ -4523,7 +4522,7 @@ snapshots:
eslint-utils: 2.1.0
regexpp: 3.2.0
- eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1):
+ eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.9
@@ -4534,7 +4533,7 @@ snapshots:
doctrine: 2.1.0
eslint: 9.39.1
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.46.4(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1)
+ eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1)
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -4546,7 +4545,7 @@ snapshots:
string.prototype.trimend: 1.0.9
tsconfig-paths: 3.15.0
optionalDependencies:
- '@typescript-eslint/parser': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/parser': 8.48.1(eslint@9.39.1)(typescript@5.9.3)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
@@ -4584,7 +4583,7 @@ snapshots:
'@eslint/config-array': 0.21.1
'@eslint/config-helpers': 0.4.2
'@eslint/core': 0.17.0
- '@eslint/eslintrc': 3.3.1
+ '@eslint/eslintrc': 3.3.3
'@eslint/js': 9.39.1
'@eslint/plugin-kit': 0.4.1
'@humanfs/node': 0.16.7
@@ -4622,8 +4621,6 @@ snapshots:
acorn-jsx: 5.3.2(acorn@8.15.0)
eslint-visitor-keys: 4.2.1
- esprima@4.0.1: {}
-
esquery@1.6.0:
dependencies:
estraverse: 5.3.0
@@ -4665,6 +4662,10 @@ snapshots:
dependencies:
pend: 1.2.0
+ fdir@6.5.0(picomatch@4.0.3):
+ optionalDependencies:
+ picomatch: 4.0.3
+
file-entry-cache@8.0.0:
dependencies:
flat-cache: 4.0.1
@@ -4728,6 +4729,8 @@ snapshots:
generator-function@2.0.1: {}
+ get-east-asian-width@1.4.0: {}
+
get-intrinsic@1.3.0:
dependencies:
call-bind-apply-helpers: 1.0.2
@@ -4763,7 +4766,7 @@ snapshots:
dependencies:
is-glob: 4.0.3
- glob@11.0.3:
+ glob@11.1.0:
dependencies:
foreground-child: 3.3.1
jackspeak: 4.1.1
@@ -5027,11 +5030,6 @@ snapshots:
js-tokens@4.0.0: {}
- js-yaml@3.14.2:
- dependencies:
- argparse: 1.0.10
- esprima: 4.0.1
-
js-yaml@4.1.1:
dependencies:
argparse: 2.0.1
@@ -5131,7 +5129,7 @@ snapshots:
lru-cache@10.4.3: {}
- lru-cache@11.2.2: {}
+ lru-cache@11.2.4: {}
lru-cache@6.0.0:
dependencies:
@@ -5193,7 +5191,7 @@ snapshots:
mute-stream@0.0.8: {}
- mute-stream@2.0.0: {}
+ mute-stream@3.0.0: {}
napi-build-utils@2.0.0:
optional: true
@@ -5211,7 +5209,7 @@ snapshots:
node-gyp-build@4.8.4:
optional: true
- node-sarif-builder@3.3.0:
+ node-sarif-builder@3.3.1:
dependencies:
'@types/sarif': 2.1.7
fs-extra: 11.3.2
@@ -5272,6 +5270,8 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.1.1
+ obug@2.1.1: {}
+
once@1.4.0:
dependencies:
wrappy: 1.0.2
@@ -5293,9 +5293,9 @@ snapshots:
type-check: 0.4.0
word-wrap: 1.2.5
- ovsx@0.10.6:
+ ovsx@0.10.7:
dependencies:
- '@vscode/vsce': 3.7.0
+ '@vscode/vsce': 3.7.1
commander: 6.2.1
follow-redirects: 1.15.11
is-ci: 2.0.0
@@ -5360,7 +5360,7 @@ snapshots:
path-scurry@2.0.1:
dependencies:
- lru-cache: 11.2.2
+ lru-cache: 11.2.4
minipass: 7.1.2
path-type@6.0.0: {}
@@ -5399,7 +5399,7 @@ snapshots:
prelude-ls@1.2.1: {}
- prettier@3.6.2: {}
+ prettier@3.7.4: {}
pump@3.0.3:
dependencies:
@@ -5635,8 +5635,6 @@ snapshots:
spdx-license-ids@3.0.22: {}
- sprintf-js@1.0.3: {}
-
stop-iteration-iterator@1.1.0:
dependencies:
es-errors: 1.3.0
@@ -5654,6 +5652,12 @@ snapshots:
emoji-regex: 9.2.2
strip-ansi: 7.1.2
+ string-width@7.2.0:
+ dependencies:
+ emoji-regex: 10.6.0
+ get-east-asian-width: 1.4.0
+ strip-ansi: 7.1.2
+
string.prototype.trim@1.2.10:
dependencies:
call-bind: 1.0.8
@@ -5748,6 +5752,11 @@ snapshots:
dependencies:
editions: 6.22.0
+ tinyglobby@0.2.15:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+
tmp@0.2.5: {}
to-regex-range@5.0.1:
@@ -5921,12 +5930,6 @@ snapshots:
word-wrap@1.2.5: {}
- wrap-ansi@6.2.0:
- dependencies:
- ansi-styles: 4.3.0
- string-width: 4.2.3
- strip-ansi: 6.0.1
-
wrap-ansi@7.0.0:
dependencies:
ansi-styles: 4.3.0
@@ -5939,6 +5942,12 @@ snapshots:
string-width: 5.1.2
strip-ansi: 7.1.2
+ wrap-ansi@9.0.2:
+ dependencies:
+ ansi-styles: 6.2.3
+ string-width: 7.2.0
+ strip-ansi: 7.1.2
+
wrappy@1.0.2:
optional: true
@@ -5971,5 +5980,3 @@ snapshots:
buffer-crc32: 0.2.13
yocto-queue@0.1.0: {}
-
- yoctocolors-cjs@2.1.3: {}
diff --git a/server/Cargo.lock b/server/Cargo.lock
index 78c10c6c..5cfd343b 100644
--- a/server/Cargo.lock
+++ b/server/Cargo.lock
@@ -21,9 +21,9 @@ dependencies = [
[[package]]
name = "actix-files"
-version = "0.6.8"
+version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c0d87f10d70e2948ad40e8edea79c8e77c6c66e0250a4c1f09b690465199576"
+checksum = "4009a8beb4dc78a58286ac9d58969ee0a8acecb7912d5ce898b4da4335579341"
dependencies = [
"actix-http",
"actix-service",
@@ -88,7 +88,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
dependencies = [
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -156,9 +156,9 @@ dependencies = [
[[package]]
name = "actix-web"
-version = "4.12.0"
+version = "4.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2233f53f6cb18ae038ce1f0713ca0c72ca0c4b71fe9aaeb59924ce2c89c6dd85"
+checksum = "1654a77ba142e37f049637a3e5685f864514af11fcbc51cb51eb6596afe5b8d6"
dependencies = [
"actix-codec",
"actix-http",
@@ -206,7 +206,7 @@ dependencies = [
"actix-router",
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -467,7 +467,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -651,9 +651,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.2.46"
+version = "1.2.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36"
+checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a"
dependencies = [
"find-msvc-tools",
"jobserver",
@@ -706,9 +706,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.51"
+version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
+checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
dependencies = [
"clap_builder",
"clap_derive",
@@ -716,9 +716,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.51"
+version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
+checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
dependencies = [
"anstream",
"anstyle",
@@ -735,7 +735,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -756,6 +756,7 @@ dependencies = [
"actix-web",
"actix-web-httpauth",
"actix-ws",
+ "anyhow",
"assert_cmd",
"assert_fs",
"assertables",
@@ -847,6 +848,15 @@ dependencies = [
"unicode-xid",
]
+[[package]]
+name = "convert_case"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
+dependencies = [
+ "unicode-segmentation",
+]
+
[[package]]
name = "cookie"
version = "0.16.2"
@@ -897,9 +907,9 @@ dependencies = [
[[package]]
name = "crc"
-version = "3.3.0"
+version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675"
+checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d"
dependencies = [
"crc-catalog",
]
@@ -1022,27 +1032,29 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
name = "derive_more"
-version = "2.0.1"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
+checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618"
dependencies = [
"derive_more-impl",
]
[[package]]
name = "derive_more-impl"
-version = "2.0.1"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
+checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b"
dependencies = [
+ "convert_case",
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "rustc_version",
+ "syn 2.0.111",
"unicode-xid",
]
@@ -1104,7 +1116,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -1122,7 +1134,7 @@ dependencies = [
"anyhow",
"bumpalo",
"hashbrown 0.15.5",
- "indexmap 2.12.0",
+ "indexmap 2.12.1",
"rustc-hash",
"serde",
"unicode-width 0.2.2",
@@ -1400,7 +1412,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -1512,7 +1524,7 @@ dependencies = [
"futures-sink",
"futures-util",
"http 0.2.12",
- "indexmap 2.12.0",
+ "indexmap 2.12.1",
"slab",
"tokio",
"tokio-util",
@@ -1538,9 +1550,9 @@ dependencies = [
[[package]]
name = "hashbrown"
-version = "0.16.0"
+version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]]
name = "heck"
@@ -1565,8 +1577,9 @@ dependencies = [
[[package]]
name = "htmd"
-version = "0.3.2"
-source = "git+https://github.com/bjones1/htmd.git?branch=fix-faithful-serialization#e13d5a5ed195163c60b0c59974fc5bb521bdd70b"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60ae59466542f2346e43d4a5e9b4432a1fc915b279c9fc0484e9ed7379121454"
dependencies = [
"html5ever",
"markup5ever_rcdom",
@@ -1597,12 +1610,11 @@ dependencies = [
[[package]]
name = "http"
-version = "1.3.1"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
+checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
dependencies = [
"bytes",
- "fnv",
"itoa",
]
@@ -1613,7 +1625,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
- "http 1.3.1",
+ "http 1.4.0",
]
[[package]]
@@ -1624,7 +1636,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
dependencies = [
"bytes",
"futures-core",
- "http 1.3.1",
+ "http 1.4.0",
"http-body",
"pin-project-lite",
]
@@ -1663,7 +1675,7 @@ dependencies = [
"bytes",
"futures-channel",
"futures-core",
- "http 1.3.1",
+ "http 1.4.0",
"http-body",
"httparse",
"itoa",
@@ -1680,7 +1692,7 @@ version = "0.27.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
dependencies = [
- "http 1.3.1",
+ "http 1.4.0",
"hyper",
"hyper-util",
"rustls",
@@ -1693,16 +1705,16 @@ dependencies = [
[[package]]
name = "hyper-util"
-version = "0.1.18"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56"
+checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
dependencies = [
"base64",
"bytes",
"futures-channel",
"futures-core",
"futures-util",
- "http 1.3.1",
+ "http 1.4.0",
"http-body",
"hyper",
"ipnet",
@@ -1885,12 +1897,12 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.12.0"
+version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
+checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
dependencies = [
"equivalent",
- "hashbrown 0.16.0",
+ "hashbrown 0.16.1",
"serde",
"serde_core",
]
@@ -2000,7 +2012,7 @@ checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -2037,9 +2049,9 @@ dependencies = [
[[package]]
name = "js-sys"
-version = "0.3.82"
+version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
+checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
dependencies = [
"once_cell",
"wasm-bindgen",
@@ -2085,9 +2097,9 @@ checksum = "2c4a545a15244c7d945065b5d392b2d2d7f21526fba56ce51467b06ed445e8f7"
[[package]]
name = "libc"
-version = "0.2.177"
+version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
+checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]]
name = "libredox"
@@ -2102,9 +2114,9 @@ dependencies = [
[[package]]
name = "libz-rs-sys"
-version = "0.5.2"
+version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "840db8cf39d9ec4dd794376f38acc40d0fc65eec2a8f484f7fd375b84602becd"
+checksum = "8b484ba8d4f775eeca644c452a56650e544bf7e617f1d170fe7298122ead5222"
dependencies = [
"zlib-rs",
]
@@ -2149,11 +2161,11 @@ dependencies = [
[[package]]
name = "log"
-version = "0.4.28"
+version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
dependencies = [
- "serde",
+ "serde_core",
]
[[package]]
@@ -2254,7 +2266,7 @@ checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -2517,9 +2529,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "pest"
-version = "2.8.3"
+version = "2.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4"
+checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22"
dependencies = [
"memchr",
"ucd-trie",
@@ -2527,9 +2539,9 @@ dependencies = [
[[package]]
name = "pest_derive"
-version = "2.8.3"
+version = "2.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de"
+checksum = "51f72981ade67b1ca6adc26ec221be9f463f2b5839c7508998daa17c23d94d7f"
dependencies = [
"pest",
"pest_generator",
@@ -2537,22 +2549,22 @@ dependencies = [
[[package]]
name = "pest_generator"
-version = "2.8.3"
+version = "2.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843"
+checksum = "dee9efd8cdb50d719a80088b76f81aec7c41ed6d522ee750178f83883d271625"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
name = "pest_meta"
-version = "2.8.3"
+version = "2.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a"
+checksum = "bf1d70880e76bdc13ba52eafa6239ce793d85c8e43896507e43dd8984ff05b82"
dependencies = [
"pest",
"sha2",
@@ -2618,7 +2630,7 @@ dependencies = [
"phf_shared 0.13.1",
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -3005,7 +3017,7 @@ dependencies = [
"futures-channel",
"futures-core",
"futures-util",
- "http 1.3.1",
+ "http 1.4.0",
"http-body",
"http-body-util",
"hyper",
@@ -3060,6 +3072,15 @@ version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
[[package]]
name = "rustix"
version = "1.1.2"
@@ -3089,9 +3110,9 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
-version = "1.13.0"
+version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a"
+checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c"
dependencies = [
"web-time",
"zeroize",
@@ -3152,7 +3173,7 @@ checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -3189,6 +3210,12 @@ dependencies = [
"zip",
]
+[[package]]
+name = "semver"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
+
[[package]]
name = "serde"
version = "1.0.228"
@@ -3238,7 +3265,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -3247,7 +3274,7 @@ version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
dependencies = [
- "indexmap 2.12.0",
+ "indexmap 2.12.1",
"itoa",
"memchr",
"ryu",
@@ -3263,7 +3290,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -3293,7 +3320,7 @@ version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
- "indexmap 2.12.0",
+ "indexmap 2.12.1",
"itoa",
"ryu",
"serde",
@@ -3347,9 +3374,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook-registry"
-version = "1.4.6"
+version = "1.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
+checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad"
dependencies = [
"libc",
]
@@ -3499,9 +3526,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.110"
+version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
+checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [
"proc-macro2",
"quote",
@@ -3525,7 +3552,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -3590,8 +3617,8 @@ dependencies = [
"cfg-if",
"const_format",
"futures-util",
- "http 1.3.1",
- "indexmap 2.12.0",
+ "http 1.4.0",
+ "indexmap 2.12.1",
"libc",
"pastey",
"reqwest",
@@ -3614,7 +3641,7 @@ source = "git+https://github.com/bjones1/thirtyfour.git?branch=selenium_manager#
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -3643,7 +3670,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -3654,7 +3681,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -3748,7 +3775,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -3818,7 +3845,7 @@ version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8"
dependencies = [
- "indexmap 2.12.0",
+ "indexmap 2.12.1",
"serde_core",
"serde_spanned",
"toml_datetime",
@@ -3868,14 +3895,14 @@ dependencies = [
[[package]]
name = "tower-http"
-version = "0.6.6"
+version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
+checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456"
dependencies = [
"bitflags 2.10.0",
"bytes",
"futures-util",
- "http 1.3.1",
+ "http 1.4.0",
"http-body",
"iri-string",
"pin-project-lite",
@@ -3898,9 +3925,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
-version = "0.1.41"
+version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647"
dependencies = [
"log",
"pin-project-lite",
@@ -3910,20 +3937,20 @@ dependencies = [
[[package]]
name = "tracing-attributes"
-version = "0.1.30"
+version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
name = "tracing-core"
-version = "0.1.34"
+version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
+checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c"
dependencies = [
"once_cell",
]
@@ -3952,7 +3979,7 @@ checksum = "ee6ff59666c9cbaec3533964505d39154dc4e0a56151fdea30a09ed0301f62e2"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
"termcolor",
]
@@ -3964,7 +3991,7 @@ checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442"
dependencies = [
"bytes",
"data-encoding",
- "http 1.3.1",
+ "http 1.4.0",
"httparse",
"log",
"rand 0.9.2",
@@ -4110,9 +4137,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
-version = "1.18.1"
+version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
+checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -4181,9 +4208,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
[[package]]
name = "wasm-bindgen"
-version = "0.2.105"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
+checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
dependencies = [
"cfg-if",
"once_cell",
@@ -4194,9 +4221,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.55"
+version = "0.4.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0"
+checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c"
dependencies = [
"cfg-if",
"js-sys",
@@ -4207,9 +4234,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.105"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
+checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -4217,31 +4244,31 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.105"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
+checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.105"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
+checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
dependencies = [
"unicode-ident",
]
[[package]]
name = "web-sys"
-version = "0.3.82"
+version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1"
+checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -4388,7 +4415,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -4399,7 +4426,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -4675,9 +4702,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "winnow"
-version = "0.7.13"
+version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
+checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
[[package]]
name = "winsafe"
@@ -4776,28 +4803,28 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
"synstructure",
]
[[package]]
name = "zerocopy"
-version = "0.8.27"
+version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
+checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
-version = "0.8.27"
+version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
+checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -4817,7 +4844,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
"synstructure",
]
@@ -4838,7 +4865,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -4871,7 +4898,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.110",
+ "syn 2.0.111",
]
[[package]]
@@ -4883,16 +4910,16 @@ dependencies = [
"arbitrary",
"crc32fast",
"flate2",
- "indexmap 2.12.0",
+ "indexmap 2.12.1",
"memchr",
"zopfli",
]
[[package]]
name = "zlib-rs"
-version = "0.5.2"
+version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2"
+checksum = "36134c44663532e6519d7a6dfdbbe06f6f8192bde8ae9ed076e9b213f0e31df7"
[[package]]
name = "zopfli"
diff --git a/server/Cargo.toml b/server/Cargo.toml
index 0bf216d1..0792f084 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -75,7 +75,7 @@ dunce = "1.0.5"
# This is also for integration testing.
futures = { version = "0.3.31", optional = true }
futures-util = "0.3.29"
-htmd = { git = "https://github.com/bjones1/htmd.git", branch = "fix-faithful-serialization", version = "0.3.2" }
+htmd = { version = "0.5" }
imara-diff = { version = "0.2", features = [] }
indoc = "2.0.5"
lazy_static = "1"
From bb22c254a100a76c4f188381cc8cb57072f01e5d Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Wed, 3 Dec 2025 23:06:46 -0600
Subject: [PATCH 35/38] Fix: specify webdriver resolution to ensure enough
width so that a full line of text fits on one line of the Client.
---
server/tests/overall_core/mod.rs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/server/tests/overall_core/mod.rs b/server/tests/overall_core/mod.rs
index 94a3b1c5..c7c0aa12 100644
--- a/server/tests/overall_core/mod.rs
+++ b/server/tests/overall_core/mod.rs
@@ -164,6 +164,8 @@ macro_rules! harness {
// Start the webdriver.
let server_url = "http://localhost:4444";
let mut caps = DesiredCapabilities::chrome();
+ // Ensure the screen is wide enough for an 80-character line, used to word wrapping test in `test_client_updates`. Otherwise, this test send the End 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("--headless")?;
// On Ubuntu CI, avoid failures, probably due to running Chrome as
// root.
From 7cb31805d907dfa2fea7df735611ee079adf956d Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Thu, 4 Dec 2025 07:34:46 -0600
Subject: [PATCH 36/38] Fix: use specific key for macos.
---
server/tests/overall_core/mod.rs | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/server/tests/overall_core/mod.rs b/server/tests/overall_core/mod.rs
index c7c0aa12..91a1de09 100644
--- a/server/tests/overall_core/mod.rs
+++ b/server/tests/overall_core/mod.rs
@@ -1163,7 +1163,15 @@ async fn test_client_updates_core(
let code_line_css = ".CodeChat-CodeMirror .cm-line";
let code_line = driver_ref.find(By::Css(code_line_css)).await.unwrap();
code_line
- .send_keys(Key::Alt + Key::Control + "g")
+ .send_keys(
+ Key::Alt
+ + if cfg!(target_os = "macos") {
+ Key::Command
+ } else {
+ Key::Control
+ }
+ + "g",
+ )
.await
.unwrap();
// Enter a line in the dialog that pops up.
From 19d63735c7b0d99c67c1db0794f2c8b2f5ced5da Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Thu, 4 Dec 2025 07:41:05 -0600
Subject: [PATCH 37/38] Fix: only use debug logging in debug builds.
---
extensions/VSCode/src/lib.rs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/extensions/VSCode/src/lib.rs b/extensions/VSCode/src/lib.rs
index c15ee28e..a0108ddf 100644
--- a/extensions/VSCode/src/lib.rs
+++ b/extensions/VSCode/src/lib.rs
@@ -37,7 +37,11 @@ use code_chat_editor::{ide, webserver};
pub fn init_server(extension_base_path: String) -> Result<(), Error> {
webserver::init_server(
Some(&PathBuf::from(extension_base_path)),
- LevelFilter::Debug,
+ if cfg!(debug_assertions) {
+ LevelFilter::Debug
+ } else {
+ LevelFilter::Warn
+ },
)
.map_err(|err| Error::new(Status::GenericFailure, err.to_string()))
}
From 5816a3f372cf49a8c55faca11ac25e2a45dba319 Mon Sep 17 00:00:00 2001
From: "Bryan A. Jones"
Date: Thu, 4 Dec 2025 10:30:19 -0600
Subject: [PATCH 38/38] Fix: add in expected cursor/scroll updates after an
autosave delay.
---
server/tests/overall_core/mod.rs | 36 +++++++++++++++++++++++++++++---
1 file changed, 33 insertions(+), 3 deletions(-)
diff --git a/server/tests/overall_core/mod.rs b/server/tests/overall_core/mod.rs
index 91a1de09..688e88b9 100644
--- a/server/tests/overall_core/mod.rs
+++ b/server/tests/overall_core/mod.rs
@@ -357,14 +357,28 @@ async fn test_server_core(
// Focus it.
doc_block_contents.click().await.unwrap();
- sleep(Duration::from_millis(100)).await;
+ // The click produces an updated cursor/scroll location after an autosave delay.
+ let mut client_id = INITIAL_CLIENT_MESSAGE_ID;
+ assert_eq!(
+ codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
+ EditorMessage {
+ id: client_id,
+ message: EditorMessageContents::Update(UpdateMessageContents {
+ file_path: path_str.clone(),
+ contents: None,
+ cursor_position: Some(1),
+ scroll_position: Some(1.0)
+ })
+ }
+ );
+
// Refind it, since it's now switched with a TinyMCE editor.
let tinymce_contents = driver_ref.find(By::Id("TinyMCE-inst")).await.unwrap();
// Make an edit.
tinymce_contents.send_keys("foo").await.unwrap();
// Verify the updated text.
- let mut client_id = INITIAL_CLIENT_MESSAGE_ID;
+ client_id += MESSAGE_ID_INCREMENT;
// Update the version from the value provided by the client, which varies randomly.
let msg = codechat_server.get_message_timeout(TIMEOUT).await.unwrap();
let client_version = get_version(&msg);
@@ -1150,6 +1164,8 @@ async fn test_client_updates_core(
}
);
codechat_server.send_result(client_id, None).await.unwrap();
+ client_id += MESSAGE_ID_INCREMENT;
+
// The Server sends the Client a wrapped version of the text; the Client replies with a Result(Ok).
assert_eq!(
codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
@@ -1182,13 +1198,27 @@ async fn test_client_updates_core(
.send_keys("4" + Key::Enter)
.await
.unwrap();
+ // The cursor movement produces a cursor/scroll position update after an autosave delay.
+ assert_eq!(
+ codechat_server.get_message_timeout(TIMEOUT).await.unwrap(),
+ EditorMessage {
+ id: client_id,
+ message: EditorMessageContents::Update(UpdateMessageContents {
+ file_path: path_str.clone(),
+ contents: None,
+ cursor_position: Some(4),
+ scroll_position: Some(1.0)
+ })
+ }
+ );
+ client_id += MESSAGE_ID_INCREMENT;
+
// Add an indented comment.
code_line.send_keys(Key::Home + "# ").await.unwrap();
// This should edit the (new) third line of the file after word wrap: `def
// foo():`.
let msg = codechat_server.get_message_timeout(TIMEOUT).await.unwrap();
let new_client_version = get_version(&msg);
- client_id += MESSAGE_ID_INCREMENT;
assert_eq!(
msg,
EditorMessage {