diff --git a/cli/jsr.rs b/cli/jsr.rs index 9897a11935..d741e6ace1 100644 --- a/cli/jsr.rs +++ b/cli/jsr.rs @@ -92,9 +92,8 @@ impl JsrCacheResolver { pub fn jsr_to_registry_url( &self, - specifier: &ModuleSpecifier, + req_ref: &JsrPackageReqReference, ) -> Option { - let req_ref = JsrPackageReqReference::from_str(specifier.as_str()).ok()?; let req = req_ref.req().clone(); let maybe_nv = self.req_to_nv(&req); let nv = maybe_nv.as_ref()?; diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs index 722cd77f67..21a613bfaa 100644 --- a/cli/lsp/documents.rs +++ b/cli/lsp/documents.rs @@ -35,7 +35,6 @@ use deno_core::error::AnyError; use deno_core::futures::future; use deno_core::futures::FutureExt; use deno_core::parking_lot::Mutex; -use deno_core::url; use deno_core::ModuleSpecifier; use deno_graph::source::ResolutionMode; use deno_graph::GraphImport; @@ -48,6 +47,7 @@ use deno_runtime::deno_node::NodeResolutionMode; use deno_runtime::deno_node::NodeResolver; use deno_runtime::deno_node::PackageJson; use deno_runtime::permissions::PermissionsContainer; +use deno_semver::jsr::JsrPackageReqReference; use deno_semver::npm::NpmPackageReqReference; use deno_semver::package::PackageReq; use indexmap::IndexMap; @@ -643,26 +643,6 @@ impl Document { } } -pub fn to_hover_text(result: &Resolution) -> String { - match result { - Resolution::Ok(resolved) => { - let specifier = &resolved.specifier; - match specifier.scheme() { - "data" => "_(a data url)_".to_string(), - "blob" => "_(a blob url)_".to_string(), - _ => format!( - "{}​{}", - &specifier[..url::Position::AfterScheme], - &specifier[url::Position::AfterScheme..], - ) - .replace('@', "​@"), - } - } - Resolution::Err(_) => "_[errored]_".to_string(), - Resolution::None => "_[missing]_".to_string(), - } -} - pub fn to_lsp_range(range: &deno_graph::Range) -> lsp::Range { lsp::Range { start: lsp::Position { @@ -1086,9 +1066,12 @@ impl Documents { .into_owned(), ) } else { - let specifier = match self.jsr_resolver.jsr_to_registry_url(specifier) { - Some(url) => Cow::Owned(url), - None => Cow::Borrowed(specifier), + let specifier = if let Ok(jsr_req_ref) = + JsrPackageReqReference::from_specifier(specifier) + { + Cow::Owned(self.jsr_resolver.jsr_to_registry_url(&jsr_req_ref)?) + } else { + Cow::Borrowed(specifier) }; self.redirect_resolver.resolve(&specifier) } diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index b565246290..b108eb54ea 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -11,8 +11,10 @@ use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; use deno_core::unsync::spawn; +use deno_core::url; use deno_core::ModuleSpecifier; use deno_graph::GraphKind; +use deno_graph::Resolution; use deno_lockfile::Lockfile; use deno_npm::NpmSystemInfo; use deno_runtime::deno_fs; @@ -20,6 +22,7 @@ use deno_runtime::deno_node::NodeResolver; use deno_runtime::deno_node::PackageJson; use deno_runtime::deno_tls::rustls::RootCertStore; use deno_runtime::deno_tls::RootCertStoreProvider; +use deno_semver::jsr::JsrPackageReqReference; use import_map::ImportMap; use indexmap::IndexSet; use log::error; @@ -62,7 +65,6 @@ use super::diagnostics::DiagnosticDataSpecifier; use super::diagnostics::DiagnosticServerUpdateMessage; use super::diagnostics::DiagnosticsServer; use super::diagnostics::DiagnosticsState; -use super::documents::to_hover_text; use super::documents::to_lsp_range; use super::documents::AssetOrDocument; use super::documents::Document; @@ -1866,32 +1868,32 @@ impl Inner { let value = match (dep.maybe_code.is_none(), dep.maybe_type.is_none(), &dep_maybe_types_dependency) { (false, false, None) => format!( "**Resolved Dependency**\n\n**Code**: {}\n\n**Types**: {}\n", - to_hover_text(&dep.maybe_code), - to_hover_text(&dep.maybe_type) + self.resolution_to_hover_text(&dep.maybe_code), + self.resolution_to_hover_text(&dep.maybe_type), ), (false, false, Some(types_dep)) if !types_dep.is_none() => format!( "**Resolved Dependency**\n\n**Code**: {}\n**Types**: {}\n**Import Types**: {}\n", - to_hover_text(&dep.maybe_code), - to_hover_text(&dep.maybe_type), - to_hover_text(types_dep) + self.resolution_to_hover_text(&dep.maybe_code), + self.resolution_to_hover_text(&dep.maybe_type), + self.resolution_to_hover_text(types_dep), ), (false, false, Some(_)) => format!( "**Resolved Dependency**\n\n**Code**: {}\n\n**Types**: {}\n", - to_hover_text(&dep.maybe_code), - to_hover_text(&dep.maybe_type) + self.resolution_to_hover_text(&dep.maybe_code), + self.resolution_to_hover_text(&dep.maybe_type), ), (false, true, Some(types_dep)) if !types_dep.is_none() => format!( "**Resolved Dependency**\n\n**Code**: {}\n\n**Types**: {}\n", - to_hover_text(&dep.maybe_code), - to_hover_text(types_dep) + self.resolution_to_hover_text(&dep.maybe_code), + self.resolution_to_hover_text(types_dep), ), (false, true, _) => format!( "**Resolved Dependency**\n\n**Code**: {}\n", - to_hover_text(&dep.maybe_code) + self.resolution_to_hover_text(&dep.maybe_code), ), (true, false, _) => format!( "**Resolved Dependency**\n\n**Types**: {}\n", - to_hover_text(&dep.maybe_type) + self.resolution_to_hover_text(&dep.maybe_type), ), (true, true, _) => unreachable!("{}", json!(params)), }; @@ -1922,6 +1924,40 @@ impl Inner { Ok(hover) } + fn resolution_to_hover_text(&self, resolution: &Resolution) -> String { + match resolution { + Resolution::Ok(resolved) => { + let specifier = &resolved.specifier; + match specifier.scheme() { + "data" => "_(a data url)_".to_string(), + "blob" => "_(a blob url)_".to_string(), + _ => { + let mut result = format!( + "{}​{}", + &specifier[..url::Position::AfterScheme], + &specifier[url::Position::AfterScheme..], + ) + .replace('@', "​@"); + if let Ok(jsr_req_ref) = + JsrPackageReqReference::from_specifier(specifier) + { + if let Some(url) = self + .documents + .get_jsr_resolver() + .jsr_to_registry_url(&jsr_req_ref) + { + result = format!("{result} (<{url}>)"); + } + } + result + } + } + } + Resolution::Err(_) => "_[errored]_".to_string(), + Resolution::None => "_[missing]_".to_string(), + } + } + async fn code_action( &self, params: CodeActionParams, diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs index cbf2725810..4ea4336a51 100644 --- a/tests/integration/lsp_tests.rs +++ b/tests/integration/lsp_tests.rs @@ -2514,6 +2514,55 @@ fn lsp_hover_typescript_types() { client.shutdown(); } +#[test] +fn lsp_hover_jsr() { + let context = TestContextBuilder::new() + .use_http_server() + .use_temp_cwd() + .build(); + let temp_dir = context.temp_dir(); + let mut client = context.new_lsp_command().build(); + client.initialize_default(); + client.did_open(json!({ + "textDocument": { + "uri": temp_dir.uri().join("file.ts").unwrap(), + "languageId": "typescript", + "version": 1, + "text": "import \"jsr:@denotest/add@1.0.0\";\n", + } + })); + client.write_request( + "workspace/executeCommand", + json!({ + "command": "deno.cache", + "arguments": [[], temp_dir.uri().join("file.ts").unwrap()], + }), + ); + let res = client.write_request( + "textDocument/hover", + json!({ + "textDocument": { + "uri": temp_dir.uri().join("file.ts").unwrap(), + }, + "position": { "line": 0, "character": 7 }, + }), + ); + assert_eq!( + res, + json!({ + "contents": { + "kind": "markdown", + "value": "**Resolved Dependency**\n\n**Code**: jsr​:​@denotest/add​@1.0.0 ()\n", + }, + "range": { + "start": { "line": 0, "character": 7 }, + "end": { "line": 0, "character": 32 }, + }, + }), + ); + client.shutdown(); +} + #[test] fn lsp_hover_jsdoc_symbol_link() { let context = TestContextBuilder::new().use_temp_cwd().build();