fix(lsp): fix import specifiers in file rename changes (#30458)
Some checks are pending
ci / test release macos-x86_64 (push) Blocked by required conditions
ci / test debug windows-x86_64 (push) Blocked by required conditions
ci / test release windows-x86_64 (push) Blocked by required conditions
ci / build libs (push) Blocked by required conditions
ci / pre-build (push) Waiting to run
ci / test debug linux-aarch64 (push) Blocked by required conditions
ci / test release linux-aarch64 (push) Blocked by required conditions
ci / test debug macos-aarch64 (push) Blocked by required conditions
ci / test release macos-aarch64 (push) Blocked by required conditions
ci / bench release linux-x86_64 (push) Blocked by required conditions
ci / lint debug linux-x86_64 (push) Blocked by required conditions
ci / lint debug macos-x86_64 (push) Blocked by required conditions
ci / lint debug windows-x86_64 (push) Blocked by required conditions
ci / test debug linux-x86_64 (push) Blocked by required conditions
ci / test release linux-x86_64 (push) Blocked by required conditions
ci / test debug macos-x86_64 (push) Blocked by required conditions
ci / publish canary (push) Blocked by required conditions

This commit is contained in:
Nayeem Rahman 2025-08-19 21:46:59 +01:00 committed by GitHub
parent dabf9c79b3
commit efdcdf82c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 104 additions and 2 deletions

View file

@ -5,6 +5,7 @@ use std::cmp::Ordering;
use std::collections::HashMap;
use std::collections::HashSet;
use std::path::Path;
use std::str::FromStr;
use std::sync::Arc;
use deno_ast::SourceRange;
@ -55,6 +56,7 @@ use super::language_server;
use super::resolver::LspResolver;
use super::tsc;
use crate::args::jsr_url;
use crate::lsp::urls::uri_to_url;
use crate::tools::lint::CliLinter;
use crate::util::path::relative_specifier;
@ -757,6 +759,43 @@ pub fn fix_ts_import_changes(
Ok(r)
}
pub fn fix_ts_import_changes_for_file_rename(
changes: Vec<tsc::FileTextChanges>,
new_uri: &str,
module: &DocumentModule,
language_server: &language_server::Inner,
token: &CancellationToken,
) -> Result<Vec<tsc::FileTextChanges>, AnyError> {
let Ok(new_uri) = Uri::from_str(new_uri) else {
return Ok(Vec::new());
};
if !new_uri.scheme().is_some_and(|s| s.eq_lowercase("file")) {
return Ok(Vec::new());
}
let new_url = uri_to_url(&new_uri);
let mut r = Vec::with_capacity(changes.len());
for mut change in changes {
if token.is_cancelled() {
return Err(anyhow!("request cancelled"));
}
let Ok(target_specifier) = resolve_url(&change.file_name) else {
continue;
};
let import_mapper = language_server.get_ts_response_import_mapper(module);
for text_change in &mut change.text_changes {
if let Some(new_specifier) = import_mapper
.check_specifier(&new_url, &target_specifier)
.or_else(|| relative_specifier(&target_specifier, &new_url))
.filter(|s| !s.contains("/node_modules/"))
{
text_change.new_text = new_specifier;
}
}
r.push(change);
}
Ok(r)
}
/// Fix tsc import code actions so that the module specifier is correct for
/// resolution by Deno (includes the extension).
fn fix_ts_import_action<'a>(

View file

@ -108,6 +108,7 @@ use crate::file_fetcher::CreateCliFileFetcherOptions;
use crate::file_fetcher::create_cli_file_fetcher;
use crate::graph_util;
use crate::http_util::HttpClientProvider;
use crate::lsp::analysis::fix_ts_import_changes_for_file_rename;
use crate::lsp::compiler_options::LspCompilerOptionsResolver;
use crate::lsp::config::ConfigWatchedFileType;
use crate::lsp::diagnostics::generate_module_diagnostics;
@ -3889,8 +3890,25 @@ impl Inner {
LspError::internal_error()
}
})?;
changes_with_modules
.extend(changes.into_iter().map(|c| (c, module.clone())));
let changes = fix_ts_import_changes_for_file_rename(
changes,
&rename.new_uri,
&module,
self,
token,
)
.map_err(|err| {
if token.is_cancelled() {
LspError::request_cancelled()
} else {
error!("Unable to fix import changes: {:#}", err);
LspError::internal_error()
}
})?;
if !changes.is_empty() {
changes_with_modules
.extend(changes.into_iter().map(|c| (c, module.clone())));
}
}
}
file_text_changes_to_workspace_edit(&changes_with_modules, self, token)

View file

@ -18893,6 +18893,51 @@ console.log(invalid, validBytes, validText);
client.shutdown();
}
/// Regression test for https://github.com/denoland/deno/issues/30380.
#[test]
#[timeout(300_000)]
fn lsp_will_rename_files_js_to_ts() {
let context = TestContextBuilder::new().use_temp_cwd().build();
let temp_dir = context.temp_dir();
temp_dir.write("deno.json", json!({}).to_string());
let file = temp_dir.source_file("main.ts", "import \"./other.js\";\n");
let other_file = temp_dir.source_file("other.js", "");
let mut client = context.new_lsp_command().build();
client.initialize_default();
client.did_open_file(&file);
let res = client.write_request(
"workspace/willRenameFiles",
json!({
"files": [
{
"oldUri": other_file.uri(),
"newUri": temp_dir.path().join("other.ts").uri_file(),
},
],
}),
);
assert_eq!(
res,
json!({
"documentChanges": [
{
"textDocument": { "uri": file.uri(), "version": 1 },
"edits": [
{
"range": {
"start": { "line": 0, "character": 8 },
"end": { "line": 0, "character": 18 },
},
"newText": "./other.ts",
},
],
},
],
}),
);
client.shutdown();
}
#[test]
#[timeout(300_000)]
fn lsp_push_diagnostics() {