diff options
author | Kitson Kelly <me@kitsonkelly.com> | 2021-12-16 14:53:17 +1100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-16 14:53:17 +1100 |
commit | e28fb70aeecf548d150312c30f7f32b60c4fdece (patch) | |
tree | 19a068fe1cc34e2448ac11cf7d5f82b56cce8c6c /cli/lsp | |
parent | 0f53b82cd262e972f392f81b572351b2427389ab (diff) |
fix(lsp): provide diagnostics for import assertions (#13105)
Fixes: #13099
Diffstat (limited to 'cli/lsp')
-rw-r--r-- | cli/lsp/analysis.rs | 66 | ||||
-rw-r--r-- | cli/lsp/diagnostics.rs | 35 | ||||
-rw-r--r-- | cli/lsp/language_server.rs | 7 |
3 files changed, 83 insertions, 25 deletions
diff --git a/cli/lsp/analysis.rs b/cli/lsp/analysis.rs index de1aa91b5..d21abae87 100644 --- a/cli/lsp/analysis.rs +++ b/cli/lsp/analysis.rs @@ -384,31 +384,51 @@ pub struct CodeActionCollection { impl CodeActionCollection { pub(crate) fn add_deno_fix_action( &mut self, + specifier: &ModuleSpecifier, diagnostic: &lsp::Diagnostic, ) -> Result<(), AnyError> { - if let Some(data) = diagnostic.data.clone() { - let fix_data: DenoFixData = serde_json::from_value(data)?; - let title = if matches!(&diagnostic.code, Some(lsp::NumberOrString::String(code)) if code == "no-cache-data") - { - "Cache the data URL and its dependencies.".to_string() - } else { - format!("Cache \"{}\" and its dependencies.", fix_data.specifier) - }; - let code_action = lsp::CodeAction { - title, - kind: Some(lsp::CodeActionKind::QUICKFIX), - diagnostics: Some(vec![diagnostic.clone()]), - edit: None, - command: Some(lsp::Command { - title: "".to_string(), - command: "deno.cache".to_string(), - arguments: Some(vec![json!([fix_data.specifier])]), - }), - is_preferred: None, - disabled: None, - data: None, - }; - self.actions.push(CodeActionKind::Deno(code_action)); + if let Some(lsp::NumberOrString::String(code)) = &diagnostic.code { + if code == "no-assert-type" { + let code_action = lsp::CodeAction { + title: "Insert import assertion.".to_string(), + 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: " assert { type: \"json\" }".to_string(), + range: lsp::Range { + start: diagnostic.range.end, + end: diagnostic.range.end, + }, + }], + )])), + ..Default::default() + }), + ..Default::default() + }; + self.actions.push(CodeActionKind::Deno(code_action)); + } else if let Some(data) = diagnostic.data.clone() { + let fix_data: DenoFixData = serde_json::from_value(data)?; + let title = if code == "no-cache-data" { + "Cache the data URL and its dependencies.".to_string() + } else { + format!("Cache \"{}\" and its dependencies.", fix_data.specifier) + }; + let code_action = lsp::CodeAction { + title, + kind: Some(lsp::CodeActionKind::QUICKFIX), + diagnostics: Some(vec![diagnostic.clone()]), + command: Some(lsp::Command { + title: "".to_string(), + command: "deno.cache".to_string(), + arguments: Some(vec![json!([fix_data.specifier])]), + }), + ..Default::default() + }; + self.actions.push(CodeActionKind::Deno(code_action)); + } } Ok(()) } diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs index 82a08c8f9..12d403ebb 100644 --- a/cli/lsp/diagnostics.rs +++ b/cli/lsp/diagnostics.rs @@ -9,6 +9,7 @@ use super::tsc; use crate::diagnostics; +use deno_ast::MediaType; use deno_core::anyhow::anyhow; use deno_core::error::AnyError; use deno_core::resolve_url; @@ -439,6 +440,8 @@ fn diagnose_dependency( diagnostics: &mut Vec<lsp::Diagnostic>, documents: &Documents, resolved: &deno_graph::Resolved, + is_dynamic: bool, + maybe_assert_type: Option<&str>, ) { match resolved { Some(Ok((specifier, range))) => { @@ -453,6 +456,34 @@ fn diagnose_dependency( ..Default::default() }) } + if doc.media_type() == MediaType::Json { + match maybe_assert_type { + // The module has the correct assertion type, no diagnostic + Some("json") => (), + // The dynamic import statement is missing an assertion type, which + // we might not be able to statically detect, therefore we will + // not provide a potentially incorrect diagnostic. + None if is_dynamic => (), + // The module has an incorrect assertion type, diagnostic + Some(assert_type) => diagnostics.push(lsp::Diagnostic { + range: documents::to_lsp_range(range), + severity: Some(lsp::DiagnosticSeverity::ERROR), + code: Some(lsp::NumberOrString::String("invalid-assert-type".to_string())), + source: Some("deno".to_string()), + message: format!("The module is a JSON module and expected an assertion type of \"json\". Instead got \"{}\".", assert_type), + ..Default::default() + }), + // The module is missing an assertion type, diagnostic + None => diagnostics.push(lsp::Diagnostic { + range: documents::to_lsp_range(range), + severity: Some(lsp::DiagnosticSeverity::ERROR), + code: Some(lsp::NumberOrString::String("no-assert-type".to_string())), + source: Some("deno".to_string()), + message: "The module is a JSON module and not being imported with an import assertion. Consider adding `assert { type: \"json\" }` to the import statement.".to_string(), + ..Default::default() + }), + } + } } else { let (code, message) = match specifier.scheme() { "file" => (Some(lsp::NumberOrString::String("no-local".to_string())), format!("Unable to load a local module: \"{}\".\n Please check the file path.", specifier)), @@ -508,11 +539,15 @@ async fn generate_deps_diagnostics( &mut diagnostics, &snapshot.documents, &dependency.maybe_code, + dependency.is_dynamic, + dependency.maybe_assert_type.as_deref(), ); diagnose_dependency( &mut diagnostics, &snapshot.documents, &dependency.maybe_type, + dependency.is_dynamic, + dependency.maybe_assert_type.as_deref(), ); } diagnostics_vec.push(( diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 660ef8d90..384b100b2 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -1181,7 +1181,10 @@ impl Inner { "deno-lint" => matches!(&d.code, Some(_)), "deno" => match &d.code { Some(NumberOrString::String(code)) => { - code == "no-cache" || code == "no-cache-data" + matches!( + code.as_str(), + "no-cache" | "no-cache-data" | "no-assert-type" + ) } _ => false, }, @@ -1241,7 +1244,7 @@ impl Inner { } } Some("deno") => code_actions - .add_deno_fix_action(diagnostic) + .add_deno_fix_action(&specifier, diagnostic) .map_err(|err| { error!("{}", err); LspError::internal_error() |