diff options
Diffstat (limited to 'cli/lsp/diagnostics.rs')
-rw-r--r-- | cli/lsp/diagnostics.rs | 81 |
1 files changed, 66 insertions, 15 deletions
diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs index 4faff2fae..9f3c409cc 100644 --- a/cli/lsp/diagnostics.rs +++ b/cli/lsp/diagnostics.rs @@ -13,6 +13,7 @@ use super::tsc; use super::tsc::TsServer; use crate::args::LintOptions; +use crate::graph_util::enhanced_resolution_error_message; use crate::node; use crate::npm::NpmPackageReference; use crate::tools::lint::get_configured_rules; @@ -25,7 +26,9 @@ use deno_core::serde::Deserialize; use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::ModuleSpecifier; +use deno_graph::ResolutionError; use deno_graph::Resolved; +use deno_graph::SpecifierError; use deno_lint::rules::LintRule; use deno_runtime::tokio_util::create_basic_runtime; use log::error; @@ -574,6 +577,12 @@ struct DiagnosticDataSpecifier { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] +struct DiagnosticDataStrSpecifier { + pub specifier: String, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] struct DiagnosticDataRedirect { pub redirect: ModuleSpecifier, } @@ -621,9 +630,6 @@ pub enum DenoDiagnostic { impl DenoDiagnostic { fn code(&self) -> &str { - use deno_graph::ResolutionError; - use deno_graph::SpecifierError; - match self { Self::DenoWarn(_) => "deno-warn", Self::ImportMapRemap { .. } => "import-map-remap", @@ -749,6 +755,32 @@ impl DenoDiagnostic { ..Default::default() } } + "import-prefix-missing" => { + // if an import-prefix-missing diagnostic ends up here, then that currently + // will only ever occur for a possible "node:" specifier, so don't bother + // checking if it's actually a "node:"" specifier + let data = diagnostic + .data + .clone() + .ok_or_else(|| anyhow!("Diagnostic is missing data"))?; + let data: DiagnosticDataStrSpecifier = serde_json::from_value(data)?; + lsp::CodeAction { + title: format!("Update specifier to node:{}", data.specifier), + kind: Some(lsp::CodeActionKind::QUICKFIX), + diagnostics: Some(vec![diagnostic.clone()]), + edit: Some(lsp::WorkspaceEdit { + changes: Some(HashMap::from([( + specifier.clone(), + vec![lsp::TextEdit { + new_text: format!("\"node:{}\"", data.specifier), + range: diagnostic.range, + }], + )])), + ..Default::default() + }), + ..Default::default() + } + } _ => { return Err(anyhow!( "Unsupported diagnostic code (\"{}\") provided.", @@ -764,17 +796,21 @@ impl DenoDiagnostic { /// Given a reference to the code from an LSP diagnostic, determine if the /// diagnostic is fixable or not - pub fn is_fixable(code: &Option<lsp::NumberOrString>) -> bool { - if let Some(lsp::NumberOrString::String(code)) = code { - matches!( - code.as_str(), - "import-map-remap" - | "no-cache" - | "no-cache-npm" - | "no-cache-data" - | "no-assert-type" - | "redirect" - ) + pub fn is_fixable(diagnostic: &lsp_types::Diagnostic) -> bool { + if let Some(lsp::NumberOrString::String(code)) = &diagnostic.code { + if code == "import-prefix-missing" { + diagnostic.data.is_some() + } else { + matches!( + code.as_str(), + "import-map-remap" + | "no-cache" + | "no-cache-npm" + | "no-cache-data" + | "no-assert-type" + | "redirect" + ) + } } else { false } @@ -794,7 +830,22 @@ impl DenoDiagnostic { Self::NoCacheNpm(pkg_ref, specifier) => (lsp::DiagnosticSeverity::ERROR, format!("Uncached or missing npm package: \"{}\".", pkg_ref.req), Some(json!({ "specifier": specifier }))), Self::NoLocal(specifier) => (lsp::DiagnosticSeverity::ERROR, format!("Unable to load a local module: \"{}\".\n Please check the file path.", specifier), None), Self::Redirect { from, to} => (lsp::DiagnosticSeverity::INFORMATION, format!("The import of \"{}\" was redirected to \"{}\".", from, to), Some(json!({ "specifier": from, "redirect": to }))), - Self::ResolutionError(err) => (lsp::DiagnosticSeverity::ERROR, err.to_string(), None), + Self::ResolutionError(err) => ( + lsp::DiagnosticSeverity::ERROR, + enhanced_resolution_error_message(err), + if let ResolutionError::InvalidSpecifier { + error: SpecifierError::ImportPrefixMissing(specifier, _), + .. + } = err { + if crate::node::resolve_builtin_node_module(specifier).is_ok() { + Some(json!({ "specifier": specifier })) + } else { + None + } + } else { + None + }, + ), Self::InvalidNodeSpecifier(specifier) => (lsp::DiagnosticSeverity::ERROR, format!("Unknown Node built-in module: {}", specifier.path()), None), }; lsp::Diagnostic { |