mirror of
https://github.com/denoland/deno.git
synced 2024-11-24 15:19:26 -05:00
fix(lsp): make missing import action fix infallible (#26539)
This commit is contained in:
parent
ec968aa5ae
commit
d92d2fe9b0
1 changed files with 48 additions and 55 deletions
|
@ -18,7 +18,6 @@ use deno_lint::diagnostic::LintDiagnosticRange;
|
||||||
use deno_ast::SourceRange;
|
use deno_ast::SourceRange;
|
||||||
use deno_ast::SourceRangedForSpanned;
|
use deno_ast::SourceRangedForSpanned;
|
||||||
use deno_ast::SourceTextInfo;
|
use deno_ast::SourceTextInfo;
|
||||||
use deno_core::anyhow::anyhow;
|
|
||||||
use deno_core::error::custom_error;
|
use deno_core::error::custom_error;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::serde::Deserialize;
|
use deno_core::serde::Deserialize;
|
||||||
|
@ -40,6 +39,7 @@ use import_map::ImportMap;
|
||||||
use node_resolver::NpmResolver;
|
use node_resolver::NpmResolver;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
@ -598,68 +598,62 @@ pub fn fix_ts_import_changes(
|
||||||
|
|
||||||
/// Fix tsc import code actions so that the module specifier is correct for
|
/// Fix tsc import code actions so that the module specifier is correct for
|
||||||
/// resolution by Deno (includes the extension).
|
/// resolution by Deno (includes the extension).
|
||||||
fn fix_ts_import_action(
|
fn fix_ts_import_action<'a>(
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &ModuleSpecifier,
|
||||||
action: &tsc::CodeFixAction,
|
action: &'a tsc::CodeFixAction,
|
||||||
import_mapper: &TsResponseImportMapper,
|
import_mapper: &TsResponseImportMapper,
|
||||||
) -> Result<Option<tsc::CodeFixAction>, AnyError> {
|
) -> Option<Cow<'a, tsc::CodeFixAction>> {
|
||||||
if matches!(
|
if !matches!(
|
||||||
action.fix_name.as_str(),
|
action.fix_name.as_str(),
|
||||||
"import" | "fixMissingFunctionDeclaration"
|
"import" | "fixMissingFunctionDeclaration"
|
||||||
) {
|
) {
|
||||||
let change = action
|
return Some(Cow::Borrowed(action));
|
||||||
|
}
|
||||||
|
let specifier = (|| {
|
||||||
|
let text_change = action.changes.first()?.text_changes.first()?;
|
||||||
|
let captures = IMPORT_SPECIFIER_RE.captures(&text_change.new_text)?;
|
||||||
|
Some(captures.get(1)?.as_str())
|
||||||
|
})();
|
||||||
|
let Some(specifier) = specifier else {
|
||||||
|
return Some(Cow::Borrowed(action));
|
||||||
|
};
|
||||||
|
if let Some(new_specifier) =
|
||||||
|
import_mapper.check_unresolved_specifier(specifier, referrer)
|
||||||
|
{
|
||||||
|
let description = action.description.replace(specifier, &new_specifier);
|
||||||
|
let changes = action
|
||||||
.changes
|
.changes
|
||||||
.first()
|
.iter()
|
||||||
.ok_or_else(|| anyhow!("Unexpected action changes."))?;
|
.map(|c| {
|
||||||
let text_change = change
|
let text_changes = c
|
||||||
.text_changes
|
.text_changes
|
||||||
.first()
|
|
||||||
.ok_or_else(|| anyhow!("Missing text change."))?;
|
|
||||||
if let Some(captures) = IMPORT_SPECIFIER_RE.captures(&text_change.new_text)
|
|
||||||
{
|
|
||||||
let specifier = captures
|
|
||||||
.get(1)
|
|
||||||
.ok_or_else(|| anyhow!("Missing capture."))?
|
|
||||||
.as_str();
|
|
||||||
if let Some(new_specifier) =
|
|
||||||
import_mapper.check_unresolved_specifier(specifier, referrer)
|
|
||||||
{
|
|
||||||
let description = action.description.replace(specifier, &new_specifier);
|
|
||||||
let changes = action
|
|
||||||
.changes
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| {
|
.map(|tc| tsc::TextChange {
|
||||||
let text_changes = c
|
span: tc.span.clone(),
|
||||||
.text_changes
|
new_text: tc.new_text.replace(specifier, &new_specifier),
|
||||||
.iter()
|
|
||||||
.map(|tc| tsc::TextChange {
|
|
||||||
span: tc.span.clone(),
|
|
||||||
new_text: tc.new_text.replace(specifier, &new_specifier),
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
tsc::FileTextChanges {
|
|
||||||
file_name: c.file_name.clone(),
|
|
||||||
text_changes,
|
|
||||||
is_new_file: c.is_new_file,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
tsc::FileTextChanges {
|
||||||
|
file_name: c.file_name.clone(),
|
||||||
|
text_changes,
|
||||||
|
is_new_file: c.is_new_file,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
return Ok(Some(tsc::CodeFixAction {
|
Some(Cow::Owned(tsc::CodeFixAction {
|
||||||
description,
|
description,
|
||||||
changes,
|
changes,
|
||||||
commands: None,
|
commands: None,
|
||||||
fix_name: action.fix_name.clone(),
|
fix_name: action.fix_name.clone(),
|
||||||
fix_id: None,
|
fix_id: None,
|
||||||
fix_all_description: None,
|
fix_all_description: None,
|
||||||
}));
|
}))
|
||||||
} else if !import_mapper.is_valid_import(specifier, referrer) {
|
} else if !import_mapper.is_valid_import(specifier, referrer) {
|
||||||
return Ok(None);
|
None
|
||||||
}
|
} else {
|
||||||
}
|
Some(Cow::Borrowed(action))
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(action.clone()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines if two TypeScript diagnostic codes are effectively equivalent.
|
/// Determines if two TypeScript diagnostic codes are effectively equivalent.
|
||||||
|
@ -1004,8 +998,7 @@ impl CodeActionCollection {
|
||||||
specifier,
|
specifier,
|
||||||
action,
|
action,
|
||||||
&language_server.get_ts_response_import_mapper(specifier),
|
&language_server.get_ts_response_import_mapper(specifier),
|
||||||
)?
|
) else {
|
||||||
else {
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
let edit = ts_changes_to_edit(&action.changes, language_server)?;
|
let edit = ts_changes_to_edit(&action.changes, language_server)?;
|
||||||
|
@ -1027,7 +1020,7 @@ impl CodeActionCollection {
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
.actions
|
.actions
|
||||||
.push(CodeActionKind::Tsc(code_action, action.clone()));
|
.push(CodeActionKind::Tsc(code_action, action.as_ref().clone()));
|
||||||
|
|
||||||
if let Some(fix_id) = &action.fix_id {
|
if let Some(fix_id) = &action.fix_id {
|
||||||
if let Some(CodeActionKind::Tsc(existing_fix_all, existing_action)) =
|
if let Some(CodeActionKind::Tsc(existing_fix_all, existing_action)) =
|
||||||
|
|
Loading…
Reference in a new issue