From 3c81982b74da7213f985827bba3ad02f8fc3e3d9 Mon Sep 17 00:00:00 2001 From: rolv Date: Sat, 21 Sep 2024 12:58:21 +0100 Subject: [PATCH 01/12] fix!: adjustments after refactor --- CHANGELOG.md | 10 +- Cargo.toml | 2 +- README.md | 4 +- benches/benchmarks/check_texts.rs | 16 ++-- src/api/check.rs | 32 ++++--- src/api/languages.rs | 3 - src/api/mod.rs | 47 ++++++---- src/api/server.rs | 146 +++++++++++++---------------- src/api/words/add.rs | 38 ++++++++ src/api/words/delete.rs | 33 +++++++ src/api/{words.rs => words/mod.rs} | 88 ++--------------- src/check.rs | 30 +++--- src/cli.rs | 12 ++- tests/match_positions.rs | 2 +- 14 files changed, 229 insertions(+), 234 deletions(-) create mode 100644 src/api/words/add.rs create mode 100644 src/api/words/delete.rs rename src/api/{words.rs => words/mod.rs} (60%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9875507..48bd1de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,14 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [3.0.0](https://github.com/jeertmans/languagetool-rust/compare/v2.1.4...v2.1.5) -- Added support for Mardown and Typst files. +- Added support for Markdown and Typst files. [#117](https://github.com/jeertmans/languagetool-rust/pull/117) -### Chore +### Breaking -- **Breaking** Stopped (de)serializing structs that did not need. +- **Breaking** Stopped (de)serializing structs that did not need it. [#117](https://github.com/jeertmans/languagetool-rust/pull/117) -- **Breaking** Completly reorganized the crate. +- **Breaking** Completely reorganized the crate. [#117](https://github.com/jeertmans/languagetool-rust/pull/117) ## [2.1.4](https://github.com/jeertmans/languagetool-rust/compare/v2.1.3...v2.1.4) @@ -182,7 +182,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#6](https://github.com/jeertmans/languagetool-rust/pull/6) - Add compare links to release tags in CHANGELOG. [#9](https://github.com/jeertmans/languagetool-rust/pull/9) -- Add action to check if can publish. +- Add action to check if crate is publishable. [#11](https://github.com/jeertmans/languagetool-rust/pull/11) ### Added diff --git a/Cargo.toml b/Cargo.toml index cdbaf23..c2e540f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,7 +60,7 @@ license = "MIT" name = "languagetool-rust" readme = "README.md" repository = "https://github.com/jeertmans/languagetool-rust" -rust-version = "1.64.0" +rust-version = "1.70.0" version = "2.1.4" [package.metadata.docs.rs] diff --git a/README.md b/README.md index 003d1ad..d54ebcf 100644 --- a/README.md +++ b/README.md @@ -153,14 +153,14 @@ languagetool_rust = "^2.1" ### Example ```rust -use languagetool_rust::{check::CheckRequest, server::ServerClient}; +use languagetool_rust::api::{check::CheckRequest, server::ServerClient}; #[tokio::main] async fn main() -> Result<(), Box> { let client = ServerClient::from_env_or_default(); let req = CheckRequest::default() - .with_text("Some phrase with a smal mistake".to_string()); # codespell:ignore smal + .with_text("Some phrase with a smal mistake".to_string()); //# codespell:ignore smal println!( "{}", diff --git a/benches/benchmarks/check_texts.rs b/benches/benchmarks/check_texts.rs index 757eed2..c52acd0 100644 --- a/benches/benchmarks/check_texts.rs +++ b/benches/benchmarks/check_texts.rs @@ -1,9 +1,11 @@ use criterion::{criterion_group, Criterion, Throughput}; use futures::future::join_all; use languagetool_rust::{ - check::{CheckRequest, CheckResponse, CheckResponseWithContext}, + api::{ + check::{CheckRequest, CheckResponse, CheckResponseWithContext}, + server::ServerClient, + }, error::Error, - server::ServerClient, }; static FILES: [(&str, &str); 3] = [ @@ -44,12 +46,10 @@ async fn check_text_split(text: &str) -> CheckResponse { ); let lines = text.lines(); - let resps = join_all(lines.map(|line| { - async { - let req = CheckRequest::default().with_text(line.to_string()); - let resp = request_until_success(&req, &client).await; - CheckResponseWithContext::new(req.get_text(), resp) - } + let resps = join_all(lines.map(|line| async { + let req = CheckRequest::default().with_text(line.to_string()); + let resp = request_until_success(&req, &client).await; + CheckResponseWithContext::new(req.get_text(), resp) })) .await; diff --git a/src/api/check.rs b/src/api/check.rs index 41f2512..b830d6d 100644 --- a/src/api/check.rs +++ b/src/api/check.rs @@ -12,7 +12,7 @@ use annotate_snippets::{ use clap::{Args, Parser, ValueEnum}; use serde::{Deserialize, Serialize, Serializer}; -use super::error::{Error, Result}; +use crate::error::{Error, Result}; /// Requests @@ -23,7 +23,7 @@ use super::error::{Error, Result}; /// - a five character string matching pattern `[a-z]{2}-[A-Z]{2} /// - or some more complex ascii string (see below) /// -/// Language code is case insensitive. +/// Language code is case-insensitive. /// /// Therefore, a valid language code must match the following: /// @@ -38,7 +38,7 @@ use super::error::{Error, Result}; /// # Examples /// /// ``` -/// # use languagetool_rust::check::parse_language_code; +/// # use languagetool_rust::api::check::parse_language_code; /// assert!(parse_language_code("en").is_ok()); /// /// assert!(parse_language_code("en-US").is_ok()); @@ -187,7 +187,7 @@ impl DataAnnotation { #[cfg(test)] mod data_annotation_tests { - use crate::check::DataAnnotation; + use super::DataAnnotation; #[test] fn test_text() { @@ -277,7 +277,7 @@ impl Level { /// # Examples /// /// ``` - /// # use languagetool_rust::check::Level; + /// # use languagetool_rust::api::check::Level; /// /// let level: Level = Default::default(); /// @@ -296,7 +296,7 @@ impl Level { /// # Examples /// /// ``` -/// # use languagetool_rust::check::split_len; +/// # use languagetool_rust::api::check::split_len; /// let s = "I have so many friends. /// They are very funny. /// I think I am very lucky to have them. @@ -696,7 +696,7 @@ pub struct CheckCommand { /// Specify the files type to use the correct parser. /// /// If set to auto, the type is guessed from the filename extension. - #[clap(long, default_value = "default", ignore_case = true, value_enum)] + #[clap(long, value_enum, default_value_t = FileType::default(), ignore_case = true)] pub r#type: FileType, /// Optional filenames from which input is read. #[arg(conflicts_with_all(["text", "data"]), value_parser = parse_filename)] @@ -709,7 +709,7 @@ pub struct CheckCommand { #[cfg(test)] mod request_tests { - use crate::CheckRequest; + use super::CheckRequest; #[test] fn test_with_text() { @@ -845,7 +845,7 @@ pub struct Rule { pub urls: Option>, } -/// Type of a given match. +/// Type of given match. #[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] #[non_exhaustive] @@ -876,7 +876,7 @@ pub struct Match { /// More context to match, post-processed using original text. #[serde(skip_serializing_if = "Option::is_none")] pub more_context: Option, - /// Char index at which the match start. + /// Char index at which the match starts. pub offset: usize, /// List of possible replacements (if applies). pub replacements: Vec, @@ -959,7 +959,7 @@ impl CheckResponse { #[must_use] pub fn annotate(&self, text: &str, origin: Option<&str>, color: bool) -> String { if self.matches.is_empty() { - return "No error were found in provided text".to_string(); + return "No errors were found in provided text".to_string(); } let replacements: Vec<_> = self .matches @@ -975,8 +975,11 @@ impl CheckResponse { }) .collect(); - let snippets = self.matches.iter().zip(replacements.iter()).map(|(m, r)| { - Snippet { + let snippets = self + .matches + .iter() + .zip(replacements.iter()) + .map(|(m, r)| Snippet { title: Some(Annotation { label: Some(&m.message), id: Some(&m.rule.id), @@ -1005,8 +1008,7 @@ impl CheckResponse { color, ..Default::default() }, - } - }); + }); let mut annotation = String::new(); diff --git a/src/api/languages.rs b/src/api/languages.rs index ffa9173..ad4014f 100644 --- a/src/api/languages.rs +++ b/src/api/languages.rs @@ -2,9 +2,6 @@ use serde::{Deserialize, Serialize}; -/// LanguageTool GET languages request. -pub struct Request; - #[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] #[non_exhaustive] diff --git a/src/api/mod.rs b/src/api/mod.rs index ee62576..f4a5e7c 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,23 +1,24 @@ -/// Raw bindings to the LanguageTool API v1.1.2. -/// -/// The current bindings were generated using the -/// [HTTP API documentation](https://languagetool.org/http-api/). -/// -/// Unfortunately, the LanguageTool API is not as documented as we could -/// hope, and resquests might return undocumented fields. Those are deserialized -/// to the `undocumented` field. +//! Raw bindings to the LanguageTool API v1.1.2. +//! +//! The current bindings were generated using the +//! [HTTP API documentation](https://languagetool.org/http-api/). +//! +//! Unfortunately, the LanguageTool API is not as documented as we could +//! hope, and requests might return undocumented fields. Those are de-serialized +//! to the `undocumented` field. pub mod check; pub mod languages; pub mod server; pub mod words; -/// A HTTP client for making requests to some LanguageTool server. +/// A HTTP client for making requests to a LanguageTool server. +#[derive(Debug)] pub struct Client { /// Server's hostname. hostname: String, /// Server's port. port: Option, - /// Inner client to perform HTTP requets. + /// Inner client to perform HTTP requests. client: reqwest::Client, } @@ -25,40 +26,46 @@ impl Default for Client { fn default() -> Self { Self { hostname: "https://api.languagetoolplus.com".to_string(), - ..Default::default() + port: None, + client: Default::default(), } } } impl Client { - /// Construct a HTTP url base on the current hostname, optional port, + /// Construct an HTTP URL base on the current hostname, optional port, /// and provided endpoint. #[inline] + #[must_use] pub fn url(&self, endpoint: &str) -> String { - let hostname = self.hostname; - match self.port { + let hostname = &self.hostname; + match &self.port { Some(p) => format!("{hostname}:{p}/v2{endpoint}"), None => format!("{hostname}/v2{endpoint}"), } } /// Send a check request to the server and await for the response. - pub async fn check(&self, request: &check::Request) -> Result { + pub async fn check( + &self, + request: &check::CheckRequest, + ) -> reqwest::Result { self.client .post(self.url("/check")) .query(request) .send() .await? - .json::() + .json::() + .await } - /// Send a words request to the server and await for the response. - pub async fn languages(&self, request: &languages::Request) -> Result { + /// Send a request for the list of supported languages to the server and await for the response. + pub async fn languages(&self) -> reqwest::Result { self.client .get(self.url("/languages")) - .query(request) .send() .await? - .json::() + .json::() + .await } } diff --git a/src/api/server.rs b/src/api/server.rs index 8c38b1b..e60b13e 100644 --- a/src/api/server.rs +++ b/src/api/server.rs @@ -1,13 +1,10 @@ //! Structure to communicate with some `LanguageTool` server through the API. use crate::{ - check::{CheckRequest, CheckResponse, CheckResponseWithContext}, + api::check::{CheckRequest, CheckResponse, CheckResponseWithContext}, + api::languages, + api::words, error::{Error, Result}, - languages::LanguagesResponse, - words::{ - WordsAddRequest, WordsAddResponse, WordsDeleteRequest, WordsDeleteResponse, WordsRequest, - WordsResponse, - }, }; #[cfg(feature = "cli")] use clap::Args; @@ -25,7 +22,7 @@ use std::{io, path::PathBuf, time::Instant}; /// # Examples /// /// ``` -/// # use languagetool_rust::server::parse_port; +/// # use languagetool_rust::api::server::parse_port; /// assert!(parse_port("8081").is_ok()); /// /// assert!(parse_port("").is_ok()); // No port specified, which is accepted @@ -143,17 +140,15 @@ impl ConfigFile { Value::Bool(b) => writeln!(w, "{key}={b}")?, Value::Number(n) => writeln!(w, "{key}={n}")?, Value::String(s) => writeln!(w, "{key}=\"{s}\"")?, - Value::Array(a) => { - writeln!( - w, - "{}=\"{}\"", - key, - a.iter() - .map(std::string::ToString::to_string) - .collect::>() - .join(",") - )? - }, + Value::Array(a) => writeln!( + w, + "{}=\"{}\"", + key, + a.iter() + .map(std::string::ToString::to_string) + .collect::>() + .join(",") + )?, Value::Object(o) => { for (key, value) in o.iter() { writeln!(w, "{key}=\"{value}\"")? @@ -376,29 +371,26 @@ impl ServerClient { .send() .await { - Ok(resp) => { - match resp.error_for_status_ref() { - Ok(_) => { - resp.json::() - .await - .map_err(Error::ResponseDecode) - .map(|mut resp| { - if self.max_suggestions > 0 { - let max = self.max_suggestions as usize; - resp.matches.iter_mut().for_each(|m| { - let len = m.replacements.len(); - if max < len { - m.replacements[max] = - format!("... ({} not shown)", len - max).into(); - m.replacements.truncate(max + 1); - } - }); + Ok(resp) => match resp.error_for_status_ref() { + Ok(_) => resp + .json::() + .await + .map_err(Error::ResponseDecode) + .map(|mut resp| { + if self.max_suggestions > 0 { + let max = self.max_suggestions as usize; + resp.matches.iter_mut().for_each(|m| { + let len = m.replacements.len(); + if max < len { + m.replacements[max] = + format!("... ({} not shown)", len - max).into(); + m.replacements.truncate(max + 1); } - resp - }) - }, - Err(_) => Err(Error::InvalidRequest(resp.text().await?)), - } + }); + } + resp + }), + Err(_) => Err(Error::InvalidRequest(resp.text().await?)), }, Err(e) => Err(Error::RequestEncode(e)), } @@ -459,29 +451,26 @@ impl ServerClient { } /// Send a languages request to the server and await for the response. - pub async fn languages(&self) -> Result { + pub async fn languages(&self) -> Result { match self .client .get(format!("{}/languages", self.api)) .send() .await { - Ok(resp) => { - match resp.error_for_status_ref() { - Ok(_) => { - resp.json::() - .await - .map_err(Error::ResponseDecode) - }, - Err(_) => Err(Error::InvalidRequest(resp.text().await?)), - } + Ok(resp) => match resp.error_for_status_ref() { + Ok(_) => resp + .json::() + .await + .map_err(Error::ResponseDecode), + Err(_) => Err(Error::InvalidRequest(resp.text().await?)), }, Err(e) => Err(Error::RequestEncode(e)), } } /// Send a words request to the server and await for the response. - pub async fn words(&self, request: &WordsRequest) -> Result { + pub async fn words(&self, request: &words::Request) -> Result { match self .client .get(format!("{}/words", self.api)) @@ -489,22 +478,19 @@ impl ServerClient { .send() .await { - Ok(resp) => { - match resp.error_for_status_ref() { - Ok(_) => { - resp.json::() - .await - .map_err(Error::ResponseDecode) - }, - Err(_) => Err(Error::InvalidRequest(resp.text().await?)), - } + Ok(resp) => match resp.error_for_status_ref() { + Ok(_) => resp + .json::() + .await + .map_err(Error::ResponseDecode), + Err(_) => Err(Error::InvalidRequest(resp.text().await?)), }, Err(e) => Err(Error::RequestEncode(e)), } } /// Send a words/add request to the server and await for the response. - pub async fn words_add(&self, request: &WordsAddRequest) -> Result { + pub async fn words_add(&self, request: &words::add::Request) -> Result { match self .client .post(format!("{}/words/add", self.api)) @@ -512,22 +498,22 @@ impl ServerClient { .send() .await { - Ok(resp) => { - match resp.error_for_status_ref() { - Ok(_) => { - resp.json::() - .await - .map_err(Error::ResponseDecode) - }, - Err(_) => Err(Error::InvalidRequest(resp.text().await?)), - } + Ok(resp) => match resp.error_for_status_ref() { + Ok(_) => resp + .json::() + .await + .map_err(Error::ResponseDecode), + Err(_) => Err(Error::InvalidRequest(resp.text().await?)), }, Err(e) => Err(Error::RequestEncode(e)), } } /// Send a words/delete request to the server and await for the response. - pub async fn words_delete(&self, request: &WordsDeleteRequest) -> Result { + pub async fn words_delete( + &self, + request: &words::delete::Request, + ) -> Result { match self .client .post(format!("{}/words/delete", self.api)) @@ -535,15 +521,12 @@ impl ServerClient { .send() .await { - Ok(resp) => { - match resp.error_for_status_ref() { - Ok(_) => { - resp.json::() - .await - .map_err(Error::ResponseDecode) - }, - Err(_) => Err(Error::InvalidRequest(resp.text().await?)), - } + Ok(resp) => match resp.error_for_status_ref() { + Ok(_) => resp + .json::() + .await + .map_err(Error::ResponseDecode), + Err(_) => Err(Error::InvalidRequest(resp.text().await?)), }, Err(e) => Err(Error::RequestEncode(e)), } @@ -583,7 +566,8 @@ impl ServerClient { #[cfg(test)] mod tests { - use crate::{check::CheckRequest, ServerClient}; + use super::ServerClient; + use crate::api::check::CheckRequest; #[tokio::test] async fn test_server_ping() { diff --git a/src/api/words/add.rs b/src/api/words/add.rs new file mode 100644 index 0000000..95af380 --- /dev/null +++ b/src/api/words/add.rs @@ -0,0 +1,38 @@ +//! Structures for `words` requests and responses related to adding. + +use super::*; + +/// LanguageTool POST words add request. +/// +/// Add a word to one of the user's personal dictionaries. Please note that +/// this feature is considered to be used for personal dictionaries +/// which must not contain more than 500 words. If this is an issue for +/// you, please contact us. +#[cfg_attr(feature = "cli", derive(Args))] +#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize, Hash)] +#[non_exhaustive] +pub struct Request { + /// The word to be added. Must not be a phrase, i.e., cannot contain + /// white space. The word is added to a global dictionary that + /// applies to all languages. + #[cfg_attr(feature = "cli", clap(required = true, value_parser = parse_word))] + pub word: String, + /// Login arguments. + #[cfg_attr(feature = "cli", clap(flatten))] + #[serde(flatten)] + pub login: LoginArgs, + /// Name of the dictionary to add the word to; non-existent dictionaries + /// are created after calling this; if unset, adds to special + /// default dictionary. + #[cfg_attr(feature = "cli", clap(long))] + #[serde(skip_serializing_if = "Option::is_none")] + pub dict: Option, +} + +/// LanguageTool POST word add response. +#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)] +#[non_exhaustive] +pub struct Response { + /// `true` if word was correctly added. + pub added: bool, +} diff --git a/src/api/words/delete.rs b/src/api/words/delete.rs new file mode 100644 index 0000000..a1f5af4 --- /dev/null +++ b/src/api/words/delete.rs @@ -0,0 +1,33 @@ +//! Structures for `words` requests and responses related to deleting. + +use super::*; + +/// LanguageTool POST words delete request. +/// +/// Remove a word from one of the user's personal dictionaries. +#[cfg_attr(feature = "cli", derive(Args))] +#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize, Hash)] +#[non_exhaustive] +pub struct Request { + /// The word to be removed. + #[cfg_attr(feature = "cli", clap(required = true, value_parser = parse_word))] + pub word: String, + /// Login arguments. + #[cfg_attr(feature = "cli", clap(flatten))] + #[serde(flatten)] + pub login: LoginArgs, + /// Name of the dictionary to add the word to; non-existent dictionaries + /// are created after calling this; if unset, adds to special + /// default dictionary. + #[cfg_attr(feature = "cli", clap(long))] + #[serde(skip_serializing_if = "Option::is_none")] + pub dict: Option, +} + +/// LanguageTool POST word delete response. +#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)] +#[non_exhaustive] +pub struct Response { + /// `true` if word was correctly removed. + pub deleted: bool, +} diff --git a/src/api/words.rs b/src/api/words/mod.rs similarity index 60% rename from src/api/words.rs rename to src/api/words/mod.rs index 68d8dbd..b23f24b 100644 --- a/src/api/words.rs +++ b/src/api/words/mod.rs @@ -1,12 +1,15 @@ //! Structures for `words` requests and responses. -use crate::{Error, Result}; +use crate::error::{Error, Result}; use super::check::serialize_option_vec_string; #[cfg(feature = "cli")] use clap::{Args, Parser, Subcommand}; use serde::{Deserialize, Serialize}; +pub mod add; +pub mod delete; + /// Parse `v` if valid word. /// /// A valid word is any string slice that does not contain any whitespace @@ -14,7 +17,7 @@ use serde::{Deserialize, Serialize}; /// # Examples /// /// ``` -/// # use languagetool_rust::words::parse_word; +/// # use languagetool_rust::api::words::parse_word; /// assert!(parse_word("word").is_ok()); /// /// assert!(parse_word("some words").is_err()); @@ -109,8 +112,8 @@ impl From for Request { #[inline] fn from(args: RequestArgs) -> Self { Self { - offset: args.offset, - limit: args.limit, + offset: Some(args.offset), + limit: Some(args.limit), login: args.login.unwrap(), dicts: args.dicts, } @@ -122,9 +125,9 @@ impl From for Request { #[derive(Clone, Debug, Subcommand)] pub enum WordsSubcommand { /// Add a word to some user's list. - Add(WordsAddRequest), + Add(add::Request), /// Remove a word from some user's list. - Delete(WordsDeleteRequest), + Delete(delete::Request), } /// Retrieve some user's words list. @@ -148,76 +151,3 @@ pub struct Response { /// List of words. pub words: Vec, } - -pub mod add { - use super::*; - - /// LanguageTool POST words add request. - /// - /// Add a word to one of the user's personal dictionaries. Please note that - /// this feature is considered to be used for personal dictionaries - /// which must not contain more than 500 words. If this is an issue for - /// you, please contact us. - #[cfg_attr(feature = "cli", derive(Args))] - #[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize, Hash)] - #[non_exhaustive] - pub struct Request { - /// The word to be added. Must not be a phrase, i.e., cannot contain - /// white space. The word is added to a global dictionary that - /// applies to all languages. - #[cfg_attr(feature = "cli", clap(required = true, value_parser = parse_word))] - pub word: String, - /// Login arguments. - #[cfg_attr(feature = "cli", clap(flatten))] - #[serde(flatten)] - pub login: LoginArgs, - /// Name of the dictionary to add the word to; non-existent dictionaries - /// are created after calling this; if unset, adds to special - /// default dictionary. - #[cfg_attr(feature = "cli", clap(long))] - #[serde(skip_serializing_if = "Option::is_none")] - pub dict: Option, - } - - /// LanguageTool POST word add response. - #[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)] - #[non_exhaustive] - pub struct Response { - /// `true` if word was correctly added. - pub added: bool, - } -} - -pub mod delete { - use super::*; - - /// LanguageTool POST words delete request. - /// - /// Remove a word from one of the user's personal dictionaries. - #[cfg_attr(feature = "cli", derive(Args))] - #[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize, Hash)] - #[non_exhaustive] - pub struct Request { - /// The word to be removed. - #[cfg_attr(feature = "cli", clap(required = true, value_parser = parse_word))] - pub word: String, - /// Login arguments. - #[cfg_attr(feature = "cli", clap(flatten))] - #[serde(flatten)] - pub login: LoginArgs, - /// Name of the dictionary to add the word to; non-existent dictionaries - /// are created after calling this; if unset, adds to special - /// default dictionary. - #[cfg_attr(feature = "cli", clap(long))] - #[serde(skip_serializing_if = "Option::is_none")] - pub dict: Option, - } - - /// LanguageTool POST word delete response. - #[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)] - #[non_exhaustive] - pub struct Response { - /// `true` if word was correctly removed. - pub deleted: bool, - } -} diff --git a/src/check.rs b/src/check.rs index 4fc96b7..f320364 100644 --- a/src/check.rs +++ b/src/check.rs @@ -25,7 +25,7 @@ use super::error::{Error, Result}; /// - a five character string matching pattern `[a-z]{2}-[A-Z]{2} /// - or some more complex ascii string (see below) /// -/// Language code is case insensitive. +/// Language code is case-insensitive. /// /// Therefore, a valid language code must match the following: /// @@ -40,7 +40,7 @@ use super::error::{Error, Result}; /// # Examples /// /// ``` -/// # use languagetool_rust::check::parse_language_code; +/// # use languagetool_rust::api::check::parse_language_code; /// assert!(parse_language_code("en").is_ok()); /// /// assert!(parse_language_code("en-US").is_ok()); @@ -279,7 +279,7 @@ impl Level { /// # Examples /// /// ``` - /// # use languagetool_rust::check::Level; + /// # use languagetool_rust::api::check::Level; /// /// let level: Level = Default::default(); /// @@ -298,7 +298,7 @@ impl Level { /// # Examples /// /// ``` -/// # use languagetool_rust::check::split_len; +/// # use languagetool_rust::api::check::split_len; /// let s = "I have so many friends. /// They are very funny. /// I think I am very lucky to have them. @@ -815,7 +815,7 @@ impl From<&str> for Replacement { #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] #[non_exhaustive] pub struct Category { - /// Category id. + /// Category ID. pub id: String, /// Category name. pub name: String, @@ -838,14 +838,14 @@ pub struct Rule { pub category: Category, /// Rule description. pub description: String, - /// Rule id. + /// Rule ID. pub id: String, /// Issue type. pub issue_type: String, /// Rule source file. - /// Rule sub id. + /// Rule sub ID. pub sub_id: Option, - /// Rule list of urls. + /// Rule list of URLs. pub urls: Option>, /// Undocumented fields. /// @@ -858,7 +858,7 @@ pub struct Rule { pub undocumented: HashMap, } -/// Type of a given match. +/// Type of given match. #[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] #[non_exhaustive] @@ -970,7 +970,7 @@ impl Response { #[must_use] pub fn annotate(&self, text: &str, origin: Option<&str>, color: bool) -> String { if self.matches.is_empty() { - return "No error were found in provided text".to_string(); + return "No errors were found in provided text".to_string(); } let replacements: Vec<_> = self .matches @@ -986,8 +986,11 @@ impl Response { }) .collect(); - let snippets = self.matches.iter().zip(replacements.iter()).map(|(m, r)| { - Snippet { + let snippets = self + .matches + .iter() + .zip(replacements.iter()) + .map(|(m, r)| Snippet { title: Some(Annotation { label: Some(&m.message), id: Some(&m.rule.id), @@ -1016,8 +1019,7 @@ impl Response { color, ..Default::default() }, - } - }); + }); let mut annotation = String::new(); diff --git a/src/cli.rs b/src/cli.rs index 5aa65ee..47dfdcf 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -11,10 +11,12 @@ use termcolor::WriteColor; use termcolor::{ColorChoice, StandardStream}; use crate::{ - check::CheckResponseWithContext, + api::{ + check::CheckResponseWithContext, + server::{ServerCli, ServerClient}, + words::WordsSubcommand, + }, error::Result, - server::{ServerCli, ServerClient}, - words::WordsSubcommand, }; /// Read lines from standard input and write to buffer string. @@ -71,7 +73,7 @@ pub struct Cli { #[allow(missing_docs)] pub enum Command { /// Check text using LanguageTool server. - Check(crate::check::CheckCommand), + Check(crate::api::check::CheckCommand), /// Commands to easily run a LanguageTool server with Docker. #[cfg(feature = "docker")] Docker(crate::docker::DockerCommand), @@ -81,7 +83,7 @@ pub enum Command { /// Ping the LanguageTool server and return time elapsed in ms if success. Ping, /// Retrieve some user's words list, or add / delete word from it. - Words(crate::words::WordsCommand), + Words(crate::api::words::WordsCommand), /// Generate tab-completion scripts for supported shells #[cfg(feature = "cli-complete")] Completions(complete::CompleteCommand), diff --git a/tests/match_positions.rs b/tests/match_positions.rs index eb47b4e..78b61d0 100644 --- a/tests/match_positions.rs +++ b/tests/match_positions.rs @@ -1,4 +1,4 @@ -use languagetool_rust::{ +use languagetool_rust::api::{ check::{CheckRequest, CheckResponseWithContext}, server::ServerClient, }; From 198feecd34ac8fd6730d32649cb25e2617cd6673 Mon Sep 17 00:00:00 2001 From: Rolv Apneseth Date: Sat, 21 Sep 2024 15:24:13 +0100 Subject: [PATCH 02/12] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérome Eertmans --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d54ebcf..1eec660 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ async fn main() -> Result<(), Box> { let client = ServerClient::from_env_or_default(); let req = CheckRequest::default() - .with_text("Some phrase with a smal mistake".to_string()); //# codespell:ignore smal + .with_text("Some phrase with a smal mistake".to_string()); // # codespell:ignore smal println!( "{}", From b3f3450182b3219bea5d6743d51ce0f28443ed68 Mon Sep 17 00:00:00 2001 From: rolv Date: Sat, 21 Sep 2024 22:05:57 +0100 Subject: [PATCH 03/12] docs(changelog): remove mention of support for markdown and typst files for now --- CHANGELOG.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48bd1de..0a36562 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [3.0.0](https://github.com/jeertmans/languagetool-rust/compare/v2.1.4...v2.1.5) -- Added support for Markdown and Typst files. - [#117](https://github.com/jeertmans/languagetool-rust/pull/117) - -### Breaking - - **Breaking** Stopped (de)serializing structs that did not need it. [#117](https://github.com/jeertmans/languagetool-rust/pull/117) - **Breaking** Completely reorganized the crate. From 3744b2f8bb8ef4ec4713fddf7aeec10c7e3fc3f6 Mon Sep 17 00:00:00 2001 From: rolv Date: Sat, 21 Sep 2024 22:08:00 +0100 Subject: [PATCH 04/12] refactor: use `check::Request`, `check::Response` and `check::ResponseWithContext` --- README.md | 4 +-- benches/benchmarks/check_texts.rs | 14 ++++----- src/api/check.rs | 48 +++++++++++++++---------------- src/api/mod.rs | 10 +++---- src/api/server.rs | 34 +++++++++++----------- src/cli.rs | 4 +-- tests/match_positions.rs | 9 ++---- 7 files changed, 59 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 1eec660..8380dbb 100644 --- a/README.md +++ b/README.md @@ -153,13 +153,13 @@ languagetool_rust = "^2.1" ### Example ```rust -use languagetool_rust::api::{check::CheckRequest, server::ServerClient}; +use languagetool_rust::api::{check, server::ServerClient}; #[tokio::main] async fn main() -> Result<(), Box> { let client = ServerClient::from_env_or_default(); - let req = CheckRequest::default() + let req = check::Request::default() .with_text("Some phrase with a smal mistake".to_string()); // # codespell:ignore smal println!( diff --git a/benches/benchmarks/check_texts.rs b/benches/benchmarks/check_texts.rs index c52acd0..88038e6 100644 --- a/benches/benchmarks/check_texts.rs +++ b/benches/benchmarks/check_texts.rs @@ -2,7 +2,7 @@ use criterion::{criterion_group, Criterion, Throughput}; use futures::future::join_all; use languagetool_rust::{ api::{ - check::{CheckRequest, CheckResponse, CheckResponseWithContext}, + check::{self, Request, Response}, server::ServerClient, }, error::Error, @@ -14,7 +14,7 @@ static FILES: [(&str, &str); 3] = [ ("large", include_str!("../large.txt")), ]; -async fn request_until_success(req: &CheckRequest, client: &ServerClient) -> CheckResponse { +async fn request_until_success(req: &Request, client: &ServerClient) -> Response { loop { match client.check(req).await { Ok(resp) => return resp, @@ -29,17 +29,17 @@ async fn request_until_success(req: &CheckRequest, client: &ServerClient) -> Che } #[tokio::main] -async fn check_text_basic(text: &str) -> CheckResponse { +async fn check_text_basic(text: &str) -> Response { let client = ServerClient::from_env().expect( "Please use a local server for benchmarking, and configure the environ variables to use \ it.", ); - let req = CheckRequest::default().with_text(text.to_string()); + let req = Request::default().with_text(text.to_string()); request_until_success(&req, &client).await } #[tokio::main] -async fn check_text_split(text: &str) -> CheckResponse { +async fn check_text_split(text: &str) -> Response { let client = ServerClient::from_env().expect( "Please use a local server for benchmarking, and configure the environ variables to use \ it.", @@ -47,9 +47,9 @@ async fn check_text_split(text: &str) -> CheckResponse { let lines = text.lines(); let resps = join_all(lines.map(|line| async { - let req = CheckRequest::default().with_text(line.to_string()); + let req = Request::default().with_text(line.to_string()); let resp = request_until_success(&req, &client).await; - CheckResponseWithContext::new(req.get_text(), resp) + check::ResponseWithContext::new(req.get_text(), resp) })) .await; diff --git a/src/api/check.rs b/src/api/check.rs index b830d6d..2acf258 100644 --- a/src/api/check.rs +++ b/src/api/check.rs @@ -389,7 +389,7 @@ pub fn split_len<'source>(s: &'source str, n: usize, pat: &str) -> Vec<&'source #[derive(Clone, Debug, PartialEq, Eq, Serialize, Hash)] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct CheckRequest { +pub struct Request { /// The text to be checked. This or 'data' is required. #[cfg_attr( feature = "cli", @@ -509,10 +509,10 @@ pub struct CheckRequest { pub level: Level, } -impl Default for CheckRequest { +impl Default for Request { #[inline] - fn default() -> CheckRequest { - CheckRequest { + fn default() -> Request { + Request { text: Default::default(), data: Default::default(), language: "auto".to_string(), @@ -536,7 +536,7 @@ fn is_false(b: &bool) -> bool { !(*b) } -impl CheckRequest { +impl Request { /// Set the text to be checked and remove potential data field. #[must_use] pub fn with_text(mut self, text: String) -> Self { @@ -597,7 +597,7 @@ impl CheckRequest { } /// Return a copy of the text within the request. - /// Call [`CheckRequest::try_get_text`] but panic on error. + /// Call [`check::request::try_get_text`] but panic on error. /// /// # Panics /// @@ -628,7 +628,7 @@ impl CheckRequest { /// Split this request into multiple, using [`split_len`] function to split /// text. - /// Call [`CheckRequest::try_split`] but panic on error. + /// Call [`check::request::try_split`] but panic on error. /// /// # Panics /// @@ -701,19 +701,19 @@ pub struct CheckCommand { /// Optional filenames from which input is read. #[arg(conflicts_with_all(["text", "data"]), value_parser = parse_filename)] pub filenames: Vec, - /// Inner [`CheckRequest`]. + /// Inner [`check::request`]. #[command(flatten, next_help_heading = "Request options")] - pub request: CheckRequest, + pub request: Request, } #[cfg(test)] mod request_tests { - use super::CheckRequest; + use super::Request; #[test] fn test_with_text() { - let req = CheckRequest::default().with_text("hello".to_string()); + let req = Request::default().with_text("hello".to_string()); assert_eq!(req.text.unwrap(), "hello".to_string()); assert!(req.data.is_none()); @@ -721,7 +721,7 @@ mod request_tests { #[test] fn test_with_data() { - let req = CheckRequest::default().with_text("hello".to_string()); + let req = Request::default().with_text("hello".to_string()); assert_eq!(req.text.unwrap(), "hello".to_string()); assert!(req.data.is_none()); @@ -928,7 +928,7 @@ pub struct Warnings { #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct CheckResponse { +pub struct Response { /// Language information. pub language: LanguageResponse, /// List of error matches. @@ -943,7 +943,7 @@ pub struct CheckResponse { pub warnings: Option, } -impl CheckResponse { +impl Response { /// Return an iterator over matches. pub fn iter_matches(&self) -> std::slice::Iter<'_, Match> { self.matches.iter() @@ -1027,19 +1027,19 @@ impl CheckResponse { /// This structure exists to keep a link between a check response /// and the original text that was checked. #[derive(Debug, Clone, PartialEq)] -pub struct CheckResponseWithContext { +pub struct ResponseWithContext { /// Original text that was checked by LT. pub text: String, /// Check response. - pub response: CheckResponse, + pub response: Response, /// Text's length. pub text_length: usize, } -impl CheckResponseWithContext { +impl ResponseWithContext { /// Bind a check response with its original text. #[must_use] - pub fn new(text: String, response: CheckResponse) -> Self { + pub fn new(text: String, response: Response) -> Self { let text_length = text.chars().count(); Self { text, @@ -1098,9 +1098,9 @@ impl CheckResponseWithContext { } } -impl From for CheckResponse { +impl From for Response { #[allow(clippy::needless_borrow)] - fn from(mut resp: CheckResponseWithContext) -> Self { + fn from(mut resp: ResponseWithContext) -> Self { let iter: MatchPositions<'_, std::slice::IterMut<'_, Match>> = (&mut resp).into(); for (line_number, line_offset, m) in iter { @@ -1123,10 +1123,10 @@ pub struct MatchPositions<'source, T> { offset: usize, } -impl<'source> From<&'source CheckResponseWithContext> +impl<'source> From<&'source ResponseWithContext> for MatchPositions<'source, std::slice::Iter<'source, Match>> { - fn from(response: &'source CheckResponseWithContext) -> Self { + fn from(response: &'source ResponseWithContext) -> Self { MatchPositions { text_chars: response.text.chars(), matches: response.iter_matches(), @@ -1137,10 +1137,10 @@ impl<'source> From<&'source CheckResponseWithContext> } } -impl<'source> From<&'source mut CheckResponseWithContext> +impl<'source> From<&'source mut ResponseWithContext> for MatchPositions<'source, std::slice::IterMut<'source, Match>> { - fn from(response: &'source mut CheckResponseWithContext) -> Self { + fn from(response: &'source mut ResponseWithContext) -> Self { MatchPositions { text_chars: response.text.chars(), matches: response.response.iter_matches_mut(), diff --git a/src/api/mod.rs b/src/api/mod.rs index f4a5e7c..c03c4b7 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -46,20 +46,18 @@ impl Client { } /// Send a check request to the server and await for the response. - pub async fn check( - &self, - request: &check::CheckRequest, - ) -> reqwest::Result { + pub async fn check(&self, request: &check::Request) -> reqwest::Result { self.client .post(self.url("/check")) .query(request) .send() .await? - .json::() + .json::() .await } - /// Send a request for the list of supported languages to the server and await for the response. + /// Send a request for the list of supported languages to the server and + /// await for the response. pub async fn languages(&self) -> reqwest::Result { self.client .get(self.url("/languages")) diff --git a/src/api/server.rs b/src/api/server.rs index e60b13e..11432df 100644 --- a/src/api/server.rs +++ b/src/api/server.rs @@ -1,9 +1,10 @@ //! Structure to communicate with some `LanguageTool` server through the API. use crate::{ - api::check::{CheckRequest, CheckResponse, CheckResponseWithContext}, - api::languages, - api::words, + api::{ + check::{self, Request, Response}, + languages, words, + }, error::{Error, Result}, }; #[cfg(feature = "cli")] @@ -363,7 +364,7 @@ impl ServerClient { } /// Send a check request to the server and await for the response. - pub async fn check(&self, request: &CheckRequest) -> Result { + pub async fn check(&self, request: &Request) -> Result { match self .client .post(format!("{0}/check", self.api)) @@ -373,7 +374,7 @@ impl ServerClient { { Ok(resp) => match resp.error_for_status_ref() { Ok(_) => resp - .json::() + .json::() .await .map_err(Error::ResponseDecode) .map(|mut resp| { @@ -402,10 +403,7 @@ impl ServerClient { /// /// If any of the requests has `self.text` field which is none. #[cfg(feature = "multithreaded")] - pub async fn check_multiple_and_join( - &self, - requests: Vec, - ) -> Result { + pub async fn check_multiple_and_join(&self, requests: Vec) -> Result { let mut tasks = Vec::with_capacity(requests.len()); for request in requests.into_iter() { @@ -415,20 +413,22 @@ impl ServerClient { let text = request.text.ok_or(Error::InvalidRequest( "missing text field; cannot join requests with data annotations".to_string(), ))?; - Result::<(String, CheckResponse)>::Ok((text, response)) + Result::<(String, Response)>::Ok((text, response)) })); } - let mut response_with_context: Option = None; + let mut response_with_context: Option = None; for task in tasks { let (text, response) = task.await.unwrap()?; match response_with_context { Some(resp) => { response_with_context = - Some(resp.append(CheckResponseWithContext::new(text, response))) + Some(resp.append(check::ResponseWithContext::new(text, response))) + }, + None => { + response_with_context = Some(check::ResponseWithContext::new(text, response)) }, - None => response_with_context = Some(CheckResponseWithContext::new(text, response)), } } @@ -440,7 +440,7 @@ impl ServerClient { #[cfg(feature = "annotate")] pub async fn annotate_check( &self, - request: &CheckRequest, + request: &Request, origin: Option<&str>, color: bool, ) -> Result { @@ -567,7 +567,7 @@ impl ServerClient { #[cfg(test)] mod tests { use super::ServerClient; - use crate::api::check::CheckRequest; + use crate::api::check::Request; #[tokio::test] async fn test_server_ping() { @@ -578,14 +578,14 @@ mod tests { #[tokio::test] async fn test_server_check_text() { let client = ServerClient::from_env_or_default(); - let req = CheckRequest::default().with_text("je suis une poupee".to_string()); + let req = Request::default().with_text("je suis une poupee".to_string()); assert!(client.check(&req).await.is_ok()); } #[tokio::test] async fn test_server_check_data() { let client = ServerClient::from_env_or_default(); - let req = CheckRequest::default() + let req = Request::default() .with_data_str("{\"annotation\":[{\"text\": \"je suis une poupee\"}]}") .unwrap(); assert!(client.check(&req).await.is_ok()); diff --git a/src/cli.rs b/src/cli.rs index 47dfdcf..00292bc 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -12,7 +12,7 @@ use termcolor::{ColorChoice, StandardStream}; use crate::{ api::{ - check::CheckResponseWithContext, + check, server::{ServerCli, ServerClient}, words::WordsSubcommand, }, @@ -136,7 +136,7 @@ impl Cli { if request.text.is_some() && !cmd.raw { let text = request.text.unwrap(); - response = CheckResponseWithContext::new(text.clone(), response).into(); + response = check::ResponseWithContext::new(text.clone(), response).into(); writeln!( &mut stdout, "{}", diff --git a/tests/match_positions.rs b/tests/match_positions.rs index 78b61d0..944166c 100644 --- a/tests/match_positions.rs +++ b/tests/match_positions.rs @@ -1,7 +1,4 @@ -use languagetool_rust::api::{ - check::{CheckRequest, CheckResponseWithContext}, - server::ServerClient, -}; +use languagetool_rust::api::{check, server::ServerClient}; #[macro_export] macro_rules! test_match_positions { @@ -10,9 +7,9 @@ macro_rules! test_match_positions { async fn $name() -> Result<(), Box> { let client = ServerClient::from_env_or_default(); - let req = CheckRequest::default().with_text($text.to_string()); + let req = check::Request::default().with_text($text.to_string()); let resp = client.check(&req).await.unwrap(); - let resp = CheckResponseWithContext::new(req.get_text(), resp); + let resp = check::ResponseWithContext::new(req.get_text(), resp); let expected = vec![$(($x, $y)),*]; let got = resp.iter_match_positions(); From 4253d2fa785a6c71587539cf722e94af54f616f7 Mon Sep 17 00:00:00 2001 From: rolv Date: Sat, 21 Sep 2024 22:08:42 +0100 Subject: [PATCH 05/12] chore: formatting --- benches/benchmarks/check_texts.rs | 10 ++- src/api/check.rs | 10 +-- src/api/server.rs | 121 +++++++++++++++++------------- 3 files changed, 79 insertions(+), 62 deletions(-) diff --git a/benches/benchmarks/check_texts.rs b/benches/benchmarks/check_texts.rs index 88038e6..6cb123f 100644 --- a/benches/benchmarks/check_texts.rs +++ b/benches/benchmarks/check_texts.rs @@ -46,10 +46,12 @@ async fn check_text_split(text: &str) -> Response { ); let lines = text.lines(); - let resps = join_all(lines.map(|line| async { - let req = Request::default().with_text(line.to_string()); - let resp = request_until_success(&req, &client).await; - check::ResponseWithContext::new(req.get_text(), resp) + let resps = join_all(lines.map(|line| { + async { + let req = Request::default().with_text(line.to_string()); + let resp = request_until_success(&req, &client).await; + check::ResponseWithContext::new(req.get_text(), resp) + } })) .await; diff --git a/src/api/check.rs b/src/api/check.rs index 2acf258..4b8c407 100644 --- a/src/api/check.rs +++ b/src/api/check.rs @@ -975,11 +975,8 @@ impl Response { }) .collect(); - let snippets = self - .matches - .iter() - .zip(replacements.iter()) - .map(|(m, r)| Snippet { + let snippets = self.matches.iter().zip(replacements.iter()).map(|(m, r)| { + Snippet { title: Some(Annotation { label: Some(&m.message), id: Some(&m.rule.id), @@ -1008,7 +1005,8 @@ impl Response { color, ..Default::default() }, - }); + } + }); let mut annotation = String::new(); diff --git a/src/api/server.rs b/src/api/server.rs index 11432df..ebb3a08 100644 --- a/src/api/server.rs +++ b/src/api/server.rs @@ -141,15 +141,17 @@ impl ConfigFile { Value::Bool(b) => writeln!(w, "{key}={b}")?, Value::Number(n) => writeln!(w, "{key}={n}")?, Value::String(s) => writeln!(w, "{key}=\"{s}\"")?, - Value::Array(a) => writeln!( - w, - "{}=\"{}\"", - key, - a.iter() - .map(std::string::ToString::to_string) - .collect::>() - .join(",") - )?, + Value::Array(a) => { + writeln!( + w, + "{}=\"{}\"", + key, + a.iter() + .map(std::string::ToString::to_string) + .collect::>() + .join(",") + )? + }, Value::Object(o) => { for (key, value) in o.iter() { writeln!(w, "{key}=\"{value}\"")? @@ -372,26 +374,29 @@ impl ServerClient { .send() .await { - Ok(resp) => match resp.error_for_status_ref() { - Ok(_) => resp - .json::() - .await - .map_err(Error::ResponseDecode) - .map(|mut resp| { - if self.max_suggestions > 0 { - let max = self.max_suggestions as usize; - resp.matches.iter_mut().for_each(|m| { - let len = m.replacements.len(); - if max < len { - m.replacements[max] = - format!("... ({} not shown)", len - max).into(); - m.replacements.truncate(max + 1); + Ok(resp) => { + match resp.error_for_status_ref() { + Ok(_) => { + resp.json::() + .await + .map_err(Error::ResponseDecode) + .map(|mut resp| { + if self.max_suggestions > 0 { + let max = self.max_suggestions as usize; + resp.matches.iter_mut().for_each(|m| { + let len = m.replacements.len(); + if max < len { + m.replacements[max] = + format!("... ({} not shown)", len - max).into(); + m.replacements.truncate(max + 1); + } + }); } - }); - } - resp - }), - Err(_) => Err(Error::InvalidRequest(resp.text().await?)), + resp + }) + }, + Err(_) => Err(Error::InvalidRequest(resp.text().await?)), + } }, Err(e) => Err(Error::RequestEncode(e)), } @@ -458,12 +463,15 @@ impl ServerClient { .send() .await { - Ok(resp) => match resp.error_for_status_ref() { - Ok(_) => resp - .json::() - .await - .map_err(Error::ResponseDecode), - Err(_) => Err(Error::InvalidRequest(resp.text().await?)), + Ok(resp) => { + match resp.error_for_status_ref() { + Ok(_) => { + resp.json::() + .await + .map_err(Error::ResponseDecode) + }, + Err(_) => Err(Error::InvalidRequest(resp.text().await?)), + } }, Err(e) => Err(Error::RequestEncode(e)), } @@ -478,12 +486,15 @@ impl ServerClient { .send() .await { - Ok(resp) => match resp.error_for_status_ref() { - Ok(_) => resp - .json::() - .await - .map_err(Error::ResponseDecode), - Err(_) => Err(Error::InvalidRequest(resp.text().await?)), + Ok(resp) => { + match resp.error_for_status_ref() { + Ok(_) => { + resp.json::() + .await + .map_err(Error::ResponseDecode) + }, + Err(_) => Err(Error::InvalidRequest(resp.text().await?)), + } }, Err(e) => Err(Error::RequestEncode(e)), } @@ -498,12 +509,15 @@ impl ServerClient { .send() .await { - Ok(resp) => match resp.error_for_status_ref() { - Ok(_) => resp - .json::() - .await - .map_err(Error::ResponseDecode), - Err(_) => Err(Error::InvalidRequest(resp.text().await?)), + Ok(resp) => { + match resp.error_for_status_ref() { + Ok(_) => { + resp.json::() + .await + .map_err(Error::ResponseDecode) + }, + Err(_) => Err(Error::InvalidRequest(resp.text().await?)), + } }, Err(e) => Err(Error::RequestEncode(e)), } @@ -521,12 +535,15 @@ impl ServerClient { .send() .await { - Ok(resp) => match resp.error_for_status_ref() { - Ok(_) => resp - .json::() - .await - .map_err(Error::ResponseDecode), - Err(_) => Err(Error::InvalidRequest(resp.text().await?)), + Ok(resp) => { + match resp.error_for_status_ref() { + Ok(_) => { + resp.json::() + .await + .map_err(Error::ResponseDecode) + }, + Err(_) => Err(Error::InvalidRequest(resp.text().await?)), + } }, Err(e) => Err(Error::RequestEncode(e)), } From fccae51f80b10bafb28f39f67521eedef4271445 Mon Sep 17 00:00:00 2001 From: rolv Date: Sat, 21 Sep 2024 22:14:15 +0100 Subject: [PATCH 06/12] fix: minimum Rust version needs to be higher for `clap` --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c2e540f..cd08d41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,8 +60,8 @@ license = "MIT" name = "languagetool-rust" readme = "README.md" repository = "https://github.com/jeertmans/languagetool-rust" -rust-version = "1.70.0" version = "2.1.4" +rust-version = "1.74.0" [package.metadata.docs.rs] all-features = true From 2f2c7f67feca8feb4d4a1d947e0a0e2a1ea43dbc Mon Sep 17 00:00:00 2001 From: rolv Date: Sat, 21 Sep 2024 22:28:31 +0100 Subject: [PATCH 07/12] fix: doc test --- Cargo.lock | 892 +++++++++++++++---------------- Cargo.toml | 2 +- src/api/check.rs | 6 +- src/check.rs | 1310 ---------------------------------------------- src/error.rs | 2 +- 5 files changed, 455 insertions(+), 1757 deletions(-) delete mode 100644 src/check.rs diff --git a/Cargo.lock b/Cargo.lock index 5bb28de..81821f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,24 +4,24 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aho-corasick" -version = "1.0.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8f9420f797f2d9e935edf629310eb938a0d839f984e25327f3c7eed22300c" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -34,9 +34,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "annotate-snippets" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3b9d411ecbaf79885c6df4d75fff75858d5995ff25385657a28af47e82f9c36" +checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" dependencies = [ "unicode-width", "yansi-term", @@ -44,47 +44,48 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.1" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -92,13 +93,14 @@ dependencies = [ [[package]] name = "assert_cmd" -version = "2.0.12" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6" +checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d" dependencies = [ "anstyle", "bstr", "doc-comment", + "libc", "predicates", "predicates-core", "predicates-tree", @@ -107,30 +109,30 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] name = "base64" -version = "0.21.2" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bitflags" @@ -140,15 +142,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bstr" -version = "1.6.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", "regex-automata", @@ -157,15 +159,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytes" -version = "1.4.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "cast" @@ -175,11 +177,11 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.82" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" dependencies = [ - "libc", + "shlex", ] [[package]] @@ -190,9 +192,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "ciborium" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", @@ -201,15 +203,15 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", @@ -217,9 +219,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" dependencies = [ "clap_builder", "clap_derive", @@ -227,9 +229,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" dependencies = [ "anstream", "anstyle", @@ -240,18 +242,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.2" +version = "4.5.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e" +checksum = "8937760c3f4c60871870b8c3ee5f9b30771f792a7045c48bcbba999d7d6b3b8e" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck", "proc-macro2", @@ -261,15 +263,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "comemo" @@ -296,9 +298,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -306,9 +308,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "criterion" @@ -346,48 +348,36 @@ dependencies = [ "itertools", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "difflib" @@ -412,45 +402,40 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] [[package]] -name = "errno" -version = "0.3.2" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "errno" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] name = "fastrand" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "float-cmp" @@ -484,18 +469,18 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -508,9 +493,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -518,15 +503,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -535,15 +520,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", @@ -552,21 +537,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -591,15 +576,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -616,15 +601,19 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" @@ -634,15 +623,21 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "http" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -651,9 +646,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -662,21 +657,21 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" dependencies = [ "bytes", "futures-channel", @@ -689,7 +684,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2", "tokio", "tower-service", "tracing", @@ -711,9 +706,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -721,31 +716,37 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ - "autocfg", + "equivalent", "hashbrown", ] [[package]] name = "ipnet" -version = "2.8.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" [[package]] name = "is-terminal" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "hermit-abi", - "rustix", - "windows-sys 0.48.0", + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.10.5" @@ -757,15 +758,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -793,29 +794,23 @@ dependencies = [ "typst-syntax", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" -version = "0.2.147" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "linux-raw-sys" -version = "0.4.5" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -823,24 +818,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mime" @@ -850,31 +836,31 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "0.8.8" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi 0.3.9", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "lazy_static", "libc", "log", "openssl", @@ -894,51 +880,41 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" -version = "0.31.1" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "openssl" -version = "0.10.56" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729b745ad4a5575dd06a3e1af1414bd330ee561c01b3899eb584baeaa8def17e" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", @@ -966,18 +942,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "111.27.0+1.1.1v" +version = "300.3.2+3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e8f197c82d7511c5b014030c9b1efeda40d7d5f99d23b4ceed3524a5e63f02" +checksum = "a211a18d945ef7e648cc6e0058f4c548ee46aab922ea203e0d30e966ea23647b" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.91" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -988,9 +964,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -998,28 +974,28 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", - "windows-targets 0.48.1", + "windows-targets 0.52.6", ] [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1029,15 +1005,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plotters" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -1048,29 +1024,28 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] [[package]] name = "predicates" -version = "3.0.3" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9" +checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" dependencies = [ "anstyle", "difflib", "float-cmp", - "itertools", "normalize-line-endings", "predicates-core", "regex", @@ -1078,15 +1053,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" dependencies = [ "predicates-core", "termtree", @@ -1094,20 +1069,20 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "pulldown-cmark" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0530d13d87d1f549b66a3e8d0c688952abe5994e204ed62615baaf25dc029c" +checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.6.0", "getopts", "memchr", "pulldown-cmark-escape", @@ -1116,24 +1091,24 @@ dependencies = [ [[package]] name = "pulldown-cmark-escape" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d8f9aa0e3cbcfaf8bf00300004ee3b72f74770f9cbac93f6928771f613276b" +checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3" [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -1141,39 +1116,28 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.9.3" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -1183,9 +1147,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -1194,15 +1158,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64", "bytes", @@ -1222,9 +1186,12 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", + "system-configuration", "tokio", "tokio-native-tls", "tower-service", @@ -1237,28 +1204,37 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "0.38.7" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.48.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64", ] [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -1271,11 +1247,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -1286,11 +1262,11 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.9.2" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -1299,9 +1275,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" dependencies = [ "core-foundation-sys", "libc", @@ -1309,18 +1285,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.198" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.198" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -1329,11 +1305,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -1350,6 +1327,12 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "siphasher" version = "1.0.1" @@ -1358,9 +1341,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -1373,22 +1356,12 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.4.9" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "winapi", -] - -[[package]] -name = "socket2" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" -dependencies = [ - "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1399,33 +1372,60 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.60" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" -version = "3.7.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.3.5", + "once_cell", "rustix", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -1448,18 +1448,18 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", @@ -1478,9 +1478,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -1493,26 +1493,25 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.30.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3ce25f50619af8b0aec2eb23deebe84249e19e2ddd393a6e16e3300a6dadfd" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", - "socket2 0.5.3", + "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", @@ -1531,55 +1530,53 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typst-syntax" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "367d86bf18f0363146bea1ea76fad19b54458695fdfad5e74ead3ede574b75fe" +checksum = "e3db69f2f41613b1ff6edbec44fd7dc524137f099ee36c46f560cedeaadb40c4" dependencies = [ "comemo", "ecow", @@ -1603,15 +1600,15 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-math-class" @@ -1621,30 +1618,30 @@ checksum = "7d246cf599d5fae3c8d56e04b20eb519adb89a8af8d0b0fbcded369aa3647d65" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-script" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8d71f5726e5f285a935e9fe8edfd53f0491eb6e9a5774097fdabee7cd8c9cd" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unscanny" @@ -1654,9 +1651,9 @@ checksum = "e9df2af067a7953e9c3831320f35c1cc0600c30d44d9f7a12b01db1cd88d6b47" [[package]] name = "url" -version = "2.4.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -1665,9 +1662,9 @@ dependencies = [ [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "vcpkg" @@ -1677,9 +1674,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wait-timeout" @@ -1692,9 +1689,9 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.3.3" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -1717,19 +1714,20 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", @@ -1742,9 +1740,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -1754,9 +1752,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1764,9 +1762,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", @@ -1777,15 +1775,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -1809,11 +1807,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -1828,7 +1826,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.1", + "windows-targets 0.48.5", ] [[package]] @@ -1837,137 +1835,147 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index cd08d41..9bd94ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ required-features = ["cli"] [dependencies] annotate-snippets = {version = "^0.9.1", optional = true} -clap = {version = "^4.5.4", features = ["cargo", "derive", "env", "wrap_help"], optional = true} +clap = {version = "^4.5.18", features = ["cargo", "derive", "env", "wrap_help"], optional = true} clap_complete = {version = "^4.5.2", optional = true} is-terminal = {version = "0.4.3", optional = true} pulldown-cmark = {version = "0.10.2", optional = true} diff --git a/src/api/check.rs b/src/api/check.rs index 4b8c407..9bce829 100644 --- a/src/api/check.rs +++ b/src/api/check.rs @@ -597,7 +597,7 @@ impl Request { } /// Return a copy of the text within the request. - /// Call [`check::request::try_get_text`] but panic on error. + /// Call [`Request::try_get_text`] but panic on error. /// /// # Panics /// @@ -628,7 +628,7 @@ impl Request { /// Split this request into multiple, using [`split_len`] function to split /// text. - /// Call [`check::request::try_split`] but panic on error. + /// Call [`Request::try_split`] but panic on error. /// /// # Panics /// @@ -701,7 +701,7 @@ pub struct CheckCommand { /// Optional filenames from which input is read. #[arg(conflicts_with_all(["text", "data"]), value_parser = parse_filename)] pub filenames: Vec, - /// Inner [`check::request`]. + /// Inner [`Request`]. #[command(flatten, next_help_heading = "Request options")] pub request: Request, } diff --git a/src/check.rs b/src/check.rs deleted file mode 100644 index f320364..0000000 --- a/src/check.rs +++ /dev/null @@ -1,1310 +0,0 @@ -//! Structures for `check` requests and responses. - -use std::collections::HashMap; -#[cfg(feature = "cli")] -use std::path::PathBuf; - -#[cfg(feature = "annotate")] -use annotate_snippets::{ - display_list::{DisplayList, FormatOptions}, - snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}, -}; -#[cfg(feature = "cli")] -use clap::{Args, Parser, ValueEnum}; -use serde::{Deserialize, Serialize, Serializer}; -use serde_json::Value; - -use super::error::{Error, Result}; - -/// Requests - -/// Parse `v` is valid language code. -/// -/// A valid language code is usually -/// - a two character string matching pattern `[a-z]{2} -/// - a five character string matching pattern `[a-z]{2}-[A-Z]{2} -/// - or some more complex ascii string (see below) -/// -/// Language code is case-insensitive. -/// -/// Therefore, a valid language code must match the following: -/// -/// - `[a-zA-Z]{2,3}(-[a-zA-Z]{2}(-[a-zA-Z]+)*)?` -/// -/// or -/// -/// - "auto" -/// -/// > Note: a valid language code does not mean that it exists. -/// -/// # Examples -/// -/// ``` -/// # use languagetool_rust::api::check::parse_language_code; -/// assert!(parse_language_code("en").is_ok()); -/// -/// assert!(parse_language_code("en-US").is_ok()); -/// -/// assert!(parse_language_code("en-us").is_ok()); -/// -/// assert!(parse_language_code("ca-ES-valencia").is_ok()); -/// -/// assert!(parse_language_code("abcd").is_err()); -/// -/// assert!(parse_language_code("en_US").is_err()); -/// -/// assert!(parse_language_code("fr-french").is_err()); -/// -/// assert!(parse_language_code("some random text").is_err()); -/// ``` -#[cfg(feature = "cli")] -pub fn parse_language_code(v: &str) -> Result { - #[inline] - fn is_match(v: &str) -> bool { - let mut splits = v.split('-'); - - match splits.next() { - Some(s) - if (s.len() == 2 || s.len() == 3) && s.chars().all(|c| c.is_ascii_alphabetic()) => { - }, - _ => return false, - } - - match splits.next() { - Some(s) if s.len() != 2 || s.chars().any(|c| !c.is_ascii_alphabetic()) => return false, - Some(_) => (), - None => return true, - } - for s in splits { - if !s.chars().all(|c| c.is_ascii_alphabetic()) { - return false; - } - } - true - } - - if v == "auto" || is_match(v) { - Ok(v.to_string()) - } else { - Err(Error::InvalidValue( - "The value should be `\"auto\"` or match regex pattern: \ - ^[a-zA-Z]{2,3}(-[a-zA-Z]{2}(-[a-zA-Z]+)*)?$" - .to_string(), - )) - } -} - -/// Utility function to serialize a optional vector a strings -/// into a comma separated list of strings. -/// -/// This is required by reqwest's RequestBuilder, otherwise it -/// will not work. -pub(crate) fn serialize_option_vec_string( - v: &Option>, - serializer: S, -) -> std::result::Result -where - S: Serializer, -{ - match v { - Some(v) if v.len() == 1 => serializer.serialize_str(&v[0]), - Some(v) if v.len() > 1 => { - let size = v.iter().map(|s| s.len()).sum::() + v.len() - 1; - let mut string = String::with_capacity(size); - - string.push_str(&v[0]); - - for s in &v[1..] { - string.push(','); - string.push_str(s); - } - - serializer.serialize_str(string.as_ref()) - }, - _ => serializer.serialize_none(), - } -} - -#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, Hash)] -#[non_exhaustive] -#[serde(rename_all = "camelCase")] -/// A portion of text to be checked. -pub struct DataAnnotation { - /// If set, the markup will be interpreted as this. - #[serde(skip_serializing_if = "Option::is_none")] - pub interpret_as: Option, - #[serde(skip_serializing_if = "Option::is_none")] - /// Text that should be treated as markup. - pub markup: Option, - #[serde(skip_serializing_if = "Option::is_none")] - /// Text that should be treated as normal text. - pub text: Option, -} - -impl Default for DataAnnotation { - fn default() -> Self { - Self { - interpret_as: None, - markup: None, - text: Some(String::new()), - } - } -} - -impl DataAnnotation { - /// Instantiate a new `DataAnnotation` with text only. - #[inline] - #[must_use] - pub fn new_text(text: String) -> Self { - Self { - interpret_as: None, - markup: None, - text: Some(text), - } - } - - /// Instantiate a new `DataAnnotation` with markup only. - #[inline] - #[must_use] - pub fn new_markup(markup: String) -> Self { - Self { - interpret_as: None, - markup: Some(markup), - text: None, - } - } - - /// Instantiate a new `DataAnnotation` with markup and its interpretation. - #[inline] - #[must_use] - pub fn new_interpreted_markup(markup: String, interpret_as: String) -> Self { - Self { - interpret_as: Some(interpret_as), - markup: Some(markup), - text: None, - } - } -} - -#[cfg(test)] -mod data_annotation_tests { - - use crate::check::DataAnnotation; - - #[test] - fn test_text() { - let da = DataAnnotation::new_text("Hello".to_string()); - - assert_eq!(da.text.unwrap(), "Hello".to_string()); - assert!(da.markup.is_none()); - assert!(da.interpret_as.is_none()); - } - - #[test] - fn test_markup() { - let da = DataAnnotation::new_markup("Hello".to_string()); - - assert!(da.text.is_none()); - assert_eq!(da.markup.unwrap(), "Hello".to_string()); - assert!(da.interpret_as.is_none()); - } - - #[test] - fn test_interpreted_markup() { - let da = - DataAnnotation::new_interpreted_markup("Hello".to_string(), "Hello".to_string()); - - assert!(da.text.is_none()); - assert_eq!(da.markup.unwrap(), "Hello".to_string()); - assert_eq!(da.interpret_as.unwrap(), "Hello".to_string()); - } -} - -/// Alternative text to be checked. -#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Hash)] -#[non_exhaustive] -pub struct Data { - /// Vector of markup text, see [`DataAnnotation`]. - pub annotation: Vec, -} - -impl> FromIterator for Data { - fn from_iter>(iter: I) -> Self { - let annotation = iter.into_iter().map(std::convert::Into::into).collect(); - Data { annotation } - } -} - -impl Serialize for Data { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - let mut map = std::collections::HashMap::new(); - map.insert("annotation", &self.annotation); - - serializer.serialize_str(&serde_json::to_string(&map).unwrap()) - } -} - -#[cfg(feature = "cli")] -impl std::str::FromStr for Data { - type Err = Error; - - fn from_str(s: &str) -> Result { - let v: Self = serde_json::from_str(s)?; - Ok(v) - } -} - -/// Possible levels for additional rules. -/// -/// Currently, `Level::Picky` adds additional rules -/// with respect to `Level::Default`. -#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Hash)] -#[cfg_attr(feature = "cli", derive(ValueEnum))] -#[serde(rename_all = "lowercase")] -#[non_exhaustive] -pub enum Level { - /// Default level. - #[default] - Default, - /// Picky level. - Picky, -} - -impl Level { - /// Return `true` if current level is the default one. - /// - /// # Examples - /// - /// ``` - /// # use languagetool_rust::api::check::Level; - /// - /// let level: Level = Default::default(); - /// - /// assert!(level.is_default()); - /// ``` - #[must_use] - pub fn is_default(&self) -> bool { - *self == Level::default() - } -} - -/// Split a string into as few fragments as possible, where each fragment -/// contains (if possible) a maximum of `n` characters. Pattern str `pat` is -/// used for splitting. -/// -/// # Examples -/// -/// ``` -/// # use languagetool_rust::api::check::split_len; -/// let s = "I have so many friends. -/// They are very funny. -/// I think I am very lucky to have them. -/// One day, I will write them a poem. -/// But, in the meantime, I write code. -/// "; -/// -/// let split = split_len(&s, 40, "\n"); -/// -/// assert_eq!(split.join(""), s); -/// assert_eq!( -/// split, -/// vec![ -/// "I have so many friends.\n", -/// "They are very funny.\n", -/// "I think I am very lucky to have them.\n", -/// "One day, I will write them a poem.\n", -/// "But, in the meantime, I write code.\n" -/// ] -/// ); -/// -/// let split = split_len(&s, 80, "\n"); -/// -/// assert_eq!( -/// split, -/// vec![ -/// "I have so many friends.\nThey are very funny.\n", -/// "I think I am very lucky to have them.\nOne day, I will write them a poem.\n", -/// "But, in the meantime, I write code.\n" -/// ] -/// ); -/// -/// let s = "I have so many friends. -/// They are very funny. -/// I think I am very lucky to have them. -/// -/// One day, I will write them a poem. -/// But, in the meantime, I write code. -/// "; -/// -/// let split = split_len(&s, 80, "\n\n"); -/// -/// println!("{:?}", split); -/// -/// assert_eq!( -/// split, -/// vec![ -/// "I have so many friends.\nThey are very funny.\nI think I am very lucky to have \ -/// them.\n\n", -/// "One day, I will write them a poem.\nBut, in the meantime, I write code.\n" -/// ] -/// ); -/// ``` -#[must_use] -pub fn split_len<'source>(s: &'source str, n: usize, pat: &str) -> Vec<&'source str> { - let mut vec: Vec<&'source str> = Vec::with_capacity(s.len() / n); - let mut splits = s.split_inclusive(pat); - - let mut start = 0; - let mut i = 0; - - if let Some(split) = splits.next() { - vec.push(split); - } else { - return Vec::new(); - } - - for split in splits { - let new_len = vec[i].len() + split.len(); - if new_len < n { - vec[i] = &s[start..start + new_len]; - } else { - vec.push(split); - start += vec[i].len(); - i += 1; - } - } - - vec -} - -/// LanguageTool POST check request. -/// -/// The main feature - check a text with LanguageTool for possible style and -/// grammar issues. -/// -/// The structure below tries to follow as closely as possible the JSON API -/// described [here](https://languagetool.org/http-api/swagger-ui/#!/default/post_check). -#[cfg_attr(feature = "cli", derive(Args))] -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Hash)] -#[serde(rename_all = "camelCase")] -#[non_exhaustive] -pub struct Request { - /// The text to be checked. This or 'data' is required. - #[cfg_attr( - feature = "cli", - clap(short = 't', long, conflicts_with = "data", allow_hyphen_values(true)) - )] - #[serde(skip_serializing_if = "Option::is_none")] - pub text: Option, - /// The text to be checked, given as a JSON document that specifies what's - /// text and what's markup. This or 'text' is required. - /// - /// Markup will be ignored when looking for errors. Example text: - /// ```html - /// A test - /// ``` - /// JSON for the example text: - /// ```json - /// {"annotation":[ - /// {"text": "A "}, - /// {"markup": ""}, - /// {"text": "test"}, - /// {"markup": ""} - /// ]} - /// ``` - /// If you have markup that should be interpreted as whitespace, like `

` - /// in HTML, you can have it interpreted like this: - /// - /// ```json - /// {"markup": "

", "interpretAs": "\n\n"} - /// ``` - /// The 'data' feature is not limited to HTML or XML, it can be used for any - /// kind of markup. Entities will need to be expanded in this input. - #[cfg_attr(feature = "cli", clap(short = 'd', long, conflicts_with = "text"))] - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option, - /// A language code like `en-US`, `de-DE`, `fr`, or `auto` to guess the - /// language automatically (see `preferredVariants` below). - /// - /// For languages with variants (English, German, Portuguese) spell checking - /// will only be activated when you specify the variant, e.g. `en-GB` - /// instead of just `en`. - #[cfg_attr( - all(feature = "cli", feature = "cli", feature = "cli"), - clap( - short = 'l', - long, - default_value = "auto", - value_parser = parse_language_code - ) - )] - pub language: String, - /// Set to get Premium API access: Your username/email as used to log in at - /// languagetool.org. - #[cfg_attr( - feature = "cli", - clap(short = 'u', long, requires = "api_key", env = "LANGUAGETOOL_USERNAME") - )] - #[serde(skip_serializing_if = "Option::is_none")] - pub username: Option, - /// Set to get Premium API access: [your API - /// key](https://languagetool.org/editor/settings/api). - #[cfg_attr( - feature = "cli", - clap(short = 'k', long, requires = "username", env = "LANGUAGETOOL_API_KEY") - )] - #[serde(skip_serializing_if = "Option::is_none")] - pub api_key: Option, - /// Comma-separated list of dictionaries to include words from; uses special - /// default dictionary if this is unset. - #[cfg_attr(feature = "cli", clap(long))] - #[serde(serialize_with = "serialize_option_vec_string")] - pub dicts: Option>, - /// A language code of the user's native language, enabling false friends - /// checks for some language pairs. - #[cfg_attr(feature = "cli", clap(long))] - #[serde(skip_serializing_if = "Option::is_none")] - pub mother_tongue: Option, - /// Comma-separated list of preferred language variants. - /// - /// The language detector used with `language=auto` can detect e.g. English, - /// but it cannot decide whether British English or American English is - /// used. Thus this parameter can be used to specify the preferred variants - /// like `en-GB` and `de-AT`. Only available with `language=auto`. You - /// should set variants for at least German and English, as otherwise the - /// spell checking will not work for those, as no spelling dictionary can be - /// selected for just `en` or `de`. - #[cfg_attr(feature = "cli", clap(long, conflicts_with = "language"))] - #[serde(serialize_with = "serialize_option_vec_string")] - pub preferred_variants: Option>, - /// IDs of rules to be enabled, comma-separated. - #[cfg_attr(feature = "cli", clap(long))] - #[serde(serialize_with = "serialize_option_vec_string")] - pub enabled_rules: Option>, - /// IDs of rules to be disabled, comma-separated. - #[cfg_attr(feature = "cli", clap(long))] - #[serde(serialize_with = "serialize_option_vec_string")] - pub disabled_rules: Option>, - /// IDs of categories to be enabled, comma-separated. - #[cfg_attr(feature = "cli", clap(long))] - #[serde(serialize_with = "serialize_option_vec_string")] - pub enabled_categories: Option>, - /// IDs of categories to be disabled, comma-separated. - #[cfg_attr(feature = "cli", clap(long))] - #[serde(serialize_with = "serialize_option_vec_string")] - pub disabled_categories: Option>, - /// If true, only the rules and categories whose IDs are specified with - /// `enabledRules` or `enabledCategories` are enabled. - #[cfg_attr(feature = "cli", clap(long))] - #[serde(skip_serializing_if = "is_false")] - pub enabled_only: bool, - /// If set to `picky`, additional rules will be activated, i.e. rules that - /// you might only find useful when checking formal text. - #[cfg_attr( - feature = "cli", - clap(long, default_value = "default", ignore_case = true, value_enum) - )] - #[serde(skip_serializing_if = "Level::is_default")] - pub level: Level, -} - -impl Default for Request { - #[inline] - fn default() -> Request { - Request { - text: Default::default(), - data: Default::default(), - language: "auto".to_string(), - username: Default::default(), - api_key: Default::default(), - dicts: Default::default(), - mother_tongue: Default::default(), - preferred_variants: Default::default(), - enabled_rules: Default::default(), - disabled_rules: Default::default(), - enabled_categories: Default::default(), - disabled_categories: Default::default(), - enabled_only: Default::default(), - level: Default::default(), - } - } -} - -#[inline] -fn is_false(b: &bool) -> bool { - !(*b) -} - -impl Request { - /// Set the text to be checked and remove potential data field. - #[must_use] - pub fn with_text(mut self, text: String) -> Self { - self.text = Some(text); - self.data = None; - self - } - - /// Set the data to be checked and remove potential text field. - #[must_use] - pub fn with_data(mut self, data: Data) -> Self { - self.data = Some(data); - self.text = None; - self - } - - /// Set the data (obtained from string) to be checked and remove potential - /// text field - pub fn with_data_str(self, data: &str) -> serde_json::Result { - Ok(self.with_data(serde_json::from_str(data)?)) - } - - /// Set the language of the text / data. - #[must_use] - pub fn with_language(mut self, language: String) -> Self { - self.language = language; - self - } - - /// Return a copy of the text within the request. - /// - /// # Errors - /// - /// If both `self.text` and `self.data` are [`None`]. - /// If any data annotation does not contain text or markup. - pub fn try_get_text(&self) -> Result { - if let Some(ref text) = self.text { - Ok(text.clone()) - } else if let Some(ref data) = self.data { - let mut text = String::new(); - for da in data.annotation.iter() { - if let Some(ref t) = da.text { - text.push_str(t.as_str()); - } else if let Some(ref t) = da.markup { - text.push_str(t.as_str()); - } else { - return Err(Error::InvalidDataAnnotation( - "missing either text or markup field in {da:?}".to_string(), - )); - } - } - Ok(text) - } else { - Err(Error::InvalidRequest( - "missing either text or data field".to_string(), - )) - } - } - - /// Return a copy of the text within the request. - /// Call [`Request::try_get_text`] but panic on error. - /// - /// # Panics - /// - /// If both `self.text` and `self.data` are [`None`]. - /// If any data annotation does not contain text or markup. - #[must_use] - pub fn get_text(&self) -> String { - self.try_get_text().unwrap() - } - - /// Split this request into multiple, using [`split_len`] function to split - /// text. - /// - /// # Errors - /// - /// If `self.text` is none. - pub fn try_split(&self, n: usize, pat: &str) -> Result> { - let text = self - .text - .as_ref() - .ok_or(Error::InvalidRequest("missing text field".to_string()))?; - - Ok(split_len(text.as_str(), n, pat) - .iter() - .map(|text_fragment| self.clone().with_text(text_fragment.to_string())) - .collect()) - } - - /// Split this request into multiple, using [`split_len`] function to split - /// text. - /// Call [`Request::try_split`] but panic on error. - /// - /// # Panics - /// - /// If `self.text` is none. - #[must_use] - pub fn split(&self, n: usize, pat: &str) -> Vec { - self.try_split(n, pat).unwrap() - } -} - -/// Parse a string slice into a [`PathBuf`], and error if the file does not -/// exist. -#[cfg(feature = "cli")] -fn parse_filename(s: &str) -> Result { - let path_buf: PathBuf = s.parse().unwrap(); - - if path_buf.is_file() { - Ok(path_buf) - } else { - Err(Error::InvalidFilename(s.to_string())) - } -} - -/// Supported file types. -#[cfg(feature = "cli")] -#[derive(Clone, Debug, Default, ValueEnum)] -#[non_exhaustive] -pub enum FileTypeOptions { - /// Auto. - #[default] - Auto, - /// Text. - Text, - /// Markdown. - Markdown, - /// Typst. - Typst, -} - -pub enum FileType {} - -/// Check text using LanguageTool server. -/// -/// The input can be one of the following: -/// -/// - raw text, if `--text TEXT` is provided; -/// - annotated data, if `--data TEXT` is provided; -/// - raw text, if `-- [FILE]...` are provided. Note that some file types will -/// use a -/// - raw text, through stdin, if nothing is provided. -#[cfg(feature = "cli")] -#[derive(Debug, Parser)] -pub struct CheckCommand { - /// If present, raw JSON output will be printed instead of annotated text. - /// This has no effect if `--data` is used, because it is never - /// annotated. - #[cfg(feature = "cli")] - #[clap(short = 'r', long)] - pub raw: bool, - /// Sets the maximum number of characters before splitting. - #[clap(long, default_value_t = 1500)] - pub max_length: usize, - /// If text is too long, will split on this pattern. - #[clap(long, default_value = "\n\n")] - pub split_pattern: String, - /// Max. number of suggestions kept. If negative, all suggestions are kept. - #[clap(long, default_value_t = 5, allow_negative_numbers = true)] - pub max_suggestions: isize, - /// Specify the files type to use the correct parser. - /// - /// If set to auto, the type is guessed from the filename extension. - #[clap(long, default_value = "default", ignore_case = true, value_enum)] - pub r#type: FileType, - /// Optional filenames from which input is read. - #[arg(conflicts_with_all(["text", "data"]), value_parser = parse_filename)] - pub filenames: Vec, - /// Inner [`Request`]. - #[command(flatten, next_help_heading = "Request options")] - pub request: Request, -} - -#[cfg(test)] -mod request_tests { - - use crate::Request; - - #[test] - fn test_with_text() { - let req = Request::default().with_text("hello".to_string()); - - assert_eq!(req.text.unwrap(), "hello".to_string()); - assert!(req.data.is_none()); - } - - #[test] - fn test_with_data() { - let req = Request::default().with_text("hello".to_string()); - - assert_eq!(req.text.unwrap(), "hello".to_string()); - assert!(req.data.is_none()); - } -} - -/// Responses - -/// Detected language from check request. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -#[non_exhaustive] -pub struct DetectedLanguage { - /// Language code, e.g., `"sk-SK"` for Slovak. - pub code: String, - /// Language name, e.g., `"Slovak"`. - pub name: String, - /// Undocumented fields. - /// - /// Examples are: - /// - /// - 'confidence', the confidence level, from 0 to 1; - /// - 'source', the source file for the language detection. - #[cfg(feature = "undoc")] - #[serde(flatten)] - pub undocumented: HashMap, -} - -/// Language information in check response. -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[non_exhaustive] -pub struct LanguageResponse { - /// Language code, e.g., `"sk-SK"` for Slovak. - pub code: String, - /// Detected language from provided request. - pub detected_language: DetectedLanguage, - /// Language name, e.g., `"Slovak"`. - pub name: String, -} - -/// Match context in check response. -#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] -#[non_exhaustive] -pub struct Context { - /// Length of the match. - pub length: usize, - /// Char index at which the match starts. - pub offset: usize, - /// Contextual text around the match. - pub text: String, -} - -/// More context, post-processed in check response. -#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] -#[non_exhaustive] -pub struct MoreContext { - /// Line number where match occurred. - pub line_number: usize, - /// Char index at which the match starts on the current line. - pub line_offset: usize, -} - -/// Possible replacement for a given match in check response. -#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] -#[non_exhaustive] -pub struct Replacement { - /// Possible replacement value. - pub value: String, -} - -impl From for Replacement { - fn from(value: String) -> Self { - Self { value } - } -} - -impl From<&str> for Replacement { - fn from(value: &str) -> Self { - value.to_string().into() - } -} - -/// A rule category. -#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] -#[non_exhaustive] -pub struct Category { - /// Category ID. - pub id: String, - /// Category name. - pub name: String, -} - -/// A possible url of a rule in a check response. -#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] -#[non_exhaustive] -pub struct Url { - /// Url value. - pub value: String, -} - -/// The rule that was not satisfied in a given match. -#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[non_exhaustive] -pub struct Rule { - /// Rule category. - pub category: Category, - /// Rule description. - pub description: String, - /// Rule ID. - pub id: String, - /// Issue type. - pub issue_type: String, - /// Rule source file. - /// Rule sub ID. - pub sub_id: Option, - /// Rule list of URLs. - pub urls: Option>, - /// Undocumented fields. - /// - /// Examples are: - /// - /// - 'is_premium', indicate if the rule is from the premium API; - /// - 'source_file', the source file of the rule. - #[cfg(feature = "undoc")] - #[serde(flatten)] - pub undocumented: HashMap, -} - -/// Type of given match. -#[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[non_exhaustive] -pub struct Type { - /// Type name. - pub type_name: String, -} - -/// Grammatical error match. -#[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[non_exhaustive] -pub struct Match { - /// Match context. - pub context: Context, - /// Match length. - pub length: usize, - /// Error message. - pub message: String, - /// More context to match, post-processed using original text. - #[serde(skip_serializing_if = "Option::is_none")] - pub more_context: Option, - /// Char index at which the match start. - pub offset: usize, - /// List of possible replacements (if applies). - pub replacements: Vec, - /// Match rule that was not satisfied. - pub rule: Rule, - /// Sentence in which the error was found. - pub sentence: String, - /// Short message about the error. - pub short_message: String, - /// Undocumented fields. - /// - /// Examples are: - /// - /// - 'type', the match type; - /// - 'context_for_sure_match', unknown; - /// - 'ignore_for_incomplete_sentence', unknown; - #[cfg(feature = "undoc")] - #[serde(flatten)] - pub undocumented: HashMap, -} - -/// LanguageTool software details. -#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[non_exhaustive] -pub struct Software { - /// LanguageTool API version. - pub api_version: usize, - /// Some information about build date. - pub build_date: String, - /// Name (should be `"LanguageTool"`). - pub name: String, - /// Tell whether the server uses premium API or not. - pub premium: bool, - /// Sentence that indicates if using premium API would find more errors. - #[cfg(feature = "unstable")] - pub premium_hint: Option, - /// Unknown: please fill a [PR](https://github.com/jeertmans/languagetool-rust/pulls) of your - /// know that this attribute is used for. - pub status: String, - /// LanguageTool version. - pub version: String, -} - -/// Warnings about check response. -#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[non_exhaustive] -pub struct Warnings { - /// Indicate if results are incomplete. - pub incomplete_results: bool, -} - -/// LanguageTool POST check response. -#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[non_exhaustive] -pub struct Response { - /// Language information. - pub language: LanguageResponse, - /// List of error matches. - pub matches: Vec, - /// Ranges ([start, end]) of sentences. - #[cfg(feature = "unstable")] - pub sentence_ranges: Option>, - /// LanguageTool software information. - pub software: Software, - /// Possible warnings. - #[cfg(feature = "unstable")] - pub warnings: Option, -} - -impl Response { - /// Return an iterator over matches. - pub fn iter_matches(&self) -> std::slice::Iter<'_, Match> { - self.matches.iter() - } - - /// Return an iterator over mutable matches. - pub fn iter_matches_mut(&mut self) -> std::slice::IterMut<'_, Match> { - self.matches.iter_mut() - } - - /// Creates an annotated string from current response. - #[cfg(feature = "annotate")] - #[must_use] - pub fn annotate(&self, text: &str, origin: Option<&str>, color: bool) -> String { - if self.matches.is_empty() { - return "No errors were found in provided text".to_string(); - } - let replacements: Vec<_> = self - .matches - .iter() - .map(|m| { - m.replacements.iter().fold(String::new(), |mut acc, r| { - if !acc.is_empty() { - acc.push_str(", "); - } - acc.push_str(&r.value); - acc - }) - }) - .collect(); - - let snippets = self - .matches - .iter() - .zip(replacements.iter()) - .map(|(m, r)| Snippet { - title: Some(Annotation { - label: Some(&m.message), - id: Some(&m.rule.id), - annotation_type: AnnotationType::Error, - }), - footer: vec![], - slices: vec![Slice { - source: &m.context.text, - line_start: 1 + text.chars().take(m.offset).filter(|c| *c == '\n').count(), - origin, - fold: true, - annotations: vec![ - SourceAnnotation { - label: &m.rule.description, - annotation_type: AnnotationType::Error, - range: (m.context.offset, m.context.offset + m.context.length), - }, - SourceAnnotation { - label: r, - annotation_type: AnnotationType::Help, - range: (m.context.offset, m.context.offset + m.context.length), - }, - ], - }], - opt: FormatOptions { - color, - ..Default::default() - }, - }); - - let mut annotation = String::new(); - - for snippet in snippets { - if !annotation.is_empty() { - annotation.push('\n'); - } - annotation.push_str(&DisplayList::from(snippet).to_string()); - } - annotation - } -} - -/// Check response with additional context. -/// -/// This structure exists to keep a link between a check response -/// and the original text that was checked. -#[derive(Debug, Clone, PartialEq)] -pub struct ResponseWithContext { - /// Original text that was checked by LT. - pub text: String, - /// Check response. - pub response: Response, - /// Text's length. - pub text_length: usize, -} - -impl ResponseWithContext { - /// Bind a check response with its original text. - #[must_use] - pub fn new(text: String, response: Response) -> Self { - let text_length = text.chars().count(); - Self { - text, - response, - text_length, - } - } - - /// Return an iterator over matches. - pub fn iter_matches(&self) -> std::slice::Iter<'_, Match> { - self.response.iter_matches() - } - - /// Return an iterator over mutable matches. - pub fn iter_matches_mut(&mut self) -> std::slice::IterMut<'_, Match> { - self.response.iter_matches_mut() - } - - /// Return an iterator over matches and corresponding line number and line - /// offset. - #[must_use] - pub fn iter_match_positions(&self) -> MatchPositions<'_, std::slice::Iter<'_, Match>> { - self.into() - } - - /// Append a check response to the current while - /// adjusting the matches' offsets. - /// - /// This is especially useful when a text was split in multiple requests. - #[must_use] - pub fn append(mut self, mut other: Self) -> Self { - let offset = self.text_length; - for m in other.iter_matches_mut() { - m.offset += offset; - } - - #[cfg(feature = "unstable")] - if let Some(ref mut sr_other) = other.response.sentence_ranges { - match self.response.sentence_ranges { - Some(ref mut sr_self) => { - sr_self.append(sr_other); - }, - None => { - std::mem::swap( - &mut self.response.sentence_ranges, - &mut other.response.sentence_ranges, - ); - }, - } - } - - self.response.matches.append(&mut other.response.matches); - self.text.push_str(other.text.as_str()); - self.text_length += other.text_length; - self - } -} - -impl From for Response { - #[allow(clippy::needless_borrow)] - fn from(mut resp: ResponseWithContext) -> Self { - let iter: MatchPositions<'_, std::slice::IterMut<'_, Match>> = (&mut resp).into(); - - for (line_number, line_offset, m) in iter { - m.more_context = Some(MoreContext { - line_number, - line_offset, - }); - } - resp.response - } -} - -/// Iterator over matches and their corresponding line number and line offset. -#[derive(Clone, Debug)] -pub struct MatchPositions<'source, T> { - text_chars: std::str::Chars<'source>, - matches: T, - line_number: usize, - line_offset: usize, - offset: usize, -} - -impl<'source> From<&'source ResponseWithContext> - for MatchPositions<'source, std::slice::Iter<'source, Match>> -{ - fn from(response: &'source ResponseWithContext) -> Self { - MatchPositions { - text_chars: response.text.chars(), - matches: response.iter_matches(), - line_number: 1, - line_offset: 0, - offset: 0, - } - } -} - -impl<'source> From<&'source mut ResponseWithContext> - for MatchPositions<'source, std::slice::IterMut<'source, Match>> -{ - fn from(response: &'source mut ResponseWithContext) -> Self { - MatchPositions { - text_chars: response.text.chars(), - matches: response.response.iter_matches_mut(), - line_number: 1, - line_offset: 0, - offset: 0, - } - } -} - -impl<'source, T> MatchPositions<'source, T> { - /// Set the line number to a give value. - /// - /// By default, the first line number is 1. - pub fn set_line_number(mut self, line_number: usize) -> Self { - self.line_number = line_number; - self - } - - fn update_line_number_and_offset(&mut self, m: &Match) { - let n = m.offset - self.offset; - for _ in 0..n { - match self.text_chars.next() { - Some('\n') => { - self.line_number += 1; - self.line_offset = 0; - }, - None => { - panic!( - "text is shorter than expected, are you sure this text was the one used \ - for the check request?" - ) - }, - _ => self.line_offset += 1, - } - } - self.offset = m.offset; - } -} - -impl<'source> Iterator for MatchPositions<'source, std::slice::Iter<'source, Match>> { - type Item = (usize, usize, &'source Match); - - fn next(&mut self) -> Option { - if let Some(m) = self.matches.next() { - self.update_line_number_and_offset(m); - Some((self.line_number, self.line_offset, m)) - } else { - None - } - } -} - -impl<'source> Iterator for MatchPositions<'source, std::slice::IterMut<'source, Match>> { - type Item = (usize, usize, &'source mut Match); - - fn next(&mut self) -> Option { - if let Some(m) = self.matches.next() { - self.update_line_number_and_offset(m); - Some((self.line_number, self.line_offset, m)) - } else { - None - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[derive(Debug)] - enum Token<'source> { - Text(&'source str), - Skip(&'source str), - } - - #[derive(Debug, Clone)] - struct ParseTokenError; - - impl<'source> From<&'source str> for Token<'source> { - fn from(s: &'source str) -> Self { - if s.chars().all(|c| c.is_ascii_alphabetic()) { - Token::Text(s) - } else { - Token::Skip(s) - } - } - } - - impl<'source> From> for DataAnnotation { - fn from(token: Token<'source>) -> Self { - match token { - Token::Text(s) => DataAnnotation::new_text(s.to_string()), - Token::Skip(s) => DataAnnotation::new_markup(s.to_string()), - } - } - } - - #[test] - fn test_data_annotation() { - let words: Vec<&str> = "My name is Q34XY".split(' ').collect(); - let data: Data = words.iter().map(|w| Token::from(*w)).collect(); - - let expected_data = Data { - annotation: vec![ - DataAnnotation::new_text("My".to_string()), - DataAnnotation::new_text("name".to_string()), - DataAnnotation::new_text("is".to_string()), - DataAnnotation::new_markup("Q34XY".to_string()), - ], - }; - - assert_eq!(data, expected_data); - } - - #[test] - fn test_serialize_option_vec_string() { - use serde::Serialize; - - #[derive(Serialize)] - struct Foo { - #[serde(serialize_with = "serialize_option_vec_string")] - values: Option>, - } - - impl Foo { - fn new(values: I) -> Self - where - I: IntoIterator, - T: ToString, - { - Self { - values: Some(values.into_iter().map(|v| v.to_string()).collect()), - } - } - fn none() -> Self { - Self { values: None } - } - } - - let got = serde_json::to_string(&Foo::new(vec!["en-US", "de-DE"])).unwrap(); - assert_eq!(got, r#"{"values":"en-US,de-DE"}"#); - - let got = serde_json::to_string(&Foo::new(vec!["en-US"])).unwrap(); - assert_eq!(got, r#"{"values":"en-US"}"#); - - let got = serde_json::to_string(&Foo::new(Vec::::new())).unwrap(); - assert_eq!(got, r#"{"values":null}"#); - - let got = serde_json::to_string(&Foo::none()).unwrap(); - assert_eq!(got, r#"{"values":null}"#); - } -} - -/// Annotate a response by using its request context. -pub fn annotate(response: &Response, request: &Request) -> String {} diff --git a/src/error.rs b/src/error.rs index 9890117..fa56652 100644 --- a/src/error.rs +++ b/src/error.rs @@ -19,7 +19,7 @@ pub enum Error { ExitStatus(String), /// Error specifying an invalid - /// [`DataAnnotation`](`crate::check::DataAnnotation`). + /// [`DataAnnotation`](`crate::api::check::DataAnnotation`). #[error("invalid request: {0}")] InvalidDataAnnotation(String), From 43de21037cfe5066f7a60e7deeeab27e95c5445d Mon Sep 17 00:00:00 2001 From: rolv Date: Sat, 28 Sep 2024 09:24:02 +0100 Subject: [PATCH 08/12] refactor: use crate's result type for the `check` method on `Client` --- src/api/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index c03c4b7..4a8bbf6 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -11,6 +11,8 @@ pub mod languages; pub mod server; pub mod words; +use crate::error::{Error, Result}; + /// A HTTP client for making requests to a LanguageTool server. #[derive(Debug)] pub struct Client { @@ -46,14 +48,16 @@ impl Client { } /// Send a check request to the server and await for the response. - pub async fn check(&self, request: &check::Request) -> reqwest::Result { + pub async fn check(&self, request: &check::Request) -> Result { self.client .post(self.url("/check")) .query(request) .send() - .await? + .await + .map_err(Error::RequestEncode)? .json::() .await + .map_err(Error::ResponseDecode) } /// Send a request for the list of supported languages to the server and From 917e6c8473ba81117ad99b887436f99586c60b69 Mon Sep 17 00:00:00 2001 From: rolv Date: Sat, 28 Sep 2024 10:24:15 +0100 Subject: [PATCH 09/12] refactor: use crate's result type for the `languages` method on `Client` --- src/api/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index 4a8bbf6..87475cf 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -62,12 +62,14 @@ impl Client { /// Send a request for the list of supported languages to the server and /// await for the response. - pub async fn languages(&self) -> reqwest::Result { + pub async fn languages(&self) -> Result { self.client .get(self.url("/languages")) .send() - .await? + .await + .map_err(Error::RequestEncode)? .json::() .await + .map_err(Error::ResponseDecode) } } From c823438b062375e646675901456bc8915560504f Mon Sep 17 00:00:00 2001 From: Rolv Apneseth Date: Sat, 28 Sep 2024 21:42:25 +0100 Subject: [PATCH 10/12] Update src/api/mod.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérome Eertmans --- src/api/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index 87475cf..f768ae1 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -53,11 +53,9 @@ impl Client { .post(self.url("/check")) .query(request) .send() - .await - .map_err(Error::RequestEncode)? + .await? .json::() .await - .map_err(Error::ResponseDecode) } /// Send a request for the list of supported languages to the server and From 7ad54dbd8c54f2112438b23a150e8b03c5616e51 Mon Sep 17 00:00:00 2001 From: Rolv Apneseth Date: Sat, 28 Sep 2024 21:42:32 +0100 Subject: [PATCH 11/12] Update src/api/mod.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérome Eertmans --- src/api/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index f768ae1..d0b09e4 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -64,10 +64,8 @@ impl Client { self.client .get(self.url("/languages")) .send() - .await - .map_err(Error::RequestEncode)? + .await? .json::() .await - .map_err(Error::ResponseDecode) } } From ca1db355899b0a199a2be4f74a576f1c98ce4f9b Mon Sep 17 00:00:00 2001 From: rolv Date: Sat, 28 Sep 2024 22:04:53 +0100 Subject: [PATCH 12/12] fix: convert `reqwest` error --- src/api/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/mod.rs b/src/api/mod.rs index d0b09e4..f6ed976 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -56,6 +56,7 @@ impl Client { .await? .json::() .await + .map_err(Into::into) } /// Send a request for the list of supported languages to the server and @@ -67,5 +68,6 @@ impl Client { .await? .json::() .await + .map_err(Into::into) } }