summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/lsp/completions.rs37
-rw-r--r--tests/integration/lsp_tests.rs107
2 files changed, 143 insertions, 1 deletions
diff --git a/cli/lsp/completions.rs b/cli/lsp/completions.rs
index a51edcb33..88900ceef 100644
--- a/cli/lsp/completions.rs
+++ b/cli/lsp/completions.rs
@@ -18,6 +18,7 @@ use crate::util::path::is_importable_ext;
use crate::util::path::relative_specifier;
use deno_graph::source::ResolutionMode;
use deno_graph::Range;
+use deno_runtime::deno_node::SUPPORTED_BUILTIN_NODE_MODULES;
use deno_runtime::fs_util::specifier_to_file_path;
use deno_ast::LineAndColumnIndex;
@@ -192,6 +193,8 @@ pub async fn get_import_completions(
get_npm_completions(specifier, &text, &range, npm_search_api).await
{
Some(lsp::CompletionResponse::List(completion_list))
+ } else if let Some(completion_list) = get_node_completions(&text, &range) {
+ Some(lsp::CompletionResponse::List(completion_list))
} else if let Some(completion_list) =
get_import_map_completions(specifier, &text, &range, maybe_import_map)
{
@@ -732,6 +735,40 @@ async fn get_npm_completions(
})
}
+/// Get completions for `node:` specifiers.
+fn get_node_completions(
+ specifier: &str,
+ range: &lsp::Range,
+) -> Option<CompletionList> {
+ if !specifier.starts_with("node:") {
+ return None;
+ }
+ let items = SUPPORTED_BUILTIN_NODE_MODULES
+ .iter()
+ .map(|name| {
+ let specifier = format!("node:{}", name);
+ let text_edit = Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
+ range: *range,
+ new_text: specifier.clone(),
+ }));
+ lsp::CompletionItem {
+ label: specifier,
+ kind: Some(lsp::CompletionItemKind::FILE),
+ detail: Some("(node)".to_string()),
+ text_edit,
+ commit_characters: Some(
+ IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect(),
+ ),
+ ..Default::default()
+ }
+ })
+ .collect();
+ Some(CompletionList {
+ is_incomplete: false,
+ items,
+ })
+}
+
/// Get workspace completions that include modules in the Deno cache which match
/// the current specifier string.
fn get_workspace_completions(
diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs
index cbc175ec6..d89061683 100644
--- a/tests/integration/lsp_tests.rs
+++ b/tests/integration/lsp_tests.rs
@@ -7499,6 +7499,111 @@ fn lsp_npm_completions_auto_import_and_quick_fix_no_import_map() {
}
#[test]
+fn lsp_completions_node_specifier() {
+ let context = TestContextBuilder::new().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.uri().join("file.ts").unwrap(),
+ "languageId": "typescript",
+ "version": 1,
+ "text": "import fs from \"node:as\";\n",
+ },
+ }));
+ let list = client.get_completion_list(
+ temp_dir.uri().join("file.ts").unwrap(),
+ (0, 23),
+ json!({
+ "triggerKind": 2,
+ "triggerCharacter": ".",
+ }),
+ );
+ assert!(!list.is_incomplete);
+ assert_eq!(
+ list
+ .items
+ .iter()
+ .map(|i| i.label.as_str())
+ .collect::<Vec<_>>(),
+ vec![
+ "node:assert",
+ "node:assert/strict",
+ "node:async_hooks",
+ "node:buffer",
+ "node:child_process",
+ "node:cluster",
+ "node:console",
+ "node:constants",
+ "node:crypto",
+ "node:dgram",
+ "node:diagnostics_channel",
+ "node:dns",
+ "node:dns/promises",
+ "node:domain",
+ "node:events",
+ "node:fs",
+ "node:fs/promises",
+ "node:http",
+ "node:http2",
+ "node:https",
+ "node:module",
+ "node:net",
+ "node:os",
+ "node:path",
+ "node:path/posix",
+ "node:path/win32",
+ "node:perf_hooks",
+ "node:process",
+ "node:punycode",
+ "node:querystring",
+ "node:repl",
+ "node:readline",
+ "node:readline/promises",
+ "node:stream",
+ "node:stream/consumers",
+ "node:stream/promises",
+ "node:stream/web",
+ "node:string_decoder",
+ "node:sys",
+ "node:test",
+ "node:timers",
+ "node:timers/promises",
+ "node:tls",
+ "node:tty",
+ "node:url",
+ "node:util",
+ "node:util/types",
+ "node:v8",
+ "node:vm",
+ "node:worker_threads",
+ "node:zlib",
+ ],
+ );
+ for item in &list.items {
+ let specifier = item.label.as_str();
+ assert_eq!(
+ json!(item),
+ json!({
+ "label": specifier,
+ "kind": 17,
+ "detail": "(node)",
+ "textEdit": {
+ "range": {
+ "start": { "line": 0, "character": 16 },
+ "end": { "line": 0, "character": 23 },
+ },
+ "newText": specifier,
+ },
+ "commitCharacters": ["\"", "'"],
+ }),
+ );
+ }
+ client.shutdown();
+}
+
+#[test]
fn lsp_infer_return_type() {
let context = TestContextBuilder::new().use_temp_cwd().build();
let temp_dir = context.temp_dir();
@@ -8614,7 +8719,7 @@ fn lsp_npm_specifier_unopened_file() {
}
#[test]
-fn lsp_completions_node_specifier() {
+fn lsp_completions_node_builtin() {
let context = TestContextBuilder::new()
.use_http_server()
.use_temp_cwd()