From f4e2e31d305ad7a8ccc3e8d0abe8e7b62e45029a Mon Sep 17 00:00:00 2001 From: HerringtonDarkholme <2883231+HerringtonDarkholme@users.noreply.github.com> Date: Fri, 9 May 2025 23:00:12 -0400 Subject: [PATCH] feat: use newer tower_lsp crate fix #1975 --- Cargo.lock | 405 +++------------------------------------- clippy.toml | 1 + crates/lsp/Cargo.toml | 4 +- crates/lsp/src/lib.rs | 28 +-- crates/lsp/src/utils.rs | 5 +- 5 files changed, 45 insertions(+), 398 deletions(-) create mode 100644 clippy.toml diff --git a/Cargo.lock b/Cargo.lock index f34d5603..e371431a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -222,11 +222,11 @@ dependencies = [ "ast-grep-config", "ast-grep-core", "ast-grep-language", - "dashmap 6.1.0", + "dashmap", "serde", "serde_json", "tokio", - "tower-lsp", + "tower-lsp-server", ] [[package]] @@ -259,17 +259,6 @@ dependencies = [ "serde", ] -[[package]] -name = "async-trait" -version = "0.1.88" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "atty" version = "0.2.14" @@ -281,17 +270,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "auto_impl" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "autocfg" version = "1.4.0" @@ -631,19 +609,6 @@ dependencies = [ "syn", ] -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - [[package]] name = "dashmap" version = "6.1.0" @@ -685,17 +650,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "doc-comment" version = "0.3.3" @@ -736,7 +690,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -755,12 +709,12 @@ dependencies = [ ] [[package]] -name = "form_urlencoded" -version = "1.2.1" +name = "fluent-uri" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" dependencies = [ - "percent-encoding", + "bitflags 1.3.2", ] [[package]] @@ -938,145 +892,6 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - [[package]] name = "ignore" version = "0.4.23" @@ -1134,7 +949,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ "hermit-abi 0.5.0", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1181,7 +996,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -1190,12 +1005,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" -[[package]] -name = "litemap" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" - [[package]] name = "litrs" version = "0.4.1" @@ -1220,15 +1029,15 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lsp-types" -version = "0.94.1" +version = "0.97.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66bfd44a06ae10647fe3f8214762e9369fd4248df1350924b4ef9e770a85ea1" +checksum = "53353550a17c04ac46c585feb189c2db82154fc84b79c7a66c96c2c644f66071" dependencies = [ "bitflags 1.3.2", + "fluent-uri", "serde", "serde_json", "serde_repr", - "url", ] [[package]] @@ -1407,32 +1216,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pin-project" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1681,7 +1464,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1867,12 +1650,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "streaming-iterator" version = "0.1.9" @@ -1897,15 +1674,10 @@ dependencies = [ ] [[package]] -name = "synstructure" -version = "0.13.1" +name = "sync_wrapper" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" [[package]] name = "target-lexicon" @@ -1923,7 +1695,7 @@ dependencies = [ "getrandom", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1971,16 +1743,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - [[package]] name = "tinytemplate" version = "1.2.1" @@ -2041,14 +1803,14 @@ checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" [[package]] name = "tower" -version = "0.4.13" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "pin-project", "pin-project-lite", + "sync_wrapper", "tower-layer", "tower-service", ] @@ -2060,15 +1822,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] -name = "tower-lsp" -version = "0.20.0" +name = "tower-lsp-server" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4ba052b54a6627628d9b3c34c176e7eda8359b7da9acd497b9f20998d118508" +checksum = "5fade4c658b63d11b623ddfa80821901e943a2923a010ae4a038661de42bd377" dependencies = [ - "async-trait", - "auto_impl", "bytes", - "dashmap 5.5.3", + "dashmap", "futures", "httparse", "lsp-types", @@ -2078,21 +1838,9 @@ dependencies = [ "tokio", "tokio-util", "tower", - "tower-lsp-macros", "tracing", ] -[[package]] -name = "tower-lsp-macros" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tower-service" version = "0.3.3" @@ -2420,30 +2168,6 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - [[package]] name = "utf8parse" version = "0.2.2" @@ -2598,7 +2322,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -2773,18 +2497,6 @@ dependencies = [ "bitflags 2.9.0", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - [[package]] name = "xtask" version = "0.0.0" @@ -2797,70 +2509,3 @@ dependencies = [ "serde_json", "toml_edit", ] - -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 00000000..fca27798 --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ +ignore-interior-mutability = ["fluent_uri::Uri"] \ No newline at end of file diff --git a/crates/lsp/Cargo.toml b/crates/lsp/Cargo.toml index 3f3c39f1..6f4d7984 100644 --- a/crates/lsp/Cargo.toml +++ b/crates/lsp/Cargo.toml @@ -23,11 +23,11 @@ serde.workspace = true serde_json = "1.0.116" dashmap = "6.0.0" -tower-lsp = "0.20.0" +tower-lsp-server = "0.21.1" [dev-dependencies] ast-grep-language.workspace = true -tokio = { version = "1.37.0", features = [ +tokio = { version = "1.45.0", features = [ "rt-multi-thread", "io-std", "io-util", diff --git a/crates/lsp/src/lib.rs b/crates/lsp/src/lib.rs index 702bf8e1..33a71edc 100644 --- a/crates/lsp/src/lib.rs +++ b/crates/lsp/src/lib.rs @@ -2,9 +2,10 @@ mod utils; use dashmap::DashMap; use serde_json::Value; -use tower_lsp::jsonrpc::Result; -use tower_lsp::lsp_types::*; -use tower_lsp::{Client, LanguageServer}; +use tower_lsp_server::jsonrpc::Result; +use tower_lsp_server::lsp_types::*; +use tower_lsp_server::UriExt; +use tower_lsp_server::{Client, LanguageServer}; use ast_grep_config::{CombinedScan, RuleCollection, RuleConfig, Severity}; use ast_grep_core::{ @@ -17,7 +18,7 @@ use std::path::PathBuf; use utils::{convert_match_to_diagnostic, diagnostic_to_code_action, RewriteData}; -pub use tower_lsp::{LspService, Server}; +pub use tower_lsp_server::{LspService, Server}; pub trait LSPLang: LanguageExt + Eq + Send + Sync + 'static {} impl LSPLang for T where T: LanguageExt + Eq + Send + Sync + 'static {} @@ -64,7 +65,6 @@ fn code_action_provider( })) } -#[tower_lsp::async_trait] impl LanguageServer for Backend { async fn initialize(&self, params: InitializeParams) -> Result { Ok(InitializeResult { @@ -187,8 +187,8 @@ impl Backend { } } - fn get_rules(&self, uri: &Url) -> Option>> { - let absolute_path = uri.to_file_path().ok()?; + fn get_rules(&self, uri: &Uri) -> Option>> { + let absolute_path = uri.to_file_path()?; let path = if let Ok(p) = absolute_path.strip_prefix(&self.base) { p } else { @@ -200,7 +200,7 @@ impl Backend { fn get_diagnostics( &self, - uri: &Url, + uri: &Uri, versioned: &VersionedAst>, ) -> Option> { let rules = self.get_rules(uri)?; @@ -220,7 +220,7 @@ impl Backend { Some(diagnostics) } - async fn publish_diagnostics(&self, uri: Url, versioned: &VersionedAst>) -> Option<()> { + async fn publish_diagnostics(&self, uri: Uri, versioned: &VersionedAst>) -> Option<()> { let diagnostics = self.get_diagnostics(&uri, versioned).unwrap_or_default(); self .client @@ -232,13 +232,13 @@ impl Backend { async fn get_path_of_first_workspace(&self) -> Option { let folders = self.client.workspace_folders().await.ok()??; let folder = folders.first()?; - folder.uri.to_file_path().ok() + folder.uri.to_file_path().map(PathBuf::from) } // skip files outside of workspace root #1382, #1402 async fn should_skip_file_outside_workspace(&self, text_doc: &TextDocumentItem) -> Option<()> { let workspace_root = self.get_path_of_first_workspace().await?; - let doc_file_path = text_doc.uri.to_file_path().ok()?; + let doc_file_path = text_doc.uri.to_file_path()?; if doc_file_path.starts_with(workspace_root) { None } else { @@ -309,7 +309,7 @@ impl Backend { fn compute_all_fixes( &self, text_document: TextDocumentIdentifier, - ) -> std::result::Result>, LspError> + ) -> std::result::Result>, LspError> where L: ast_grep_core::Language + std::cmp::Eq, { @@ -396,8 +396,8 @@ impl Backend { } // TODO: support other urls besides file_scheme - fn infer_lang_from_uri(uri: &Url) -> Option { - let path = uri.to_file_path().ok()?; + fn infer_lang_from_uri(uri: &Uri) -> Option { + let path = uri.to_file_path()?; L::from_path(path) } diff --git a/crates/lsp/src/utils.rs b/crates/lsp/src/utils.rs index fb97fa57..c0784bb7 100644 --- a/crates/lsp/src/utils.rs +++ b/crates/lsp/src/utils.rs @@ -5,9 +5,10 @@ use ast_grep_core::tree_sitter::{LanguageExt, StrDoc}; use ast_grep_core::{Doc, Node, NodeMatch}; use serde::{Deserialize, Serialize}; -use tower_lsp::lsp_types::*; +use tower_lsp_server::lsp_types::*; use std::collections::HashMap; +use std::str::FromStr; #[derive(Serialize, Deserialize)] pub struct RewriteData { @@ -117,6 +118,6 @@ fn get_non_empty_message( } fn url_to_code_description(url: &Option) -> Option { - let href = Url::parse(url.as_ref()?).ok()?; + let href = Uri::from_str(url.as_ref()?).ok()?; Some(CodeDescription { href }) }