1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-18 13:22:55 -05:00

fix(lsp): include "node:" prefix for node builtin auto-imports (#27404)

This commit is contained in:
Nayeem Rahman 2024-12-17 18:55:17 +00:00 committed by GitHub
parent d632ec9e70
commit 2820ba1e22
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 110 additions and 12 deletions

View file

@ -270,6 +270,10 @@ impl<'a> TsResponseImportMapper<'a> {
} }
} }
if specifier.scheme() == "node" {
return Some(specifier.to_string());
}
if let Some(jsr_path) = specifier.as_str().strip_prefix(jsr_url().as_str()) if let Some(jsr_path) = specifier.as_str().strip_prefix(jsr_url().as_str())
{ {
let mut segments = jsr_path.split('/'); let mut segments = jsr_path.split('/');

View file

@ -64,6 +64,7 @@ use deno_core::OpState;
use deno_core::PollEventLoopOptions; use deno_core::PollEventLoopOptions;
use deno_core::RuntimeOptions; use deno_core::RuntimeOptions;
use deno_path_util::url_to_file_path; use deno_path_util::url_to_file_path;
use deno_runtime::deno_node::SUPPORTED_BUILTIN_NODE_MODULES;
use deno_runtime::inspector_server::InspectorServer; use deno_runtime::inspector_server::InspectorServer;
use deno_runtime::tokio_util::create_basic_runtime; use deno_runtime::tokio_util::create_basic_runtime;
use indexmap::IndexMap; use indexmap::IndexMap;
@ -3411,10 +3412,18 @@ fn parse_code_actions(
additional_text_edits.extend(change.text_changes.iter().map(|tc| { additional_text_edits.extend(change.text_changes.iter().map(|tc| {
let mut text_edit = tc.as_text_edit(asset_or_doc.line_index()); let mut text_edit = tc.as_text_edit(asset_or_doc.line_index());
if let Some(specifier_rewrite) = &data.specifier_rewrite { if let Some(specifier_rewrite) = &data.specifier_rewrite {
text_edit.new_text = text_edit.new_text.replace( let specifier_index = text_edit
&specifier_rewrite.old_specifier, .new_text
&specifier_rewrite.new_specifier, .char_indices()
); .find_map(|(b, c)| (c == '\'' || c == '"').then_some(b));
if let Some(i) = specifier_index {
let mut specifier_part = text_edit.new_text.split_off(i);
specifier_part = specifier_part.replace(
&specifier_rewrite.old_specifier,
&specifier_rewrite.new_specifier,
);
text_edit.new_text.push_str(&specifier_part);
}
if let Some(deno_types_specifier) = if let Some(deno_types_specifier) =
&specifier_rewrite.new_deno_types_specifier &specifier_rewrite.new_deno_types_specifier
{ {
@ -3587,10 +3596,17 @@ impl CompletionEntryDetails {
&mut insert_replace_edit.new_text &mut insert_replace_edit.new_text
} }
}; };
*new_text = new_text.replace( let specifier_index = new_text
&specifier_rewrite.old_specifier, .char_indices()
&specifier_rewrite.new_specifier, .find_map(|(b, c)| (c == '\'' || c == '"').then_some(b));
); if let Some(i) = specifier_index {
let mut specifier_part = new_text.split_off(i);
specifier_part = specifier_part.replace(
&specifier_rewrite.old_specifier,
&specifier_rewrite.new_specifier,
);
new_text.push_str(&specifier_part);
}
if let Some(deno_types_specifier) = if let Some(deno_types_specifier) =
&specifier_rewrite.new_deno_types_specifier &specifier_rewrite.new_deno_types_specifier
{ {
@ -3729,7 +3745,7 @@ pub struct CompletionItemData {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct CompletionEntryDataAutoImport { struct CompletionEntryDataAutoImport {
module_specifier: String, module_specifier: String,
file_name: String, file_name: Option<String>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -3786,9 +3802,20 @@ impl CompletionEntry {
else { else {
return; return;
}; };
if let Ok(normalized) = specifier_map.normalize(&raw.file_name) { if let Some(file_name) = &raw.file_name {
self.auto_import_data = if let Ok(normalized) = specifier_map.normalize(file_name) {
Some(CompletionNormalizedAutoImportData { raw, normalized }); self.auto_import_data =
Some(CompletionNormalizedAutoImportData { raw, normalized });
}
} else if SUPPORTED_BUILTIN_NODE_MODULES
.contains(&raw.module_specifier.as_str())
{
if let Ok(normalized) =
resolve_url(&format!("node:{}", &raw.module_specifier))
{
self.auto_import_data =
Some(CompletionNormalizedAutoImportData { raw, normalized });
}
} }
} }

View file

@ -7960,6 +7960,73 @@ fn lsp_completions_auto_import() {
client.shutdown(); client.shutdown();
} }
#[test]
fn lsp_completions_auto_import_node_builtin() {
let context = TestContextBuilder::new()
.use_http_server()
.use_temp_cwd()
.build();
let temp_dir = context.temp_dir();
let mut client = context.new_lsp_command().build();
client.initialize_default();
client.did_open(json!({
"textDocument": {
"uri": temp_dir.url().join("file.ts").unwrap(),
"languageId": "typescript",
"version": 1,
"text": r#"
import "npm:@types/node";
pathToFileURL
"#,
}
}));
client.write_request(
"workspace/executeCommand",
json!({
"command": "deno.cache",
"arguments": [[], temp_dir.url().join("file.ts").unwrap()],
}),
);
let list = client.get_completion_list(
temp_dir.url().join("file.ts").unwrap(),
(2, 21),
json!({ "triggerKind": 2 }),
);
assert!(!list.is_incomplete);
let item = list
.items
.iter()
.find(|item| item.label == "pathToFileURL")
.unwrap();
let res = client.write_request("completionItem/resolve", json!(item));
assert_eq!(
res,
json!({
"label": "pathToFileURL",
"labelDetails": {
"description": "node:url",
},
"kind": 3,
"detail": "function pathToFileURL(path: string, options?: PathToFileUrlOptions): URL",
"documentation": {
"kind": "markdown",
"value": "This function ensures that `path` is resolved absolutely, and that the URL\ncontrol characters are correctly encoded when converting into a File URL.\n\n```js\nimport { pathToFileURL } from 'node:url';\n\nnew URL('/foo#1', 'file:'); // Incorrect: file:///foo#1\npathToFileURL('/foo#1'); // Correct: file:///foo#1 (POSIX)\n\nnew URL('/some/path%.c', 'file:'); // Incorrect: file:///some/path%.c\npathToFileURL('/some/path%.c'); // Correct: file:///some/path%.c (POSIX)\n```\n\n*@since* - v10.12.0 \n\n*@param* - path The path to convert to a File URL. \n\n*@return* - The file URL object.",
},
"sortText": "￿16_1",
"additionalTextEdits": [
{
"range": {
"start": { "line": 2, "character": 0 },
"end": { "line": 2, "character": 0 },
},
"newText": " import { pathToFileURL } from \"node:url\";\n",
},
],
}),
);
client.shutdown();
}
#[test] #[test]
fn lsp_npm_completions_auto_import_and_quick_fix_no_import_map() { fn lsp_npm_completions_auto_import_and_quick_fix_no_import_map() {
let context = TestContextBuilder::new() let context = TestContextBuilder::new()