mirror of
https://github.com/denoland/deno.git
synced 2024-11-28 16:20:57 -05:00
fix(lsp): rewrite import for 'infer return type' action (#24685)
This commit is contained in:
parent
9806064ac2
commit
a45a40533e
5 changed files with 122 additions and 8 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -7541,9 +7541,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "v8"
|
name = "v8"
|
||||||
version = "0.98.0"
|
version = "0.98.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "feb252d5be11c32cb4755d66d58db30ff30af5f1f17183e83ff54383a402c5f6"
|
checksum = "d03f42deef61349d31ae100e7bcdcc5d9293c1126cb8aff8fd56ba3cba18340b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bindgen",
|
"bindgen",
|
||||||
"bitflags 2.5.0",
|
"bitflags 2.5.0",
|
||||||
|
|
|
@ -73,8 +73,9 @@ static PREFERRED_FIXES: Lazy<HashMap<&'static str, (u32, bool)>> =
|
||||||
.collect()
|
.collect()
|
||||||
});
|
});
|
||||||
|
|
||||||
static IMPORT_SPECIFIER_RE: Lazy<Regex> =
|
static IMPORT_SPECIFIER_RE: Lazy<Regex> = lazy_regex::lazy_regex!(
|
||||||
lazy_regex::lazy_regex!(r#"\sfrom\s+["']([^"']*)["']"#);
|
r#"\sfrom\s+["']([^"']*)["']|import\s*\(\s*["']([^"']*)["']\s*\)"#
|
||||||
|
);
|
||||||
|
|
||||||
const SUPPORTED_EXTENSIONS: &[&str] = &[
|
const SUPPORTED_EXTENSIONS: &[&str] = &[
|
||||||
".ts", ".tsx", ".js", ".jsx", ".mjs", ".mts", ".cjs", ".cts", ".d.ts",
|
".ts", ".tsx", ".js", ".jsx", ".mjs", ".mts", ".cjs", ".cts", ".d.ts",
|
||||||
|
@ -528,7 +529,8 @@ pub fn fix_ts_import_changes(
|
||||||
.map(|line| {
|
.map(|line| {
|
||||||
// This assumes that there's only one import per line.
|
// This assumes that there's only one import per line.
|
||||||
if let Some(captures) = IMPORT_SPECIFIER_RE.captures(line) {
|
if let Some(captures) = IMPORT_SPECIFIER_RE.captures(line) {
|
||||||
let specifier = captures.get(1).unwrap().as_str();
|
let specifier =
|
||||||
|
captures.iter().skip(1).find_map(|s| s).unwrap().as_str();
|
||||||
if let Some(new_specifier) =
|
if let Some(new_specifier) =
|
||||||
import_mapper.check_unresolved_specifier(specifier, referrer)
|
import_mapper.check_unresolved_specifier(specifier, referrer)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1810,7 +1810,10 @@ impl Inner {
|
||||||
LspError::internal_error()
|
LspError::internal_error()
|
||||||
})?;
|
})?;
|
||||||
code_action
|
code_action
|
||||||
} else if kind.as_str().starts_with(CodeActionKind::REFACTOR.as_str()) {
|
} else if let Some(kind_suffix) = kind
|
||||||
|
.as_str()
|
||||||
|
.strip_prefix(CodeActionKind::REFACTOR.as_str())
|
||||||
|
{
|
||||||
let mut code_action = params;
|
let mut code_action = params;
|
||||||
let action_data: refactor::RefactorCodeActionData = from_value(data)
|
let action_data: refactor::RefactorCodeActionData = from_value(data)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
|
@ -1819,7 +1822,7 @@ impl Inner {
|
||||||
})?;
|
})?;
|
||||||
let asset_or_doc = self.get_asset_or_document(&action_data.specifier)?;
|
let asset_or_doc = self.get_asset_or_document(&action_data.specifier)?;
|
||||||
let line_index = asset_or_doc.line_index();
|
let line_index = asset_or_doc.line_index();
|
||||||
let refactor_edit_info = self
|
let mut refactor_edit_info = self
|
||||||
.ts_server
|
.ts_server
|
||||||
.get_edits_for_refactor(
|
.get_edits_for_refactor(
|
||||||
self.snapshot(),
|
self.snapshot(),
|
||||||
|
@ -1841,6 +1844,17 @@ impl Inner {
|
||||||
asset_or_doc.scope().cloned(),
|
asset_or_doc.scope().cloned(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
if kind_suffix == ".rewrite.function.returnType" {
|
||||||
|
refactor_edit_info.edits = fix_ts_import_changes(
|
||||||
|
&action_data.specifier,
|
||||||
|
&refactor_edit_info.edits,
|
||||||
|
&self.get_ts_response_import_mapper(&action_data.specifier),
|
||||||
|
)
|
||||||
|
.map_err(|err| {
|
||||||
|
error!("Unable to remap changes: {:#}", err);
|
||||||
|
LspError::internal_error()
|
||||||
|
})?
|
||||||
|
}
|
||||||
code_action.edit = refactor_edit_info.to_workspace_edit(self)?;
|
code_action.edit = refactor_edit_info.to_workspace_edit(self)?;
|
||||||
code_action
|
code_action
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2944,7 +2944,7 @@ pub fn file_text_changes_to_workspace_edit(
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RefactorEditInfo {
|
pub struct RefactorEditInfo {
|
||||||
edits: Vec<FileTextChanges>,
|
pub edits: Vec<FileTextChanges>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub rename_location: Option<u32>,
|
pub rename_location: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -7373,6 +7373,104 @@ fn lsp_npm_completions_auto_import_and_quick_fix_no_import_map() {
|
||||||
client.shutdown();
|
client.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lsp_infer_return_type() {
|
||||||
|
let context = TestContextBuilder::new().use_temp_cwd().build();
|
||||||
|
let temp_dir = context.temp_dir();
|
||||||
|
temp_dir.write("deno.json", json!({}).to_string());
|
||||||
|
let types_file = source_file(
|
||||||
|
temp_dir.path().join("types.d.ts"),
|
||||||
|
r#"
|
||||||
|
export interface SomeInterface {
|
||||||
|
someField: number;
|
||||||
|
}
|
||||||
|
declare global {
|
||||||
|
export function someFunction(): SomeInterface;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
let file = source_file(
|
||||||
|
temp_dir.path().join("file.ts"),
|
||||||
|
r#"
|
||||||
|
function foo() {
|
||||||
|
return someFunction();
|
||||||
|
}
|
||||||
|
foo();
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
let mut client = context.new_lsp_command().build();
|
||||||
|
client.initialize_default();
|
||||||
|
let res = client.write_request(
|
||||||
|
"textDocument/codeAction",
|
||||||
|
json!({
|
||||||
|
"textDocument": { "uri": file.uri() },
|
||||||
|
"range": {
|
||||||
|
"start": { "line": 1, "character": 15 },
|
||||||
|
"end": { "line": 1, "character": 18 },
|
||||||
|
},
|
||||||
|
"context": {
|
||||||
|
"diagnostics": [],
|
||||||
|
"only": ["refactor.rewrite.function.returnType"],
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
&res,
|
||||||
|
&json!([
|
||||||
|
{
|
||||||
|
"title": "Infer function return type",
|
||||||
|
"kind": "refactor.rewrite.function.returnType",
|
||||||
|
"isPreferred": false,
|
||||||
|
"data": {
|
||||||
|
"specifier": file.uri(),
|
||||||
|
"range": {
|
||||||
|
"start": { "line": 1, "character": 15 },
|
||||||
|
"end": { "line": 1, "character": 18 },
|
||||||
|
},
|
||||||
|
"refactorName": "Infer function return type",
|
||||||
|
"actionName": "Infer function return type",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
let code_action = res.as_array().unwrap().first().unwrap();
|
||||||
|
let res = client.write_request("codeAction/resolve", code_action);
|
||||||
|
assert_eq!(
|
||||||
|
&res,
|
||||||
|
&json!({
|
||||||
|
"title": "Infer function return type",
|
||||||
|
"kind": "refactor.rewrite.function.returnType",
|
||||||
|
"isPreferred": false,
|
||||||
|
"data": {
|
||||||
|
"specifier": file.uri(),
|
||||||
|
"range": {
|
||||||
|
"start": { "line": 1, "character": 15 },
|
||||||
|
"end": { "line": 1, "character": 18 },
|
||||||
|
},
|
||||||
|
"refactorName": "Infer function return type",
|
||||||
|
"actionName": "Infer function return type",
|
||||||
|
},
|
||||||
|
"edit": {
|
||||||
|
"documentChanges": [
|
||||||
|
{
|
||||||
|
"textDocument": { "uri": file.uri(), "version": null },
|
||||||
|
"edits": [
|
||||||
|
{
|
||||||
|
"range": {
|
||||||
|
"start": { "line": 1, "character": 20 },
|
||||||
|
"end": { "line": 1, "character": 20 },
|
||||||
|
},
|
||||||
|
"newText": format!(": import(\"{}\").SomeInterface", types_file.uri()),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
client.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
// Regression test for https://github.com/denoland/deno/issues/23895.
|
// Regression test for https://github.com/denoland/deno/issues/23895.
|
||||||
#[test]
|
#[test]
|
||||||
fn lsp_npm_types_nested_js_dts() {
|
fn lsp_npm_types_nested_js_dts() {
|
||||||
|
|
Loading…
Reference in a new issue