diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs index 7ddb3ff7b4..47b26d92ea 100644 --- a/cli/lsp/diagnostics.rs +++ b/cli/lsp/diagnostics.rs @@ -444,13 +444,21 @@ async fn generate_deps_diagnostics( range, severity: Some(lsp::DiagnosticSeverity::Error), code, - code_description: None, source: Some("deno".to_string()), message, - related_information: None, - tags: None, - data: None, + ..Default::default() }); + } else if sources.contains_key(&specifier) { + if let Some(message) = sources.get_maybe_warning(&specifier) { + diagnostics.push(lsp::Diagnostic { + range, + severity: Some(lsp::DiagnosticSeverity::Warning), + code: Some(lsp::NumberOrString::String("deno-warn".to_string())), + source: Some("deno".to_string()), + message, + ..Default::default() + }) + } } }, } diff --git a/cli/lsp/sources.rs b/cli/lsp/sources.rs index 5894e8d974..c5586a4401 100644 --- a/cli/lsp/sources.rs +++ b/cli/lsp/sources.rs @@ -14,11 +14,11 @@ use crate::module_graph::GraphBuilder; use crate::program_state::ProgramState; use crate::specifier_handler::FetchHandler; use crate::text_encoding; -use deno_runtime::permissions::Permissions; use deno_core::error::AnyError; use deno_core::serde_json; use deno_core::ModuleSpecifier; +use deno_runtime::permissions::Permissions; use std::collections::HashMap; use std::fs; use std::path::Path; @@ -105,6 +105,7 @@ struct Metadata { length_utf16: usize, line_index: LineIndex, maybe_types: Option, + maybe_warning: Option, media_type: MediaType, source: String, version: String, @@ -116,6 +117,7 @@ impl Metadata { source: &str, version: &str, media_type: &MediaType, + maybe_warning: Option, maybe_import_map: &Option, ) -> Self { let (dependencies, maybe_types) = if let Ok(parsed_module) = @@ -138,6 +140,7 @@ impl Metadata { length_utf16: source.encode_utf16().count(), line_index, maybe_types, + maybe_warning, media_type: media_type.to_owned(), source: source.to_string(), version: version.to_string(), @@ -180,6 +183,13 @@ impl Sources { self.0.lock().unwrap().get_maybe_types(specifier) } + pub fn get_maybe_warning( + &self, + specifier: &ModuleSpecifier, + ) -> Option { + self.0.lock().unwrap().get_maybe_warning(specifier) + } + pub fn get_media_type( &self, specifier: &ModuleSpecifier, @@ -271,6 +281,14 @@ impl Inner { metadata.maybe_types } + fn get_maybe_warning( + &mut self, + specifier: &ModuleSpecifier, + ) -> Option { + let metadata = self.get_metadata(&specifier)?; + metadata.maybe_warning + } + fn get_media_type( &mut self, specifier: &ModuleSpecifier, @@ -292,11 +310,11 @@ impl Inner { let path = self.get_path(specifier)?; let bytes = fs::read(path).ok()?; let scheme = specifier.scheme(); - let (source, media_type, maybe_types) = if scheme == "file" { + let (source, media_type, maybe_types, maybe_warning) = if scheme == "file" { let maybe_charset = Some(text_encoding::detect_charset(&bytes).to_string()); let source = get_source_from_bytes(bytes, maybe_charset).ok()?; - (source, MediaType::from(specifier), None) + (source, MediaType::from(specifier), None, None) } else { let cache_filename = self.http_cache.get_cache_filename(specifier)?; let headers = get_remote_headers(&cache_filename)?; @@ -307,13 +325,15 @@ impl Inner { let maybe_types = headers.get("x-typescript-types").map(|s| { analysis::resolve_import(s, &specifier, &self.maybe_import_map) }); - (source, media_type, maybe_types) + let maybe_warning = headers.get("x-deno-warning").cloned(); + (source, media_type, maybe_types, maybe_warning) }; let mut metadata = Metadata::new( specifier, &source, &version, &media_type, + maybe_warning, &self.maybe_import_map, ); if maybe_types.is_some() { @@ -547,6 +567,23 @@ mod tests { assert_eq!(actual, Some((specifier_type, MediaType::Dts))) } + #[test] + fn test_warning_header() { + let (sources, location) = setup(); + let cache = HttpCache::new(&location); + let specifier = resolve_url("https://deno.land/x/lib.js").unwrap(); + let mut headers = HashMap::new(); + headers.insert( + "x-deno-warning".to_string(), + "this is a warning".to_string(), + ); + cache + .set(&specifier, headers, b"export const a = 1;") + .unwrap(); + let actual = sources.get_maybe_warning(&specifier); + assert_eq!(actual, Some("this is a warning".to_string())); + } + #[test] fn test_resolve_dependency_evil_redirect() { let (sources, location) = setup(); diff --git a/cli/tests/integration_tests_lsp.rs b/cli/tests/integration_tests_lsp.rs index fa88ad17d4..d08da622f5 100644 --- a/cli/tests/integration_tests_lsp.rs +++ b/cli/tests/integration_tests_lsp.rs @@ -1604,6 +1604,74 @@ fn lsp_completions_registry_empty() { shutdown(&mut client); } +#[test] +fn lsp_diagnostics_warn() { + let _g = http_server(); + let mut client = init("initialize_params.json"); + did_open( + &mut client, + json!({ + "textDocument": { + "uri": "file:///a/file.ts", + "languageId": "typescript", + "version": 1, + "text": "import * as a from \"http://127.0.0.1:4545/cli/tests/x_deno_warning.js\";\n\nconsole.log(a)\n", + }, + }), + ); + let (maybe_res, maybe_err) = client + .write_request::<_, _, Value>( + "deno/cache", + json!({ + "referrer": { + "uri": "file:///a/file.ts", + }, + "uris": [ + { + "uri": "http://127.0.0.1:4545/cli/tests/x_deno_warning.js", + } + ], + }), + ) + .unwrap(); + assert!(maybe_err.is_none()); + assert!(maybe_res.is_some()); + + let (method, _) = client.read_notification::().unwrap(); + assert_eq!(method, "textDocument/publishDiagnostics"); + let (method, _) = client.read_notification::().unwrap(); + assert_eq!(method, "textDocument/publishDiagnostics"); + let (method, maybe_params) = client + .read_notification::() + .unwrap(); + assert_eq!(method, "textDocument/publishDiagnostics"); + assert_eq!( + maybe_params, + Some(lsp::PublishDiagnosticsParams { + uri: Url::parse("file:///a/file.ts").unwrap(), + diagnostics: vec![lsp::Diagnostic { + range: lsp::Range { + start: lsp::Position { + line: 0, + character: 19 + }, + end: lsp::Position { + line: 0, + character: 70 + } + }, + severity: Some(lsp::DiagnosticSeverity::Warning), + code: Some(lsp::NumberOrString::String("deno-warn".to_string())), + source: Some("deno".to_string()), + message: "foobar".to_string(), + ..Default::default() + }], + version: Some(1), + }) + ); + shutdown(&mut client); +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct PerformanceAverage {