summaryrefslogtreecommitdiff
path: root/cli/tests/integration/lsp_tests.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tests/integration/lsp_tests.rs')
-rw-r--r--cli/tests/integration/lsp_tests.rs4396
1 files changed, 2837 insertions, 1559 deletions
diff --git a/cli/tests/integration/lsp_tests.rs b/cli/tests/integration/lsp_tests.rs
index 9a62e42a3..344ba0804 100644
--- a/cli/tests/integration/lsp_tests.rs
+++ b/cli/tests/integration/lsp_tests.rs
@@ -1,7 +1,6 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use deno_ast::ModuleSpecifier;
-use deno_core::serde::de::DeserializeOwned;
use deno_core::serde::Deserialize;
use deno_core::serde::Serialize;
use deno_core::serde_json;
@@ -13,42 +12,13 @@ use std::collections::HashSet;
use std::fs;
use std::process::Stdio;
use test_util::deno_cmd_with_deno_dir;
-use test_util::deno_exe_path;
use test_util::env_vars_for_npm_tests;
-use test_util::http_server;
use test_util::lsp::LspClient;
+use test_util::lsp::LspClientBuilder;
use test_util::testdata_path;
-use test_util::TempDir;
+use test_util::TestContextBuilder;
use tower_lsp::lsp_types as lsp;
-fn load_fixture(path: &str) -> Value {
- load_fixture_as(path)
-}
-
-fn load_fixture_as<T>(path: &str) -> T
-where
- T: DeserializeOwned,
-{
- let fixture_str = load_fixture_str(path);
- serde_json::from_str::<T>(&fixture_str).unwrap()
-}
-
-fn load_fixture_str(path: &str) -> String {
- let fixtures_path = testdata_path().join("lsp");
- let path = fixtures_path.join(path);
- fs::read_to_string(path).unwrap()
-}
-
-fn init(init_path: &str) -> LspClient {
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", load_fixture(init_path))
- .unwrap();
- client.write_notification("initialized", json!({})).unwrap();
- client
-}
-
fn did_open<V>(
client: &mut LspClient,
params: V,
@@ -91,34 +61,13 @@ fn read_diagnostics(client: &mut LspClient) -> CollectedDiagnostics {
CollectedDiagnostics(diagnostics)
}
-fn shutdown(client: &mut LspClient) {
- client
- .write_request::<_, _, Value>("shutdown", json!(null))
- .unwrap();
- client.write_notification("exit", json!(null)).unwrap();
-}
-
-pub fn ensure_directory_specifier(
- mut specifier: ModuleSpecifier,
-) -> ModuleSpecifier {
- let path = specifier.path();
- if !path.ends_with('/') {
- let new_path = format!("{path}/");
- specifier.set_path(&new_path);
- }
- specifier
-}
-
+// todo(dsherret): get rid of this in favour of LspClient
struct TestSession {
client: LspClient,
open_file_count: usize,
}
impl TestSession {
- pub fn from_file(init_path: &str) -> Self {
- Self::from_client(init(init_path))
- }
-
pub fn from_client(client: LspClient) -> Self {
Self {
client,
@@ -163,7 +112,7 @@ impl TestSession {
}
pub fn shutdown_and_exit(&mut self) {
- shutdown(&mut self.client);
+ self.client.shutdown();
}
}
@@ -230,32 +179,29 @@ impl CollectedDiagnostics {
#[test]
fn lsp_startup_shutdown() {
- let mut client = init("initialize_params.json");
- shutdown(&mut client);
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
+ client.shutdown();
}
#[test]
fn lsp_init_tsconfig() {
- let temp_dir = TempDir::new();
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
- let tsconfig =
- serde_json::to_vec_pretty(&load_fixture("lib.tsconfig.json")).unwrap();
- fs::write(temp_dir.path().join("lib.tsconfig.json"), tsconfig).unwrap();
-
- params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap());
- if let Some(Value::Object(mut map)) = params.initialization_options {
- map.insert("config".to_string(), json!("./lib.tsconfig.json"));
- params.initialization_options = Some(Value::Object(map));
- }
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
+ temp_dir.write(
+ "lib.tsconfig.json",
+ r#"{
+ "compilerOptions": {
+ "lib": ["deno.ns", "deno.unstable", "dom"]
+ }
+}"#,
+ );
- client.write_notification("initialized", json!({})).unwrap();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_config("lib.tsconfig.json");
+ });
let diagnostics = did_open(
&mut client,
@@ -272,33 +218,34 @@ fn lsp_init_tsconfig() {
let diagnostics = diagnostics.into_iter().flat_map(|x| x.diagnostics);
assert_eq!(diagnostics.count(), 0);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_tsconfig_types() {
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
- let temp_dir = TempDir::new();
- let tsconfig =
- serde_json::to_vec_pretty(&load_fixture("types.tsconfig.json")).unwrap();
- fs::write(temp_dir.path().join("types.tsconfig.json"), tsconfig).unwrap();
- let a_dts = load_fixture_str("a.d.ts");
- fs::write(temp_dir.path().join("a.d.ts"), a_dts).unwrap();
-
- params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap());
- if let Some(Value::Object(mut map)) = params.initialization_options {
- map.insert("config".to_string(), json!("./types.tsconfig.json"));
- params.initialization_options = Some(Value::Object(map));
- }
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
+ temp_dir.write(
+ "types.tsconfig.json",
+ r#"{
+ "compilerOptions": {
+ "types": ["./a.d.ts"]
+ },
+ "lint": {
+ "rules": {
+ "tags": []
+ }
+ }
+}"#,
+ );
+ let a_dts = "// deno-lint-ignore-file no-var\ndeclare var a: string;";
+ temp_dir.write("a.d.ts", a_dts);
- client.write_notification("initialized", json!({})).unwrap();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_config("types.tsconfig.json");
+ });
let diagnostics = did_open(
&mut client,
@@ -315,12 +262,17 @@ fn lsp_tsconfig_types() {
let diagnostics = diagnostics.into_iter().flat_map(|x| x.diagnostics);
assert_eq!(diagnostics.count(), 0);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_tsconfig_bad_config_path() {
- let mut client = init("initialize_params_bad_config_option.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize(|builder| {
+ builder
+ .set_config("bad_tsconfig.json")
+ .set_maybe_root_uri(None);
+ });
let (method, maybe_params) = client.read_notification().unwrap();
assert_eq!(method, "window/showMessage");
assert_eq!(maybe_params, Some(lsp::ShowMessageParams {
@@ -344,27 +296,18 @@ fn lsp_tsconfig_bad_config_path() {
#[test]
fn lsp_triple_slash_types() {
- let temp_dir = TempDir::new();
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
- let a_dts = load_fixture_str("a.d.ts");
- fs::write(temp_dir.path().join("a.d.ts"), a_dts).unwrap();
-
- params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap());
-
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
-
- client.write_notification("initialized", json!({})).unwrap();
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
+ let a_dts = "// deno-lint-ignore-file no-var\ndeclare var a: string;";
+ temp_dir.write("a.d.ts", a_dts);
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
let diagnostics = did_open(
&mut client,
json!({
"textDocument": {
- "uri": Url::from_file_path(temp_dir.path().join("test.ts")).unwrap(),
+ "uri": temp_dir.uri().join("test.ts").unwrap(),
"languageId": "typescript",
"version": 1,
"text": "/// <reference types=\"./a.d.ts\" />\n\nconsole.log(a);\n"
@@ -375,37 +318,27 @@ fn lsp_triple_slash_types() {
let diagnostics = diagnostics.into_iter().flat_map(|x| x.diagnostics);
assert_eq!(diagnostics.count(), 0);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_import_map() {
- let temp_dir = TempDir::new();
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
- let import_map =
- serde_json::to_vec_pretty(&load_fixture("import-map.json")).unwrap();
- fs::write(temp_dir.path().join("import-map.json"), import_map).unwrap();
- fs::create_dir(temp_dir.path().join("lib")).unwrap();
- fs::write(
- temp_dir.path().join("lib").join("b.ts"),
- r#"export const b = "b";"#,
- )
- .unwrap();
-
- params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap());
- if let Some(Value::Object(mut map)) = params.initialization_options {
- map.insert("importMap".to_string(), json!("import-map.json"));
- params.initialization_options = Some(Value::Object(map));
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
+ let import_map = r#"{
+ "imports": {
+ "/~/": "./lib/"
}
+}"#;
+ temp_dir.write("import-map.json", import_map);
+ temp_dir.create_dir_all("lib");
+ temp_dir.write("lib/b.ts", r#"export const b = "b";"#);
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_import_map("import-map.json");
+ });
- client.write_notification("initialized", json!({})).unwrap();
let uri = Url::from_file_path(temp_dir.path().join("a.ts")).unwrap();
let diagnostics = did_open(
@@ -430,10 +363,7 @@ fn lsp_import_map() {
"textDocument": {
"uri": uri
},
- "position": {
- "line": 2,
- "character": 12
- }
+ "position": { "line": 2, "character": 12 }
}),
)
.unwrap();
@@ -449,23 +379,21 @@ fn lsp_import_map() {
""
],
"range": {
- "start": {
- "line": 2,
- "character": 12
- },
- "end": {
- "line": 2,
- "character": 13
- }
+ "start": { "line": 2, "character": 12 },
+ "end": { "line": 2, "character": 13 }
}
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_import_map_data_url() {
- let mut client = init("initialize_params_import_map.json");
+ let context = TestContextBuilder::new().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_import_map("data:application/json;utf8,{\"imports\": { \"example\": \"https://deno.land/x/example/mod.ts\" }}");
+ });
let diagnostics = did_open(
&mut client,
json!({
@@ -479,49 +407,42 @@ fn lsp_import_map_data_url() {
);
let mut diagnostics = diagnostics.into_iter().flat_map(|x| x.diagnostics);
- // This indicates that the import map from initialize_params_import_map.json
- // is applied correctly.
+ // This indicates that the import map is applied correctly.
assert!(diagnostics.any(|diagnostic| diagnostic.code
== Some(lsp::NumberOrString::String("no-cache".to_string()))
&& diagnostic
.message
.contains("https://deno.land/x/example/mod.ts")));
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_import_map_config_file() {
- let temp_dir = TempDir::new();
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
-
- let deno_import_map_jsonc =
- serde_json::to_vec_pretty(&load_fixture("deno.import_map.jsonc")).unwrap();
- fs::write(
- temp_dir.path().join("deno.import_map.jsonc"),
- deno_import_map_jsonc,
- )
- .unwrap();
-
- params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap());
- if let Some(Value::Object(mut map)) = params.initialization_options {
- map.insert("config".to_string(), json!("./deno.import_map.jsonc"));
- params.initialization_options = Some(Value::Object(map));
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
+ temp_dir.write(
+ "deno.import_map.jsonc",
+ r#"{
+ "importMap": "import-map.json"
+}"#,
+ );
+ temp_dir.write(
+ "import-map.json",
+ r#"{
+ "imports": {
+ "/~/": "./lib/"
}
- let import_map_text =
- serde_json::to_string_pretty(&load_fixture("import-map.json")).unwrap();
- temp_dir.write("import-map.json", import_map_text);
+}"#,
+ );
temp_dir.create_dir_all("lib");
temp_dir.write("lib/b.ts", r#"export const b = "b";"#);
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_config("./deno.import_map.jsonc");
+ });
- client.write_notification("initialized", json!({})).unwrap();
- let uri = Url::from_file_path(temp_dir.path().join("a.ts")).unwrap();
+ let uri = temp_dir.uri().join("a.ts").unwrap();
let diagnostics = did_open(
&mut client,
@@ -545,10 +466,7 @@ fn lsp_import_map_config_file() {
"textDocument": {
"uri": uri
},
- "position": {
- "line": 2,
- "character": 12
- }
+ "position": { "line": 2, "character": 12 }
}),
)
.unwrap();
@@ -564,51 +482,35 @@ fn lsp_import_map_config_file() {
""
],
"range": {
- "start": {
- "line": 2,
- "character": 12
- },
- "end": {
- "line": 2,
- "character": 13
- }
+ "start": { "line": 2, "character": 12 },
+ "end": { "line": 2, "character": 13 }
}
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_import_map_embedded_in_config_file() {
- let temp_dir = TempDir::new();
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
-
- let deno_import_map_jsonc = serde_json::to_string_pretty(&load_fixture(
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
+ temp_dir.write(
"deno.embedded_import_map.jsonc",
- ))
- .unwrap();
- temp_dir.write("deno.embedded_import_map.jsonc", deno_import_map_jsonc);
-
- params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap());
- if let Some(Value::Object(mut map)) = params.initialization_options {
- map.insert(
- "config".to_string(),
- json!("./deno.embedded_import_map.jsonc"),
- );
- params.initialization_options = Some(Value::Object(map));
+ r#"{
+ "imports": {
+ "/~/": "./lib/"
}
- fs::create_dir(temp_dir.path().join("lib")).unwrap();
+}"#,
+ );
+ temp_dir.create_dir_all("lib");
temp_dir.write("lib/b.ts", r#"export const b = "b";"#);
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_config("./deno.embedded_import_map.jsonc");
+ });
- client.write_notification("initialized", json!({})).unwrap();
- let uri = Url::from_file_path(temp_dir.path().join("a.ts")).unwrap();
+ let uri = temp_dir.uri().join("a.ts").unwrap();
let diagnostics = did_open(
&mut client,
@@ -632,10 +534,7 @@ fn lsp_import_map_embedded_in_config_file() {
"textDocument": {
"uri": uri
},
- "position": {
- "line": 2,
- "character": 12
- }
+ "position": { "line": 2, "character": 12 }
}),
)
.unwrap();
@@ -651,44 +550,32 @@ fn lsp_import_map_embedded_in_config_file() {
""
],
"range": {
- "start": {
- "line": 2,
- "character": 12
- },
- "end": {
- "line": 2,
- "character": 13
- }
+ "start": { "line": 2, "character": 12 },
+ "end": { "line": 2, "character": 13 }
}
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_deno_task() {
- let temp_dir = TempDir::new();
- let workspace_root = temp_dir.path().canonicalize().unwrap();
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
- fs::write(
- workspace_root.join("deno.jsonc"),
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
+ temp_dir.write(
+ "deno.jsonc",
r#"{
"tasks": {
"build": "deno test",
"some:test": "deno bundle mod.ts"
}
}"#,
- )
- .unwrap();
+ );
- params.root_uri = Some(Url::from_file_path(workspace_root).unwrap());
-
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_config("./deno.jsonc");
+ });
let (maybe_res, maybe_err) = client
.write_request::<_, _, Value>("deno/task", json!(null))
@@ -701,8 +588,7 @@ fn lsp_deno_task() {
{
"name": "build",
"detail": "deno test"
- },
- {
+ }, {
"name": "some:test",
"detail": "deno bundle mod.ts"
}
@@ -712,7 +598,12 @@ fn lsp_deno_task() {
#[test]
fn lsp_import_assertions() {
- let mut client = init("initialize_params_import_map.json");
+ let context = TestContextBuilder::new().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_import_map("data:application/json;utf8,{\"imports\": { \"example\": \"https://deno.land/x/example/mod.ts\" }}");
+ });
+
client
.write_notification(
"textDocument/didOpen",
@@ -757,14 +648,8 @@ fn lsp_import_assertions() {
json!([
{
"range": {
- "start": {
- "line": 0,
- "character": 14
- },
- "end": {
- "line": 0,
- "character": 27
- }
+ "start": { "line": 0, "character": 14 },
+ "end": { "line": 0, "character": 27 }
},
"severity": 1,
"code": "no-assert-type",
@@ -777,47 +662,89 @@ fn lsp_import_assertions() {
let (maybe_res, maybe_err) = client
.write_request(
"textDocument/codeAction",
- load_fixture("code_action_params_import_assertion.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/a.ts"
+ },
+ "range": {
+ "start": { "line": 0, "character": 14 },
+ "end": { "line": 0, "character": 27 }
+ },
+ "context": {
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 0, "character": 14 },
+ "end": { "line": 0, "character": 27 }
+ },
+ "severity": 1,
+ "code": "no-assert-type",
+ "source": "deno",
+ "message": "The module is a JSON module and not being imported with an import assertion. Consider adding `assert { type: \"json\" }` to the import statement."
+ }],
+ "only": ["quickfix"]
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_action_response_import_assertion.json"))
+ Some(json!([{
+ "title": "Insert import assertion.",
+ "kind": "quickfix",
+ "diagnostics": [
+ {
+ "range": {
+ "start": { "line": 0, "character": 14 },
+ "end": { "line": 0, "character": 27 }
+ },
+ "severity": 1,
+ "code": "no-assert-type",
+ "source": "deno",
+ "message": "The module is a JSON module and not being imported with an import assertion. Consider adding `assert { type: \"json\" }` to the import statement."
+ }
+ ],
+ "edit": {
+ "changes": {
+ "file:///a/a.ts": [
+ {
+ "range": {
+ "start": { "line": 0, "character": 27 },
+ "end": { "line": 0, "character": 27 }
+ },
+ "newText": " assert { type: \"json\" }"
+ }
+ ]
+ }
+ }
+ }]))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_import_map_import_completions() {
- let temp_dir = TempDir::new();
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
- let import_map =
- serde_json::to_vec_pretty(&load_fixture("import-map-completions.json"))
- .unwrap();
- fs::write(temp_dir.path().join("import-map.json"), import_map).unwrap();
- fs::create_dir(temp_dir.path().join("lib")).unwrap();
- fs::write(
- temp_dir.path().join("lib").join("b.ts"),
- r#"export const b = "b";"#,
- )
- .unwrap();
-
- params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap());
- if let Some(Value::Object(mut map)) = params.initialization_options {
- map.insert("importMap".to_string(), json!("import-map.json"));
- params.initialization_options = Some(Value::Object(map));
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
+ temp_dir.write(
+ "import-map.json",
+ r#"{
+ "imports": {
+ "/~/": "./lib/",
+ "fs": "https://example.com/fs/index.js",
+ "std/": "https://example.com/std@0.123.0/"
}
+}"#,
+ );
+ temp_dir.create_dir_all("lib");
+ temp_dir.write("lib/b.ts", r#"export const b = "b";"#);
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_import_map("import-map.json");
+ });
- client.write_notification("initialized", json!({})).unwrap();
- let uri = Url::from_file_path(temp_dir.path().join("a.ts")).unwrap();
+ let uri = temp_dir.uri().join("a.ts").unwrap();
did_open(
&mut client,
@@ -838,10 +765,7 @@ fn lsp_import_map_import_completions() {
"textDocument": {
"uri": uri
},
- "position": {
- "line": 1,
- "character": 20
- },
+ "position": { "line": 1, "character": 20 },
"context": {
"triggerKind": 2,
"triggerCharacter": "\""
@@ -862,32 +786,28 @@ fn lsp_import_map_import_completions() {
"sortText": "1",
"insertText": ".",
"commitCharacters": ["\"", "'"],
- },
- {
+ }, {
"label": "..",
"kind": 19,
"detail": "(local)",
"sortText": "1",
"insertText": "..",
"commitCharacters": ["\"", "'"],
- },
- {
+ }, {
"label": "std",
"kind": 19,
"detail": "(import map)",
"sortText": "std",
"insertText": "std",
"commitCharacters": ["\"", "'"],
- },
- {
+ }, {
"label": "fs",
"kind": 17,
"detail": "(import map)",
"sortText": "fs",
"insertText": "fs",
"commitCharacters": ["\"", "'"],
- },
- {
+ }, {
"label": "/~",
"kind": 19,
"detail": "(import map)",
@@ -910,14 +830,8 @@ fn lsp_import_map_import_completions() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 1,
- "character": 20
- },
- "end": {
- "line": 1,
- "character": 20
- }
+ "start": { "line": 1, "character": 20 },
+ "end": { "line": 1, "character": 20 }
},
"text": "/~/"
}
@@ -939,10 +853,7 @@ fn lsp_import_map_import_completions() {
"textDocument": {
"uri": uri
},
- "position": {
- "line": 1,
- "character": 23
- },
+ "position": { "line": 1, "character": 23 },
"context": {
"triggerKind": 2,
"triggerCharacter": "/"
@@ -964,14 +875,8 @@ fn lsp_import_map_import_completions() {
"filterText": "/~/b.ts",
"textEdit": {
"range": {
- "start": {
- "line": 1,
- "character": 20
- },
- "end": {
- "line": 1,
- "character": 23
- }
+ "start": { "line": 1, "character": 20 },
+ "end": { "line": 1, "character": 23 }
},
"newText": "/~/b.ts"
},
@@ -981,12 +886,13 @@ fn lsp_import_map_import_completions() {
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_hover() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -1005,10 +911,7 @@ fn lsp_hover() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 19
- }
+ "position": { "line": 0, "character": 19 }
}),
)
.unwrap();
@@ -1025,23 +928,18 @@ fn lsp_hover() {
"\n\n*@category* - Runtime Environment",
],
"range": {
- "start": {
- "line": 0,
- "character": 17
- },
- "end": {
- "line": 0,
- "character": 21
- }
+ "start": { "line": 0, "character": 17 },
+ "end": { "line": 0, "character": 21 }
}
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_hover_asset() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -1060,10 +958,7 @@ fn lsp_hover_asset() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 14
- }
+ "position": { "line": 0, "character": 14 }
}),
)
.unwrap();
@@ -1086,10 +981,7 @@ fn lsp_hover_asset() {
"textDocument": {
"uri": "deno:/asset/lib.es2015.symbol.wellknown.d.ts"
},
- "position": {
- "line": 109,
- "character": 13
- }
+ "position": { "line": 109, "character": 13 }
}),
)
.unwrap();
@@ -1105,23 +997,21 @@ fn lsp_hover_asset() {
"Enables basic storage and retrieval of dates and times."
],
"range": {
- "start": {
- "line": 109,
- "character": 10,
- },
- "end": {
- "line": 109,
- "character": 14,
- }
+ "start": { "line": 109, "character": 10, },
+ "end": { "line": 109, "character": 14, }
}
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_hover_disabled() {
- let mut client = init("initialize_params_disabled.json");
+ let context = TestContextBuilder::new().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_deno_enable(false);
+ });
client
.write_notification(
"textDocument/didOpen",
@@ -1145,21 +1035,22 @@ fn lsp_hover_disabled() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 19
- }
+ "position": { "line": 0, "character": 19 }
}),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(maybe_res, Some(json!(null)));
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_inlay_hints() {
- let mut client = init("initialize_params_hints.json");
+ let context = TestContextBuilder::new().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.enable_inlay_hints();
+ });
did_open(
&mut client,
json!({
@@ -1198,14 +1089,8 @@ fn lsp_inlay_hints() {
"uri": "file:///a/file.ts",
},
"range": {
- "start": {
- "line": 0,
- "character": 0
- },
- "end": {
- "line": 19,
- "character": 0,
- }
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 19, "character": 0, }
}
}),
)
@@ -1215,90 +1100,51 @@ fn lsp_inlay_hints() {
json!(maybe_res),
json!([
{
- "position": {
- "line": 0,
- "character": 21
- },
+ "position": { "line": 0, "character": 21 },
"label": ": string",
"kind": 1,
"paddingLeft": true
- },
- {
- "position": {
- "line": 4,
- "character": 10
- },
+ }, {
+ "position": { "line": 4, "character": 10 },
"label": "b:",
"kind": 2,
"paddingRight": true
- },
- {
- "position": {
- "line": 7,
- "character": 11
- },
+ }, {
+ "position": { "line": 7, "character": 11 },
"label": "= 0",
"paddingLeft": true
- },
- {
- "position": {
- "line": 10,
- "character": 17
- },
+ }, {
+ "position": { "line": 10, "character": 17 },
"label": "string:",
"kind": 2,
"paddingRight": true
- },
- {
- "position": {
- "line": 10,
- "character": 24
- },
+ }, {
+ "position": { "line": 10, "character": 24 },
"label": "radix:",
"kind": 2,
"paddingRight": true
- },
- {
- "position": {
- "line": 12,
- "character": 15
- },
+ }, {
+ "position": { "line": 12, "character": 15 },
"label": ": number",
"kind": 1,
"paddingLeft": true
- },
- {
- "position": {
- "line": 15,
- "character": 11
- },
+ }, {
+ "position": { "line": 15, "character": 11 },
"label": ": number",
"kind": 1,
"paddingLeft": true
- },
- {
- "position": {
- "line": 18,
- "character": 18
- },
+ }, {
+ "position": { "line": 18, "character": 18 },
"label": "callbackfn:",
"kind": 2,
"paddingRight": true
- },
- {
- "position": {
- "line": 18,
- "character": 20
- },
+ }, {
+ "position": { "line": 18, "character": 20 },
"label": ": string",
"kind": 1,
"paddingLeft": true
- },
- {
- "position": {
- "line": 18,
- "character": 21
- },
+ }, {
+ "position": { "line": 18, "character": 21 },
"label": ": string",
"kind": 1,
"paddingLeft": true
@@ -1309,7 +1155,8 @@ fn lsp_inlay_hints() {
#[test]
fn lsp_inlay_hints_not_enabled() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -1348,14 +1195,8 @@ fn lsp_inlay_hints_not_enabled() {
"uri": "file:///a/file.ts",
},
"range": {
- "start": {
- "line": 0,
- "character": 0
- },
- "end": {
- "line": 19,
- "character": 0,
- }
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 19, "character": 0, }
}
}),
)
@@ -1366,39 +1207,31 @@ fn lsp_inlay_hints_not_enabled() {
#[test]
fn lsp_workspace_enable_paths() {
- let mut params: lsp::InitializeParams = serde_json::from_value(load_fixture(
- "initialize_params_workspace_enable_paths.json",
- ))
- .unwrap();
+ let context = TestContextBuilder::new().build();
// we aren't actually writing anything to the tempdir in this test, but we
// just need a legitimate file path on the host system so that logic that
// tries to convert to and from the fs paths works on all env
- let temp_dir = TempDir::new();
-
- let root_specifier =
- ensure_directory_specifier(Url::from_file_path(temp_dir.path()).unwrap());
-
- params.root_uri = Some(root_specifier.clone());
- params.workspace_folders = Some(vec![lsp::WorkspaceFolder {
- uri: root_specifier.clone(),
- name: "project".to_string(),
- }]);
-
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
-
- client.write_notification("initialized", json!({})).unwrap();
+ let temp_dir = context.deno_dir();
+
+ let root_specifier = temp_dir.uri();
+
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder
+ .set_enable_paths(vec!["./worker".to_string()])
+ .set_root_uri(root_specifier.clone())
+ .set_workspace_folders(vec![lsp::WorkspaceFolder {
+ uri: root_specifier.clone(),
+ name: "project".to_string(),
+ }])
+ .set_deno_enable(false);
+ });
handle_configuration_request(
&mut client,
json!([{
"enable": false,
- "enablePaths": [
- "./worker"
- ],
+ "enablePaths": ["./worker"],
}]),
);
@@ -1457,10 +1290,7 @@ fn lsp_workspace_enable_paths() {
"textDocument": {
"uri": root_specifier.join("./file.ts").unwrap(),
},
- "position": {
- "line": 0,
- "character": 19
- }
+ "position": { "line": 0, "character": 19 }
}),
)
.unwrap();
@@ -1474,10 +1304,7 @@ fn lsp_workspace_enable_paths() {
"textDocument": {
"uri": root_specifier.join("./other/file.ts").unwrap(),
},
- "position": {
- "line": 0,
- "character": 19
- }
+ "position": { "line": 0, "character": 19 }
}),
)
.unwrap();
@@ -1491,10 +1318,7 @@ fn lsp_workspace_enable_paths() {
"textDocument": {
"uri": root_specifier.join("./worker/file.ts").unwrap(),
},
- "position": {
- "line": 0,
- "character": 19
- }
+ "position": { "line": 0, "character": 19 }
}),
)
.unwrap();
@@ -1510,14 +1334,8 @@ fn lsp_workspace_enable_paths() {
"Returns the number of milliseconds elapsed since midnight, January 1, 1970 Universal Coordinated Time (UTC)."
],
"range": {
- "start": {
- "line": 0,
- "character": 17,
- },
- "end": {
- "line": 0,
- "character": 20,
- }
+ "start": { "line": 0, "character": 17, },
+ "end": { "line": 0, "character": 20, }
}
}))
);
@@ -1529,10 +1347,7 @@ fn lsp_workspace_enable_paths() {
"textDocument": {
"uri": root_specifier.join("./worker/subdir/file.ts").unwrap(),
},
- "position": {
- "line": 0,
- "character": 19
- }
+ "position": { "line": 0, "character": 19 }
}),
)
.unwrap();
@@ -1548,24 +1363,19 @@ fn lsp_workspace_enable_paths() {
"Returns the number of milliseconds elapsed since midnight, January 1, 1970 Universal Coordinated Time (UTC)."
],
"range": {
- "start": {
- "line": 0,
- "character": 17,
- },
- "end": {
- "line": 0,
- "character": 20,
- }
+ "start": { "line": 0, "character": 17, },
+ "end": { "line": 0, "character": 20, }
}
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_hover_unstable_disabled() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -1584,10 +1394,7 @@ fn lsp_hover_unstable_disabled() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 19
- }
+ "position": { "line": 0, "character": 19 }
}),
)
.unwrap();
@@ -1602,23 +1409,20 @@ fn lsp_hover_unstable_disabled() {
}
],
"range": {
- "start": {
- "line": 0,
- "character": 17
- },
- "end": {
- "line": 0,
- "character": 23
- }
+ "start": { "line": 0, "character": 17 },
+ "end": { "line": 0, "character": 23 }
}
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_hover_unstable_enabled() {
- let mut client = init("initialize_params_unstable.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize(|builder| {
+ builder.set_unstable(true);
+ });
did_open(
&mut client,
json!({
@@ -1637,10 +1441,7 @@ fn lsp_hover_unstable_enabled() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 19
- }
+ "position": { "line": 0, "character": 19 }
}),
)
.unwrap();
@@ -1657,23 +1458,18 @@ fn lsp_hover_unstable_enabled() {
"\n\n*@category* - Runtime Environment",
],
"range":{
- "start":{
- "line":0,
- "character":17
- },
- "end":{
- "line":0,
- "character":21
- }
+ "start":{ "line":0, "character":17 },
+ "end":{ "line":0, "character":21 }
}
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_hover_change_mbc() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -1696,10 +1492,7 @@ fn lsp_hover_change_mbc() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 1,
- "character": 11
- },
+ "start": { "line": 1, "character": 11 },
"end": {
"line": 1,
// the LSP uses utf16 encoded characters indexes, so
@@ -1726,10 +1519,7 @@ fn lsp_hover_change_mbc() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 2,
- "character": 15
- }
+ "position": { "line": 2, "character": 15 }
}),
)
.unwrap();
@@ -1745,35 +1535,27 @@ fn lsp_hover_change_mbc() {
"",
],
"range": {
- "start": {
- "line": 2,
- "character": 15,
- },
- "end": {
- "line": 2,
- "character": 16,
- },
+ "start": { "line": 2, "character": 15, },
+ "end": { "line": 2, "character": 16, },
}
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_hover_closed_document() {
- let temp_dir_guard = TempDir::new();
- let temp_dir = temp_dir_guard.path();
- let a_path = temp_dir.join("a.ts");
- fs::write(a_path, r#"export const a = "a";"#).unwrap();
- let b_path = temp_dir.join("b.ts");
- fs::write(&b_path, r#"export * from "./a.ts";"#).unwrap();
- let b_specifier = Url::from_file_path(b_path).unwrap();
- let c_path = temp_dir.join("c.ts");
- fs::write(&c_path, "import { a } from \"./b.ts\";\nconsole.log(a);\n")
- .unwrap();
- let c_specifier = Url::from_file_path(c_path).unwrap();
-
- let mut client = init("initialize_params.json");
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
+ temp_dir.write("a.ts", r#"export const a = "a";"#);
+ temp_dir.write("b.ts", r#"export * from "./a.ts";"#);
+ temp_dir.write("c.ts", "import { a } from \"./b.ts\";\nconsole.log(a);\n");
+
+ let b_specifier = temp_dir.uri().join("b.ts").unwrap();
+ let c_specifier = temp_dir.uri().join("c.ts").unwrap();
+
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
client
.write_notification(
"textDocument/didOpen",
@@ -1825,10 +1607,7 @@ fn lsp_hover_closed_document() {
"textDocument": {
"uri": c_specifier,
},
- "position": {
- "line": 0,
- "character": 10
- }
+ "position": { "line": 0, "character": 10 }
}),
)
.unwrap();
@@ -1844,14 +1623,8 @@ fn lsp_hover_closed_document() {
""
],
"range": {
- "start": {
- "line": 0,
- "character": 9
- },
- "end": {
- "line": 0,
- "character": 10
- }
+ "start": { "line": 0, "character": 9 },
+ "end": { "line": 0, "character": 10 }
}
}))
);
@@ -1872,10 +1645,7 @@ fn lsp_hover_closed_document() {
"textDocument": {
"uri": c_specifier,
},
- "position": {
- "line": 0,
- "character": 10
- }
+ "position": { "line": 0, "character": 10 }
}),
)
.unwrap();
@@ -1891,24 +1661,19 @@ fn lsp_hover_closed_document() {
""
],
"range": {
- "start": {
- "line": 0,
- "character": 9
- },
- "end": {
- "line": 0,
- "character": 10
- }
+ "start": { "line": 0, "character": 9 },
+ "end": { "line": 0, "character": 10 }
}
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_hover_dependency() {
- let _g = http_server();
- let mut client = init("initialize_params.json");
+ let context = TestContextBuilder::new().use_http_server().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -1922,7 +1687,14 @@ fn lsp_hover_dependency() {
);
did_open(
&mut client,
- load_fixture("did_open_params_import_hover.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "languageId": "typescript",
+ "version": 1,
+ "text": "import * as a from \"http://127.0.0.1:4545/xTypeScriptTypes.js\";\n// @deno-types=\"http://127.0.0.1:4545/type_definitions/foo.d.ts\"\nimport * as b from \"http://127.0.0.1:4545/type_definitions/foo.js\";\nimport * as c from \"http://127.0.0.1:4545/subdir/type_reference.js\";\nimport * as d from \"http://127.0.0.1:4545/subdir/mod1.ts\";\nimport * as e from \"data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=\";\nimport * as f from \"./file_01.ts\";\nimport * as g from \"http://localhost:4545/x/a/mod.ts\";\n\nconsole.log(a, b, c, d, e, f, g);\n"
+ }
+ }),
);
let (maybe_res, maybe_err) = client
.write_request::<_, _, Value>(
@@ -1944,10 +1716,7 @@ fn lsp_hover_dependency() {
"textDocument": {
"uri": "file:///a/file.ts",
},
- "position": {
- "line": 0,
- "character": 28
- }
+ "position": { "line": 0, "character": 28 }
}),
)
.unwrap();
@@ -1960,14 +1729,8 @@ fn lsp_hover_dependency() {
"value": "**Resolved Dependency**\n\n**Code**: http&#8203;://127.0.0.1:4545/xTypeScriptTypes.js\n\n**Types**: http&#8203;://127.0.0.1:4545/xTypeScriptTypes.d.ts\n"
},
"range": {
- "start": {
- "line": 0,
- "character": 19
- },
- "end":{
- "line": 0,
- "character": 62
- }
+ "start": { "line": 0, "character": 19 },
+ "end":{ "line": 0, "character": 62 }
}
}))
);
@@ -1978,10 +1741,7 @@ fn lsp_hover_dependency() {
"textDocument": {
"uri": "file:///a/file.ts",
},
- "position": {
- "line": 3,
- "character": 28
- }
+ "position": { "line": 3, "character": 28 }
}),
)
.unwrap();
@@ -1994,14 +1754,8 @@ fn lsp_hover_dependency() {
"value": "**Resolved Dependency**\n\n**Code**: http&#8203;://127.0.0.1:4545/subdir/type_reference.js\n\n**Types**: http&#8203;://127.0.0.1:4545/subdir/type_reference.d.ts\n"
},
"range": {
- "start": {
- "line": 3,
- "character": 19
- },
- "end":{
- "line": 3,
- "character": 67
- }
+ "start": { "line": 3, "character": 19 },
+ "end":{ "line": 3, "character": 67 }
}
}))
);
@@ -2012,10 +1766,7 @@ fn lsp_hover_dependency() {
"textDocument": {
"uri": "file:///a/file.ts",
},
- "position": {
- "line": 4,
- "character": 28
- }
+ "position": { "line": 4, "character": 28 }
}),
)
.unwrap();
@@ -2028,14 +1779,8 @@ fn lsp_hover_dependency() {
"value": "**Resolved Dependency**\n\n**Code**: http&#8203;://127.0.0.1:4545/subdir/mod1.ts\n"
},
"range": {
- "start": {
- "line": 4,
- "character": 19
- },
- "end":{
- "line": 4,
- "character": 57
- }
+ "start": { "line": 4, "character": 19 },
+ "end":{ "line": 4, "character": 57 }
}
}))
);
@@ -2046,10 +1791,7 @@ fn lsp_hover_dependency() {
"textDocument": {
"uri": "file:///a/file.ts",
},
- "position": {
- "line": 5,
- "character": 28
- }
+ "position": { "line": 5, "character": 28 }
}),
)
.unwrap();
@@ -2062,14 +1804,8 @@ fn lsp_hover_dependency() {
"value": "**Resolved Dependency**\n\n**Code**: _(a data url)_\n"
},
"range": {
- "start": {
- "line": 5,
- "character": 19
- },
- "end":{
- "line": 5,
- "character": 132
- }
+ "start": { "line": 5, "character": 19 },
+ "end":{ "line": 5, "character": 132 }
}
}))
);
@@ -2080,10 +1816,7 @@ fn lsp_hover_dependency() {
"textDocument": {
"uri": "file:///a/file.ts",
},
- "position": {
- "line": 6,
- "character": 28
- }
+ "position": { "line": 6, "character": 28 }
}),
)
.unwrap();
@@ -2096,14 +1829,8 @@ fn lsp_hover_dependency() {
"value": "**Resolved Dependency**\n\n**Code**: file&#8203;:///a/file_01.ts\n"
},
"range": {
- "start": {
- "line": 6,
- "character": 19
- },
- "end":{
- "line": 6,
- "character": 33
- }
+ "start": { "line": 6, "character": 19 },
+ "end":{ "line": 6, "character": 33 }
}
}))
);
@@ -2113,7 +1840,8 @@ fn lsp_hover_dependency() {
// unable to resolve dependencies when there was an invalid syntax in the module
#[test]
fn lsp_hover_deps_preserved_when_invalid_parse() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -2143,10 +1871,7 @@ fn lsp_hover_deps_preserved_when_invalid_parse() {
"textDocument": {
"uri": "file:///a/file2.ts"
},
- "position": {
- "line": 0,
- "character": 56
- }
+ "position": { "line": 0, "character": 56 }
}),
)
.unwrap();
@@ -2162,14 +1887,8 @@ fn lsp_hover_deps_preserved_when_invalid_parse() {
""
],
"range": {
- "start": {
- "line": 0,
- "character": 56,
- },
- "end": {
- "line": 0,
- "character": 57,
- }
+ "start": { "line": 0, "character": 56, },
+ "end": { "line": 0, "character": 57, }
}
}))
);
@@ -2184,14 +1903,8 @@ fn lsp_hover_deps_preserved_when_invalid_parse() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 0,
- "character": 57
- },
- "end": {
- "line": 0,
- "character": 58
- }
+ "start": { "line": 0, "character": 57 },
+ "end": { "line": 0, "character": 58 }
},
"text": "."
}
@@ -2206,10 +1919,7 @@ fn lsp_hover_deps_preserved_when_invalid_parse() {
"textDocument": {
"uri": "file:///a/file2.ts"
},
- "position": {
- "line": 0,
- "character": 56
- }
+ "position": { "line": 0, "character": 56 }
}),
)
.unwrap();
@@ -2225,24 +1935,19 @@ fn lsp_hover_deps_preserved_when_invalid_parse() {
""
],
"range": {
- "start": {
- "line": 0,
- "character": 56,
- },
- "end": {
- "line": 0,
- "character": 57,
- }
+ "start": { "line": 0, "character": 56, },
+ "end": { "line": 0, "character": 57, }
}
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_hover_typescript_types() {
- let _g = http_server();
- let mut client = init("initialize_params.json");
+ let context = TestContextBuilder::new().use_http_server().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -2278,10 +1983,7 @@ fn lsp_hover_typescript_types() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 24
- }
+ "position": { "line": 0, "character": 24 }
}),
)
.unwrap();
@@ -2295,23 +1997,18 @@ fn lsp_hover_typescript_types() {
"value": "**Resolved Dependency**\n\n**Code**: http&#8203;://127.0.0.1:4545/xTypeScriptTypes.js\n\n**Types**: http&#8203;://127.0.0.1:4545/xTypeScriptTypes.d.ts\n"
},
"range": {
- "start": {
- "line": 0,
- "character": 19
- },
- "end": {
- "line": 0,
- "character": 62
- }
+ "start": { "line": 0, "character": 19 },
+ "end": { "line": 0, "character": 62 }
}
})
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_hover_jsdoc_symbol_link() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -2341,10 +2038,7 @@ fn lsp_hover_jsdoc_symbol_link() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 7,
- "character": 10
- }
+ "position": { "line": 7, "character": 10 }
}),
)
.unwrap();
@@ -2360,23 +2054,18 @@ fn lsp_hover_jsdoc_symbol_link() {
"JSDoc [hello](file:///a/file.ts#L1,10) and [`b`](file:///a/file.ts#L5,7)"
],
"range": {
- "start": {
- "line": 7,
- "character": 9
- },
- "end": {
- "line": 7,
- "character": 10
- }
+ "start": { "line": 7, "character": 9 },
+ "end": { "line": 7, "character": 10 }
}
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_goto_type_definition() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -2395,10 +2084,7 @@ fn lsp_goto_type_definition() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 12,
- "character": 1
- }
+ "position": { "line": 12, "character": 1 }
}),
)
.unwrap();
@@ -2409,34 +2095,23 @@ fn lsp_goto_type_definition() {
{
"targetUri": "file:///a/file.ts",
"targetRange": {
- "start": {
- "line": 4,
- "character": 0
- },
- "end": {
- "line": 9,
- "character": 1
- }
+ "start": { "line": 4, "character": 0 },
+ "end": { "line": 9, "character": 1 }
},
"targetSelectionRange": {
- "start": {
- "line": 4,
- "character": 13
- },
- "end": {
- "line": 4,
- "character": 14
- }
+ "start": { "line": 4, "character": 13 },
+ "end": { "line": 4, "character": 14 }
}
}
]))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_call_hierarchy() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -2455,47 +2130,141 @@ fn lsp_call_hierarchy() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 5,
- "character": 3
- }
+ "position": { "line": 5, "character": 3 }
}),
)
.unwrap();
assert!(maybe_error.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("prepare_call_hierarchy_response.json"))
+ Some(json!([{
+ "name": "baz",
+ "kind": 6,
+ "detail": "Bar",
+ "uri": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 5, "character": 2 },
+ "end": { "line": 7, "character": 3 }
+ },
+ "selectionRange": {
+ "start": { "line": 5, "character": 2 },
+ "end": { "line": 5, "character": 5 }
+ }
+ }]))
);
let (maybe_res, maybe_error) = client
.write_request(
"callHierarchy/incomingCalls",
- load_fixture("incoming_calls_params.json"),
+ json!({
+ "item": {
+ "name": "baz",
+ "kind": 6,
+ "detail": "Bar",
+ "uri": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 5, "character": 2 },
+ "end": { "line": 7, "character": 3 }
+ },
+ "selectionRange": {
+ "start": { "line": 5, "character": 2 },
+ "end": { "line": 5, "character": 5 }
+ }
+ }
+ }),
)
.unwrap();
assert!(maybe_error.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("incoming_calls_response.json"))
+ Some(json!([{
+ "from": {
+ "name": "main",
+ "kind": 12,
+ "detail": "",
+ "uri": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 10, "character": 0 },
+ "end": { "line": 13, "character": 1 }
+ },
+ "selectionRange": {
+ "start": { "line": 10, "character": 9 },
+ "end": { "line": 10, "character": 13 }
+ }
+ },
+ "fromRanges": [
+ {
+ "start": { "line": 12, "character": 6 },
+ "end": { "line": 12, "character": 9 }
+ }
+ ]
+ }]))
);
let (maybe_res, maybe_error) = client
.write_request(
"callHierarchy/outgoingCalls",
- load_fixture("outgoing_calls_params.json"),
+ json!({
+ "item": {
+ "name": "baz",
+ "kind": 6,
+ "detail": "Bar",
+ "uri": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 5, "character": 2 },
+ "end": { "line": 7, "character": 3 }
+ },
+ "selectionRange": {
+ "start": { "line": 5, "character": 2 },
+ "end": { "line": 5, "character": 5 }
+ }
+ }
+ }),
)
.unwrap();
assert!(maybe_error.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("outgoing_calls_response.json"))
+ Some(json!([{
+ "to": {
+ "name": "foo",
+ "kind": 12,
+ "detail": "",
+ "uri": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 2, "character": 1 }
+ },
+ "selectionRange": {
+ "start": { "line": 0, "character": 9 },
+ "end": { "line": 0, "character": 12 }
+ }
+ },
+ "fromRanges": [{
+ "start": { "line": 6, "character": 11 },
+ "end": { "line": 6, "character": 14 }
+ }]
+ }]))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_large_doc_changes() {
- let mut client = init("initialize_params.json");
- did_open(&mut client, load_fixture("did_open_params_large.json"));
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
+ let large_file_text =
+ fs::read_to_string(testdata_path().join("lsp").join("large_file.txt"))
+ .unwrap();
+ did_open(
+ &mut client,
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "languageId": "javascript",
+ "version": 1,
+ "text": large_file_text,
+ }
+ }),
+ );
client
.write_notification(
"textDocument/didChange",
@@ -2507,14 +2276,8 @@ fn lsp_large_doc_changes() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 444,
- "character": 11
- },
- "end": {
- "line": 444,
- "character": 14
- }
+ "start": { "line": 444, "character": 11 },
+ "end": { "line": 444, "character": 14 }
},
"text": "+++"
}
@@ -2533,14 +2296,8 @@ fn lsp_large_doc_changes() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 445,
- "character": 4
- },
- "end": {
- "line": 445,
- "character": 4
- }
+ "start": { "line": 445, "character": 4 },
+ "end": { "line": 445, "character": 4 }
},
"text": "// "
}
@@ -2559,14 +2316,8 @@ fn lsp_large_doc_changes() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 477,
- "character": 4
- },
- "end": {
- "line": 477,
- "character": 9
- }
+ "start": { "line": 477, "character": 4 },
+ "end": { "line": 477, "character": 9 }
},
"text": "error"
}
@@ -2581,10 +2332,7 @@ fn lsp_large_doc_changes() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 421,
- "character": 30
- }
+ "position": { "line": 421, "character": 30 }
}),
)
.unwrap();
@@ -2597,10 +2345,7 @@ fn lsp_large_doc_changes() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 444,
- "character": 6
- }
+ "position": { "line": 444, "character": 6 }
}),
)
.unwrap();
@@ -2613,24 +2358,32 @@ fn lsp_large_doc_changes() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 461,
- "character": 34
- }
+ "position": { "line": 461, "character": 34 }
}),
)
.unwrap();
assert!(maybe_res.is_some());
assert!(maybe_err.is_none());
- shutdown(&mut client);
+ client.shutdown();
assert!(client.duration().as_millis() <= 15000);
}
#[test]
fn lsp_document_symbol() {
- let mut client = init("initialize_params.json");
- did_open(&mut client, load_fixture("did_open_params_doc_symbol.json"));
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
+ did_open(
+ &mut client,
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "languageId": "typescript",
+ "version": 1,
+ "text": "interface IFoo {\n foo(): boolean;\n}\n\nclass Bar implements IFoo {\n constructor(public x: number) { }\n foo() { return true; }\n /** @deprecated */\n baz() { return false; }\n get value(): number { return 0; }\n set value(newVavlue: number) { return; }\n static staticBar = new Bar(0);\n private static getStaticBar() { return Bar.staticBar; }\n}\n\nenum Values { value1, value2 }\n\nvar bar: IFoo = new Bar(3);"
+ }
+ }),
+ );
let (maybe_res, maybe_err) = client
.write_request(
"textDocument/documentSymbol",
@@ -2644,14 +2397,185 @@ fn lsp_document_symbol() {
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("document_symbol_response.json"))
+ Some(json!([{
+ "name": "bar",
+ "kind": 13,
+ "range": {
+ "start": { "line": 17, "character": 4 },
+ "end": { "line": 17, "character": 26 }
+ },
+ "selectionRange": {
+ "start": { "line": 17, "character": 4 },
+ "end": { "line": 17, "character": 7 }
+ }
+ }, {
+ "name": "Bar",
+ "kind": 5,
+ "range": {
+ "start": { "line": 4, "character": 0 },
+ "end": { "line": 13, "character": 1 }
+ },
+ "selectionRange": {
+ "start": { "line": 4, "character": 6 },
+ "end": { "line": 4, "character": 9 }
+ },
+ "children": [{
+ "name": "constructor",
+ "kind": 9,
+ "range": {
+ "start": { "line": 5, "character": 2 },
+ "end": { "line": 5, "character": 35 }
+ },
+ "selectionRange": {
+ "start": { "line": 5, "character": 2 },
+ "end": { "line": 5, "character": 35 }
+ }
+ }, {
+ "name": "baz",
+ "kind": 6,
+ "tags": [1],
+ "range": {
+ "start": { "line": 8, "character": 2 },
+ "end": { "line": 8, "character": 25 }
+ },
+ "selectionRange": {
+ "start": { "line": 8, "character": 2 },
+ "end": { "line": 8, "character": 5 }
+ }
+ }, {
+ "name": "foo",
+ "kind": 6,
+ "range": {
+ "start": { "line": 6, "character": 2 },
+ "end": { "line": 6, "character": 24 }
+ },
+ "selectionRange": {
+ "start": { "line": 6, "character": 2 },
+ "end": { "line": 6, "character": 5 }
+ }
+ }, {
+ "name": "getStaticBar",
+ "kind": 6,
+ "range": {
+ "start": { "line": 12, "character": 2 },
+ "end": { "line": 12, "character": 57 }
+ },
+ "selectionRange": {
+ "start": { "line": 12, "character": 17 },
+ "end": { "line": 12, "character": 29 }
+ }
+ }, {
+ "name": "staticBar",
+ "kind": 8,
+ "range": {
+ "start": { "line": 11, "character": 2 },
+ "end": { "line": 11, "character": 32 }
+ },
+ "selectionRange": {
+ "start": { "line": 11, "character": 9 },
+ "end": { "line": 11, "character": 18 }
+ }
+ }, {
+ "name": "(get) value",
+ "kind": 8,
+ "range": {
+ "start": { "line": 9, "character": 2 },
+ "end": { "line": 9, "character": 35 }
+ },
+ "selectionRange": {
+ "start": { "line": 9, "character": 6 },
+ "end": { "line": 9, "character": 11 }
+ }
+ }, {
+ "name": "(set) value",
+ "kind": 8,
+ "range": {
+ "start": { "line": 10, "character": 2 },
+ "end": { "line": 10, "character": 42 }
+ },
+ "selectionRange": {
+ "start": { "line": 10, "character": 6 },
+ "end": { "line": 10, "character": 11 }
+ }
+ }, {
+ "name": "x",
+ "kind": 8,
+ "range": {
+ "start": { "line": 5, "character": 14 },
+ "end": { "line": 5, "character": 30 }
+ },
+ "selectionRange": {
+ "start": { "line": 5, "character": 21 },
+ "end": { "line": 5, "character": 22 }
+ }
+ }]
+ }, {
+ "name": "IFoo",
+ "kind": 11,
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 2, "character": 1 }
+ },
+ "selectionRange": {
+ "start": { "line": 0, "character": 10 },
+ "end": { "line": 0, "character": 14 }
+ },
+ "children": [{
+ "name": "foo",
+ "kind": 6,
+ "range": {
+ "start": { "line": 1, "character": 2 },
+ "end": { "line": 1, "character": 17 }
+ },
+ "selectionRange": {
+ "start": { "line": 1, "character": 2 },
+ "end": { "line": 1, "character": 5 }
+ }
+ }]
+ }, {
+ "name": "Values",
+ "kind": 10,
+ "range": {
+ "start": { "line": 15, "character": 0 },
+ "end": { "line": 15, "character": 30 }
+ },
+ "selectionRange": {
+ "start": { "line": 15, "character": 5 },
+ "end": { "line": 15, "character": 11 }
+ },
+ "children": [{
+ "name": "value1",
+ "kind": 22,
+ "range": {
+ "start": { "line": 15, "character": 14 },
+ "end": { "line": 15, "character": 20 }
+ },
+ "selectionRange": {
+ "start": { "line": 15, "character": 14 },
+ "end": { "line": 15, "character": 20 }
+ }
+ }, {
+ "name": "value2",
+ "kind": 22,
+ "range": {
+ "start": { "line": 15, "character": 22 },
+ "end": { "line": 15, "character": 28 }
+ },
+ "selectionRange": {
+ "start": { "line": 15, "character": 22 },
+ "end": { "line": 15, "character": 28 }
+ }
+ }]
+ }]
+ ))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_folding_range() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -2676,37 +2600,32 @@ fn lsp_folding_range() {
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(json!([
- {
- "startLine": 0,
- "endLine": 12,
- "kind": "region"
- },
- {
- "startLine": 1,
- "endLine": 3,
- "kind": "comment"
- },
- {
- "startLine": 4,
- "endLine": 10
- },
- {
- "startLine": 5,
- "endLine": 9
- },
- {
- "startLine": 6,
- "endLine": 7
- }
- ]))
+ Some(json!([{
+ "startLine": 0,
+ "endLine": 12,
+ "kind": "region"
+ }, {
+ "startLine": 1,
+ "endLine": 3,
+ "kind": "comment"
+ }, {
+ "startLine": 4,
+ "endLine": 10
+ }, {
+ "startLine": 5,
+ "endLine": 9
+ }, {
+ "startLine": 6,
+ "endLine": 7
+ }]))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_rename() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -2726,22 +2645,43 @@ fn lsp_rename() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 4
- },
+ "position": { "line": 0, "character": 4 },
"newName": "variable_modified"
}),
)
.unwrap();
assert!(maybe_err.is_none());
- assert_eq!(maybe_res, Some(load_fixture("rename_response.json")));
- shutdown(&mut client);
+ assert_eq!(
+ maybe_res,
+ Some(json!({
+ "documentChanges": [{
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "version": 1
+ },
+ "edits": [{
+ "range": {
+ "start": { "line": 0, "character": 4 },
+ "end": { "line": 0, "character": 12 }
+ },
+ "newText": "variable_modified"
+ }, {
+ "range": {
+ "start": { "line": 1, "character": 12 },
+ "end": { "line": 1, "character": 20 }
+ },
+ "newText": "variable_modified"
+ }]
+ }]
+ }))
+ );
+ client.shutdown();
}
#[test]
fn lsp_selection_range() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -2760,29 +2700,79 @@ fn lsp_selection_range() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "positions": [
- {
- "line": 2,
- "character": 8
- }
- ]
+ "positions": [{ "line": 2, "character": 8 }]
}),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("selection_range_response.json"))
+ Some(json!([{
+ "range": {
+ "start": { "line": 2, "character": 8 },
+ "end": { "line": 2, "character": 9 }
+ },
+ "parent": {
+ "range": {
+ "start": { "line": 2, "character": 8 },
+ "end": { "line": 2, "character": 15 }
+ },
+ "parent": {
+ "range": {
+ "start": { "line": 2, "character": 4 },
+ "end": { "line": 4, "character": 5 }
+ },
+ "parent": {
+ "range": {
+ "start": { "line": 1, "character": 13 },
+ "end": { "line": 6, "character": 2 }
+ },
+ "parent": {
+ "range": {
+ "start": { "line": 1, "character": 12 },
+ "end": { "line": 6, "character": 3 }
+ },
+ "parent": {
+ "range": {
+ "start": { "line": 1, "character": 2 },
+ "end": { "line": 6, "character": 3 }
+ },
+ "parent": {
+ "range": {
+ "start": { "line": 0, "character": 11 },
+ "end": { "line": 7, "character": 0 }
+ },
+ "parent": {
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 7, "character": 1 }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }]))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_semantic_tokens() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
- load_fixture("did_open_params_semantic_tokens.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "languageId": "typescript",
+ "version": 1,
+ "text": "enum Values { value1, value2 }\n\nasync function baz(s: string): Promise<string> {\n const r = s.slice(0);\n return r;\n}\n\ninterface IFoo {\n readonly x: number;\n foo(): boolean;\n}\n\nclass Bar implements IFoo {\n constructor(public readonly x: number) { }\n foo() { return true; }\n static staticBar = new Bar(0);\n private static getStaticBar() { return Bar.staticBar; }\n}\n"
+ }
+ }),
);
let (maybe_res, maybe_err) = client
.write_request(
@@ -2815,14 +2805,8 @@ fn lsp_semantic_tokens() {
"uri": "file:///a/file.ts"
},
"range": {
- "start": {
- "line": 0,
- "character": 0
- },
- "end": {
- "line": 6,
- "character": 0
- }
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 6, "character": 0 }
}
}),
)
@@ -2838,12 +2822,13 @@ fn lsp_semantic_tokens() {
]
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_code_lens() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -2866,20 +2851,35 @@ fn lsp_code_lens() {
)
.unwrap();
assert!(maybe_err.is_none());
- assert_eq!(maybe_res, Some(load_fixture("code_lens_response.json")));
+ assert_eq!(
+ maybe_res,
+ Some(json!([{
+ "range": {
+ "start": { "line": 0, "character": 6 },
+ "end": { "line": 0, "character": 7 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "references"
+ }
+ }, {
+ "range": {
+ "start": { "line": 1, "character": 2 },
+ "end": { "line": 1, "character": 3 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "references"
+ }
+ }]))
+ );
let (maybe_res, maybe_err) = client
.write_request(
"codeLens/resolve",
json!({
"range": {
- "start": {
- "line": 0,
- "character": 6
- },
- "end": {
- "line": 0,
- "character": 7
- }
+ "start": { "line": 0, "character": 6 },
+ "end": { "line": 0, "character": 7 }
},
"data": {
"specifier": "file:///a/file.ts",
@@ -2891,14 +2891,41 @@ fn lsp_code_lens() {
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_lens_resolve_response.json"))
+ Some(json!({
+ "range": {
+ "start": { "line": 0, "character": 6 },
+ "end": { "line": 0, "character": 7 }
+ },
+ "command": {
+ "title": "2 references",
+ "command": "deno.showReferences",
+ "arguments": [
+ "file:///a/file.ts",
+ { "line": 0, "character": 6 },
+ [{
+ "uri": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 0, "character": 6 },
+ "end": { "line": 0, "character": 7 }
+ }
+ }, {
+ "uri": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 12, "character": 14 },
+ "end": { "line": 12, "character": 15 }
+ }
+ }]
+ ]
+ }
+ }))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_code_lens_impl() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -2923,21 +2950,69 @@ fn lsp_code_lens_impl() {
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_lens_response_impl.json"))
+ Some(json!([ {
+ "range": {
+ "start": { "line": 0, "character": 10 },
+ "end": { "line": 0, "character": 11 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "implementations"
+ }
+ }, {
+ "range": {
+ "start": { "line": 0, "character": 10 },
+ "end": { "line": 0, "character": 11 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "references"
+ }
+ }, {
+ "range": {
+ "start": { "line": 4, "character": 6 },
+ "end": { "line": 4, "character": 7 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "references"
+ }
+ }, {
+ "range": {
+ "start": { "line": 10, "character": 10 },
+ "end": { "line": 10, "character": 11 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "implementations"
+ }
+ }, {
+ "range": {
+ "start": { "line": 10, "character": 10 },
+ "end": { "line": 10, "character": 11 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "references"
+ }
+ }, {
+ "range": {
+ "start": { "line": 11, "character": 2 },
+ "end": { "line": 11, "character": 3 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "references"
+ }
+ }]))
);
let (maybe_res, maybe_err) = client
.write_request(
"codeLens/resolve",
json!({
"range": {
- "start": {
- "line": 0,
- "character": 10
- },
- "end": {
- "line": 0,
- "character": 11
- }
+ "start": { "line": 0, "character": 10 },
+ "end": { "line": 0, "character": 11 }
},
"data": {
"specifier": "file:///a/file.ts",
@@ -2949,21 +3024,35 @@ fn lsp_code_lens_impl() {
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_lens_resolve_response_impl.json"))
+ Some(json!({
+ "range": {
+ "start": { "line": 0, "character": 10 },
+ "end": { "line": 0, "character": 11 }
+ },
+ "command": {
+ "title": "1 implementation",
+ "command": "deno.showReferences",
+ "arguments": [
+ "file:///a/file.ts",
+ { "line": 0, "character": 10 },
+ [{
+ "uri": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 4, "character": 6 },
+ "end": { "line": 4, "character": 7 }
+ }
+ }]
+ ]
+ }
+ }))
);
let (maybe_res, maybe_err) = client
.write_request::<_, _, Value>(
"codeLens/resolve",
json!({
"range": {
- "start": {
- "line": 10,
- "character": 10
- },
- "end": {
- "line": 10,
- "character": 11
- }
+ "start": { "line": 10, "character": 10 },
+ "end": { "line": 10, "character": 11 }
},
"data": {
"specifier": "file:///a/file.ts",
@@ -2977,14 +3066,8 @@ fn lsp_code_lens_impl() {
maybe_res,
Some(json!({
"range": {
- "start": {
- "line": 10,
- "character": 10
- },
- "end": {
- "line": 10,
- "character": 11
- }
+ "start": { "line": 10, "character": 10 },
+ "end": { "line": 10, "character": 11 }
},
"command": {
"title": "0 implementations",
@@ -2992,15 +3075,25 @@ fn lsp_code_lens_impl() {
}
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_code_lens_test() {
- let mut client = init("initialize_params_code_lens_test.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize(|builder| {
+ builder.disable_testing_api().set_code_lens(None);
+ });
did_open(
&mut client,
- load_fixture("did_open_params_test_code_lens.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "languageId": "typescript",
+ "version": 1,
+ "text": "const { test } = Deno;\nconst { test: test2 } = Deno;\nconst test3 = Deno.test;\n\nDeno.test(\"test a\", () => {});\nDeno.test({\n name: \"test b\",\n fn() {},\n});\ntest({\n name: \"test c\",\n fn() {},\n});\ntest(\"test d\", () => {});\ntest2({\n name: \"test e\",\n fn() {},\n});\ntest2(\"test f\", () => {});\ntest3({\n name: \"test g\",\n fn() {},\n});\ntest3(\"test h\", () => {});\n"
+ }
+ }),
);
let (maybe_res, maybe_err) = client
.write_request(
@@ -3015,18 +3108,256 @@ fn lsp_code_lens_test() {
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_lens_response_test.json"))
+ Some(json!([{
+ "range": {
+ "start": { "line": 4, "character": 5 },
+ "end": { "line": 4, "character": 9 }
+ },
+ "command": {
+ "title": "▶︎ Run Test",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test a",
+ { "inspect": false }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 4, "character": 5 },
+ "end": { "line": 4, "character": 9 }
+ },
+ "command": {
+ "title": "Debug",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test a",
+ { "inspect": true }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 5, "character": 5 },
+ "end": { "line": 5, "character": 9 }
+ },
+ "command": {
+ "title": "▶︎ Run Test",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test b",
+ { "inspect": false }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 5, "character": 5 },
+ "end": { "line": 5, "character": 9 }
+ },
+ "command": {
+ "title": "Debug",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test b",
+ { "inspect": true }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 9, "character": 0 },
+ "end": { "line": 9, "character": 4 }
+ },
+ "command": {
+ "title": "▶︎ Run Test",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test c",
+ { "inspect": false }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 9, "character": 0 },
+ "end": { "line": 9, "character": 4 }
+ },
+ "command": {
+ "title": "Debug",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test c",
+ { "inspect": true }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 13, "character": 0 },
+ "end": { "line": 13, "character": 4 }
+ },
+ "command": {
+ "title": "▶︎ Run Test",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test d",
+ { "inspect": false }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 13, "character": 0 },
+ "end": { "line": 13, "character": 4 }
+ },
+ "command": {
+ "title": "Debug",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test d",
+ { "inspect": true }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 14, "character": 0 },
+ "end": { "line": 14, "character": 5 }
+ },
+ "command": {
+ "title": "▶︎ Run Test",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test e",
+ { "inspect": false }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 14, "character": 0 },
+ "end": { "line": 14, "character": 5 }
+ },
+ "command": {
+ "title": "Debug",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test e",
+ { "inspect": true }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 18, "character": 0 },
+ "end": { "line": 18, "character": 5 }
+ },
+ "command": {
+ "title": "▶︎ Run Test",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test f",
+ { "inspect": false }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 18, "character": 0 },
+ "end": { "line": 18, "character": 5 }
+ },
+ "command": {
+ "title": "Debug",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test f",
+ { "inspect": true }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 19, "character": 0 },
+ "end": { "line": 19, "character": 5 }
+ },
+ "command": {
+ "title": "▶︎ Run Test",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test g",
+ { "inspect": false }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 19, "character": 0 },
+ "end": { "line": 19, "character": 5 }
+ },
+ "command": {
+ "title": "Debug",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test g",
+ { "inspect": true }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 23, "character": 0 },
+ "end": { "line": 23, "character": 5 }
+ },
+ "command": {
+ "title": "▶︎ Run Test",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test h",
+ { "inspect": false }
+ ]
+ }
+ }, {
+ "range": {
+ "start": { "line": 23, "character": 0 },
+ "end": { "line": 23, "character": 5 }
+ },
+ "command": {
+ "title": "Debug",
+ "command": "deno.test",
+ "arguments": [
+ "file:///a/file.ts",
+ "test h",
+ { "inspect": true }
+ ]
+ }
+ }]))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_code_lens_test_disabled() {
- let mut client = init("initialize_params_code_lens_test_disabled.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize(|builder| {
+ builder.disable_testing_api().set_code_lens(Some(json!({
+ "implementations": true,
+ "references": true,
+ "test": false
+ })));
+ });
client
.write_notification(
"textDocument/didOpen",
- load_fixture("did_open_params_test_code_lens.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "languageId": "typescript",
+ "version": 1,
+ "text": "const { test } = Deno;\nconst { test: test2 } = Deno;\nconst test3 = Deno.test;\n\nDeno.test(\"test a\", () => {});\nDeno.test({\n name: \"test b\",\n fn() {},\n});\ntest({\n name: \"test c\",\n fn() {},\n});\ntest(\"test d\", () => {});\ntest2({\n name: \"test e\",\n fn() {},\n});\ntest2(\"test f\", () => {});\ntest3({\n name: \"test g\",\n fn() {},\n});\ntest3(\"test h\", () => {});\n"
+ }
+ }),
)
.unwrap();
@@ -3062,12 +3393,13 @@ fn lsp_code_lens_test_disabled() {
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(maybe_res, Some(json!([])));
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_code_lens_non_doc_nav_tree() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -3086,10 +3418,7 @@ fn lsp_code_lens_non_doc_nav_tree() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 3
- },
+ "position": { "line": 0, "character": 3 },
"context": {
"includeDeclaration": true
}
@@ -3129,14 +3458,8 @@ fn lsp_code_lens_non_doc_nav_tree() {
"codeLens/resolve",
json!({
"range": {
- "start": {
- "line": 416,
- "character": 12
- },
- "end": {
- "line": 416,
- "character": 19
- }
+ "start": { "line": 416, "character": 12 },
+ "end": { "line": 416, "character": 19 }
},
"data": {
"specifier": "asset:///lib.deno.shared_globals.d.ts",
@@ -3147,12 +3470,13 @@ fn lsp_code_lens_non_doc_nav_tree() {
.unwrap();
assert!(maybe_err.is_none());
assert!(maybe_res.is_some());
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_nav_tree_updates() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -3177,7 +3501,61 @@ fn lsp_nav_tree_updates() {
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_lens_response_impl.json"))
+ Some(Some(json!([ {
+ "range": {
+ "start": { "line": 0, "character": 10 },
+ "end": { "line": 0, "character": 11 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "implementations"
+ }
+ }, {
+ "range": {
+ "start": { "line": 0, "character": 10 },
+ "end": { "line": 0, "character": 11 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "references"
+ }
+ }, {
+ "range": {
+ "start": { "line": 4, "character": 6 },
+ "end": { "line": 4, "character": 7 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "references"
+ }
+ }, {
+ "range": {
+ "start": { "line": 10, "character": 10 },
+ "end": { "line": 10, "character": 11 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "implementations"
+ }
+ }, {
+ "range": {
+ "start": { "line": 10, "character": 10 },
+ "end": { "line": 10, "character": 11 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "references"
+ }
+ }, {
+ "range": {
+ "start": { "line": 11, "character": 2 },
+ "end": { "line": 11, "character": 3 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "references"
+ }
+ }])))
);
client
.write_notification(
@@ -3190,14 +3568,8 @@ fn lsp_nav_tree_updates() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 10,
- "character": 0
- },
- "end": {
- "line": 13,
- "character": 0
- }
+ "start": { "line": 10, "character": 0 },
+ "end": { "line": 13, "character": 0 }
},
"text": ""
}
@@ -3218,14 +3590,42 @@ fn lsp_nav_tree_updates() {
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_lens_response_changed.json"))
+ Some(json!([{
+ "range": {
+ "start": { "line": 0, "character": 10 },
+ "end": { "line": 0, "character": 11 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "implementations"
+ }
+ }, {
+ "range": {
+ "start": { "line": 0, "character": 10 },
+ "end": { "line": 0, "character": 11 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "references"
+ }
+ }, {
+ "range": {
+ "start": { "line": 4, "character": 6 },
+ "end": { "line": 4, "character": 7 }
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "source": "references"
+ }
+ }]))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_signature_help() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -3244,10 +3644,7 @@ fn lsp_signature_help() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "character": 4,
- "line": 9
- },
+ "position": { "character": 4, "line": 9 },
"context": {
"triggerKind": 2,
"triggerCharacter": "(",
@@ -3274,8 +3671,7 @@ fn lsp_signature_help() {
"kind": "markdown",
"value": "This is a first number."
}
- },
- {
+ }, {
"label": "b: number",
"documentation": {
"kind": "markdown",
@@ -3300,14 +3696,8 @@ fn lsp_signature_help() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 9,
- "character": 4
- },
- "end": {
- "line": 9,
- "character": 4
- }
+ "start": { "line": 9, "character": 4 },
+ "end": { "line": 9, "character": 4 }
},
"text": "123, "
}
@@ -3322,10 +3712,7 @@ fn lsp_signature_help() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "character": 8,
- "line": 9
- }
+ "position": { "character": 8, "line": 9 }
}),
)
.unwrap();
@@ -3347,8 +3734,7 @@ fn lsp_signature_help() {
"kind": "markdown",
"value": "This is a first number."
}
- },
- {
+ }, {
"label": "b: number",
"documentation": {
"kind": "markdown",
@@ -3362,12 +3748,13 @@ fn lsp_signature_help() {
"activeParameter": 1
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_code_actions() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -3382,28 +3769,185 @@ fn lsp_code_actions() {
let (maybe_res, maybe_err) = client
.write_request(
"textDocument/codeAction",
- load_fixture("code_action_params.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts"
+ },
+ "range": {
+ "start": { "line": 1, "character": 2 },
+ "end": { "line": 1, "character": 7 }
+ },
+ "context": {
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 1, "character": 2 },
+ "end": { "line": 1, "character": 7 }
+ },
+ "severity": 1,
+ "code": 1308,
+ "source": "deno-ts",
+ "message": "'await' expressions are only allowed within async functions and at the top levels of modules.",
+ "relatedInformation": []
+ }],
+ "only": ["quickfix"]
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
- assert_eq!(maybe_res, Some(load_fixture("code_action_response.json")));
+ assert_eq!(
+ maybe_res,
+ Some(json!([{
+ "title": "Add async modifier to containing function",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 1, "character": 2 },
+ "end": { "line": 1, "character": 7 }
+ },
+ "severity": 1,
+ "code": 1308,
+ "source": "deno-ts",
+ "message": "'await' expressions are only allowed within async functions and at the top levels of modules.",
+ "relatedInformation": []
+ }],
+ "edit": {
+ "documentChanges": [{
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "version": 1
+ },
+ "edits": [{
+ "range": {
+ "start": { "line": 0, "character": 7 },
+ "end": { "line": 0, "character": 7 }
+ },
+ "newText": "async "
+ }, {
+ "range": {
+ "start": { "line": 0, "character": 21 },
+ "end": { "line": 0, "character": 25 }
+ },
+ "newText": "Promise<void>"
+ }]
+ }]
+ }
+ }, {
+ "title": "Add all missing 'async' modifiers",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 1, "character": 2 },
+ "end": { "line": 1, "character": 7 }
+ },
+ "severity": 1,
+ "code": 1308,
+ "source": "deno-ts",
+ "message": "'await' expressions are only allowed within async functions and at the top levels of modules.",
+ "relatedInformation": []
+ }],
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "fixId": "fixAwaitInSyncFunction"
+ }
+ }]))
+ );
let (maybe_res, maybe_err) = client
.write_request(
"codeAction/resolve",
- load_fixture("code_action_resolve_params.json"),
+ json!({
+ "title": "Add all missing 'async' modifiers",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 1, "character": 2 },
+ "end": { "line": 1, "character": 7 }
+ },
+ "severity": 1,
+ "code": 1308,
+ "source": "deno-ts",
+ "message": "'await' expressions are only allowed within async functions and at the top levels of modules.",
+ "relatedInformation": []
+ }],
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "fixId": "fixAwaitInSyncFunction"
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_action_resolve_response.json"))
+ Some(json!({
+ "title": "Add all missing 'async' modifiers",
+ "kind": "quickfix",
+ "diagnostics": [
+ {
+ "range": {
+ "start": {
+ "line": 1,
+ "character": 2
+ },
+ "end": {
+ "line": 1,
+ "character": 7
+ }
+ },
+ "severity": 1,
+ "code": 1308,
+ "source": "deno-ts",
+ "message": "'await' expressions are only allowed within async functions and at the top levels of modules.",
+ "relatedInformation": []
+ }
+ ],
+ "edit": {
+ "documentChanges": [{
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "version": 1
+ },
+ "edits": [{
+ "range": {
+ "start": { "line": 0, "character": 7 },
+ "end": { "line": 0, "character": 7 }
+ },
+ "newText": "async "
+ }, {
+ "range": {
+ "start": { "line": 0, "character": 21 },
+ "end": { "line": 0, "character": 25 }
+ },
+ "newText": "Promise<void>"
+ }, {
+ "range": {
+ "start": { "line": 4, "character": 7 },
+ "end": { "line": 4, "character": 7 }
+ },
+ "newText": "async "
+ }, {
+ "range": {
+ "start": { "line": 4, "character": 21 },
+ "end": { "line": 4, "character": 25 }
+ },
+ "newText": "Promise<void>"
+ }]
+ }]
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "fixId": "fixAwaitInSyncFunction"
+ }
+ }))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_code_actions_deno_cache() {
- let mut session = TestSession::from_file("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
+ let mut session = TestSession::from_client(client);
let diagnostics = session.did_open(json!({
"textDocument": {
"uri": "file:///a/file.ts",
@@ -3414,27 +3958,88 @@ fn lsp_code_actions_deno_cache() {
}));
assert_eq!(
diagnostics.with_source("deno"),
- load_fixture_as("diagnostics_deno_deps.json")
+ serde_json::from_value(json!({
+ "uri": "file:///a/file.ts",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 0, "character": 19 },
+ "end": { "line": 0, "character": 49 }
+ },
+ "severity": 1,
+ "code": "no-cache",
+ "source": "deno",
+ "message": "Uncached or missing remote URL: \"https://deno.land/x/a/mod.ts\".",
+ "data": { "specifier": "https://deno.land/x/a/mod.ts" }
+ }],
+ "version": 1
+ })).unwrap()
);
let (maybe_res, maybe_err) = session
.client
.write_request(
"textDocument/codeAction",
- load_fixture("code_action_params_cache.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts"
+ },
+ "range": {
+ "start": { "line": 0, "character": 19 },
+ "end": { "line": 0, "character": 49 }
+ },
+ "context": {
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 0, "character": 19 },
+ "end": { "line": 0, "character": 49 }
+ },
+ "severity": 1,
+ "code": "no-cache",
+ "source": "deno",
+ "message": "Unable to load the remote module: \"https://deno.land/x/a/mod.ts\".",
+ "data": {
+ "specifier": "https://deno.land/x/a/mod.ts"
+ }
+ }],
+ "only": ["quickfix"]
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_action_response_cache.json"))
+ Some(json!([{
+ "title": "Cache \"https://deno.land/x/a/mod.ts\" and its dependencies.",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 0, "character": 19 },
+ "end": { "line": 0, "character": 49 }
+ },
+ "severity": 1,
+ "code": "no-cache",
+ "source": "deno",
+ "message": "Unable to load the remote module: \"https://deno.land/x/a/mod.ts\".",
+ "data": {
+ "specifier": "https://deno.land/x/a/mod.ts"
+ }
+ }],
+ "command": {
+ "title": "",
+ "command": "deno.cache",
+ "arguments": [["https://deno.land/x/a/mod.ts"]]
+ }
+ }]))
);
session.shutdown_and_exit();
}
#[test]
fn lsp_code_actions_deno_cache_npm() {
- let mut session = TestSession::from_file("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
+ let mut session = TestSession::from_client(client);
let diagnostics = session.did_open(json!({
"textDocument": {
"uri": "file:///a/file.ts",
@@ -3445,27 +4050,85 @@ fn lsp_code_actions_deno_cache_npm() {
}));
assert_eq!(
diagnostics.with_source("deno"),
- load_fixture_as("code_actions/cache_npm/diagnostics.json")
+ serde_json::from_value(json!({
+ "uri": "file:///a/file.ts",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 0, "character": 18 },
+ "end": { "line": 0, "character": 29 }
+ },
+ "severity": 1,
+ "code": "no-cache-npm",
+ "source": "deno",
+ "message": "Uncached or missing npm package: \"chalk\".",
+ "data": { "specifier": "npm:chalk" }
+ }],
+ "version": 1
+ }))
+ .unwrap()
);
let (maybe_res, maybe_err) = session
.client
.write_request(
"textDocument/codeAction",
- load_fixture("code_actions/cache_npm/cache_action.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts"
+ },
+ "range": {
+ "start": { "line": 0, "character": 18 },
+ "end": { "line": 0, "character": 29 }
+ },
+ "context": {
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 0, "character": 18 },
+ "end": { "line": 0, "character": 29 }
+ },
+ "severity": 1,
+ "code": "no-cache-npm",
+ "source": "deno",
+ "message": "Uncached or missing npm package: \"chalk\".",
+ "data": { "specifier": "npm:chalk" }
+ }],
+ "only": ["quickfix"]
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_actions/cache_npm/cache_response.json"))
+ Some(json!([{
+ "title": "Cache \"npm:chalk\" and its dependencies.",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 0, "character": 18 },
+ "end": { "line": 0, "character": 29 }
+ },
+ "severity": 1,
+ "code": "no-cache-npm",
+ "source": "deno",
+ "message": "Uncached or missing npm package: \"chalk\".",
+ "data": { "specifier": "npm:chalk" }
+ }],
+ "command": {
+ "title": "",
+ "command": "deno.cache",
+ "arguments": [["npm:chalk"]]
+ }
+ }]))
);
session.shutdown_and_exit();
}
#[test]
fn lsp_code_actions_imports() {
- let mut session = TestSession::from_file("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
+ let mut session = TestSession::from_client(client);
session.did_open(json!({
"textDocument": {
"uri": "file:///a/file00.ts",
@@ -3516,25 +4179,195 @@ export class DuckConfig {
.client
.write_request(
"textDocument/codeAction",
- load_fixture("code_action_params_imports.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file00.ts"
+ },
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 6, "character": 0 }
+ },
+ "context": {
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 0, "character": 50 },
+ "end": { "line": 0, "character": 67 }
+ },
+ "severity": 1,
+ "code": 2304,
+ "source": "deno-ts",
+ "message": "Cannot find name 'DuckConfigOptions'."
+ }, {
+ "range": {
+ "start": { "line": 4, "character": 39 },
+ "end": { "line": 4, "character": 49 }
+ },
+ "severity": 1,
+ "code": 2304,
+ "source": "deno-ts",
+ "message": "Cannot find name 'DuckConfig'."
+ }],
+ "only": ["quickfix"]
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_action_response_imports.json"))
+ Some(json!([{
+ "title": "Add import from \"./file02.ts\"",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 0, "character": 50 },
+ "end": { "line": 0, "character": 67 }
+ },
+ "severity": 1,
+ "code": 2304,
+ "source": "deno-ts",
+ "message": "Cannot find name 'DuckConfigOptions'."
+ }],
+ "edit": {
+ "documentChanges": [{
+ "textDocument": {
+ "uri": "file:///a/file00.ts",
+ "version": 1
+ },
+ "edits": [{
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 0, "character": 0 }
+ },
+ "newText": "import { DuckConfigOptions } from \"./file02.ts\";\n\n"
+ }]
+ }]
+ }
+ }, {
+ "title": "Add all missing imports",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 0, "character": 50 },
+ "end": { "line": 0, "character": 67 }
+ },
+ "severity": 1,
+ "code": 2304,
+ "source": "deno-ts",
+ "message": "Cannot find name 'DuckConfigOptions'."
+ }],
+ "data": {
+ "specifier": "file:///a/file00.ts",
+ "fixId": "fixMissingImport"
+ }
+ }, {
+ "title": "Add import from \"./file01.ts\"",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 4, "character": 39 },
+ "end": { "line": 4, "character": 49 }
+ },
+ "severity": 1,
+ "code": 2304,
+ "source": "deno-ts",
+ "message": "Cannot find name 'DuckConfig'."
+ }],
+ "edit": {
+ "documentChanges": [{
+ "textDocument": {
+ "uri": "file:///a/file00.ts",
+ "version": 1
+ },
+ "edits": [{
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 0, "character": 0 }
+ },
+ "newText": "import { DuckConfig } from \"./file01.ts\";\n\n"
+ }]
+ }]
+ }
+ }]))
);
let (maybe_res, maybe_err) = session
.client
.write_request(
"codeAction/resolve",
- load_fixture("code_action_resolve_params_imports.json"),
+ json!({
+ "title": "Add all missing imports",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 0, "character": 50 },
+ "end": { "line": 0, "character": 67 }
+ },
+ "severity": 1,
+ "code": 2304,
+ "source": "deno-ts",
+ "message": "Cannot find name 'DuckConfigOptions'."
+ }, {
+ "range": {
+ "start": { "line": 4, "character": 39 },
+ "end": { "line": 4, "character": 49 }
+ },
+ "severity": 1,
+ "code": 2304,
+ "source": "deno-ts",
+ "message": "Cannot find name 'DuckConfig'."
+ }],
+ "data": {
+ "specifier": "file:///a/file00.ts",
+ "fixId": "fixMissingImport"
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_action_resolve_response_imports.json"))
+ Some(json!({
+ "title": "Add all missing imports",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 0, "character": 50 },
+ "end": { "line": 0, "character": 67 }
+ },
+ "severity": 1,
+ "code": 2304,
+ "source": "deno-ts",
+ "message": "Cannot find name 'DuckConfigOptions'."
+ }, {
+ "range": {
+ "start": { "line": 4, "character": 39 },
+ "end": { "line": 4, "character": 49 }
+ },
+ "severity": 1,
+ "code": 2304,
+ "source": "deno-ts",
+ "message": "Cannot find name 'DuckConfig'."
+ }],
+ "edit": {
+ "documentChanges": [{
+ "textDocument": {
+ "uri": "file:///a/file00.ts",
+ "version": 1
+ },
+ "edits": [{
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 0, "character": 0 }
+ },
+ "newText": "import { DuckConfig } from \"./file01.ts\";\nimport { DuckConfigOptions } from \"./file02.ts\";\n\n"
+ }]
+ }]
+ },
+ "data": {
+ "specifier": "file:///a/file00.ts",
+ "fixId": "fixMissingImport"
+ }
+ }))
);
session.shutdown_and_exit();
@@ -3542,7 +4375,8 @@ export class DuckConfig {
#[test]
fn lsp_code_actions_refactor() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -3557,31 +4391,216 @@ fn lsp_code_actions_refactor() {
let (maybe_res, maybe_err) = client
.write_request(
"textDocument/codeAction",
- load_fixture("code_action_params_refactor.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts"
+ },
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 1, "character": 0 }
+ },
+ "context": {
+ "diagnostics": [],
+ "only": ["refactor"]
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_action_response_refactor.json"))
+ Some(json!([{
+ "title": "Extract to function in module scope",
+ "kind": "refactor.extract.function",
+ "isPreferred": false,
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 1, "character": 0 }
+ },
+ "refactorName": "Extract Symbol",
+ "actionName": "function_scope_0"
+ }
+ }, {
+ "title": "Extract to constant in enclosing scope",
+ "kind": "refactor.extract.constant",
+ "isPreferred": false,
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 1, "character": 0 }
+ },
+ "refactorName": "Extract Symbol",
+ "actionName": "constant_scope_0"
+ }
+ }, {
+ "title": "Move to a new file",
+ "kind": "refactor.move.newFile",
+ "isPreferred": false,
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 1, "character": 0 }
+ },
+ "refactorName": "Move to a new file",
+ "actionName": "Move to a new file"
+ }
+ }, {
+ "title": "Convert default export to named export",
+ "kind": "refactor.rewrite.export.named",
+ "isPreferred": false,
+ "disabled": {
+ "reason": "This file already has a default export"
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 1, "character": 0 }
+ },
+ "refactorName": "Convert export",
+ "actionName": "Convert default export to named export"
+ }
+ }, {
+ "title": "Convert named export to default export",
+ "kind": "refactor.rewrite.export.default",
+ "isPreferred": false,
+ "disabled": {
+ "reason": "This file already has a default export"
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 1, "character": 0 }
+ },
+ "refactorName": "Convert export",
+ "actionName": "Convert named export to default export"
+ }
+ }, {
+ "title": "Convert namespace import to named imports",
+ "kind": "refactor.rewrite.import.named",
+ "isPreferred": false,
+ "disabled": {
+ "reason": "Selection is not an import declaration."
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 1, "character": 0 }
+ },
+ "refactorName": "Convert import",
+ "actionName": "Convert namespace import to named imports"
+ }
+ }, {
+ "title": "Convert named imports to default import",
+ "kind": "refactor.rewrite.import.default",
+ "isPreferred": false,
+ "disabled": {
+ "reason": "Selection is not an import declaration."
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 1, "character": 0 }
+ },
+ "refactorName": "Convert import",
+ "actionName": "Convert named imports to default import"
+ }
+ }, {
+ "title": "Convert named imports to namespace import",
+ "kind": "refactor.rewrite.import.namespace",
+ "isPreferred": false,
+ "disabled": {
+ "reason": "Selection is not an import declaration."
+ },
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 1, "character": 0 }
+ },
+ "refactorName": "Convert import",
+ "actionName": "Convert named imports to namespace import"
+ }
+ }]))
);
let (maybe_res, maybe_err) = client
.write_request(
"codeAction/resolve",
- load_fixture("code_action_resolve_params_refactor.json"),
+ json!({
+ "title": "Extract to interface",
+ "kind": "refactor.extract.interface",
+ "isPreferred": true,
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 0, "character": 7 },
+ "end": { "line": 0, "character": 33 }
+ },
+ "refactorName": "Extract type",
+ "actionName": "Extract to interface"
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_action_resolve_response_refactor.json"))
+ Some(json!({
+ "title": "Extract to interface",
+ "kind": "refactor.extract.interface",
+ "edit": {
+ "documentChanges": [{
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "version": 1
+ },
+ "edits": [{
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 0, "character": 0 }
+ },
+ "newText": "interface NewType {\n a?: number;\n b?: string;\n}\n\n"
+ }, {
+ "range": {
+ "start": { "line": 0, "character": 7 },
+ "end": { "line": 0, "character": 33 }
+ },
+ "newText": "NewType"
+ }]
+ }]
+ },
+ "isPreferred": true,
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 0, "character": 7 },
+ "end": { "line": 0, "character": 33 }
+ },
+ "refactorName": "Extract type",
+ "actionName": "Extract to interface"
+ }
+ }))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_code_actions_refactor_no_disabled_support() {
- let mut client = init("initialize_params_ca_no_disabled.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize(|builder| {
+ builder.with_capabilities(|c| {
+ let doc = c.text_document.as_mut().unwrap();
+ let code_action = doc.code_action.as_mut().unwrap();
+ code_action.disabled_support = Some(false);
+ });
+ });
did_open(
&mut client,
json!({
@@ -3601,20 +4620,12 @@ fn lsp_code_actions_refactor_no_disabled_support() {
"uri": "file:///a/file.ts"
},
"range": {
- "start": {
- "line": 0,
- "character": 0
- },
- "end": {
- "line": 14,
- "character": 0
- }
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 14, "character": 0 }
},
"context": {
"diagnostics": [],
- "only": [
- "refactor"
- ]
+ "only": ["refactor"]
}
}),
)
@@ -3622,18 +4633,55 @@ fn lsp_code_actions_refactor_no_disabled_support() {
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_action_response_no_disabled.json"))
+ Some(json!([{
+ "title": "Extract to function in module scope",
+ "kind": "refactor.extract.function",
+ "isPreferred": false,
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 14, "character": 0 }
+ },
+ "refactorName": "Extract Symbol",
+ "actionName": "function_scope_0"
+ }
+ }, {
+ "title": "Move to a new file",
+ "kind": "refactor.move.newFile",
+ "isPreferred": false,
+ "data": {
+ "specifier": "file:///a/file.ts",
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 14, "character": 0 }
+ },
+ "refactorName": "Move to a new file",
+ "actionName": "Move to a new file"
+ }
+ }]))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_code_actions_deadlock() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
+ let large_file_text =
+ fs::read_to_string(testdata_path().join("lsp").join("large_file.txt"))
+ .unwrap();
client
.write_notification(
"textDocument/didOpen",
- load_fixture("did_open_params_large.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "languageId": "javascript",
+ "version": 1,
+ "text": large_file_text,
+ }
+ }),
)
.unwrap();
let (id, method, _) = client.read_request::<Value>().unwrap();
@@ -3665,14 +4713,8 @@ fn lsp_code_actions_deadlock() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 444,
- "character": 11
- },
- "end": {
- "line": 444,
- "character": 14
- }
+ "start": { "line": 444, "character": 11 },
+ "end": { "line": 444, "character": 14 }
},
"text": "+++"
}
@@ -3691,14 +4733,8 @@ fn lsp_code_actions_deadlock() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 445,
- "character": 4
- },
- "end": {
- "line": 445,
- "character": 4
- }
+ "start": { "line": 445, "character": 4 },
+ "end": { "line": 445, "character": 4 }
},
"text": "// "
}
@@ -3717,14 +4753,8 @@ fn lsp_code_actions_deadlock() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 477,
- "character": 4
- },
- "end": {
- "line": 477,
- "character": 9
- }
+ "start": { "line": 477, "character": 4 },
+ "end": { "line": 477, "character": 9 }
},
"text": "error"
}
@@ -3743,10 +4773,7 @@ fn lsp_code_actions_deadlock() {
"textDocument": {
"uri": "file:///a/file.ts",
},
- "position": {
- "line": 609,
- "character": 33,
- }
+ "position": { "line": 609, "character": 33, }
}),
)
.unwrap();
@@ -3755,7 +4782,28 @@ fn lsp_code_actions_deadlock() {
let (maybe_res, maybe_err) = client
.write_request::<_, _, Value>(
"textDocument/codeAction",
- load_fixture("code_action_params_deadlock.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts"
+ },
+ "range": {
+ "start": { "line": 441, "character": 33 },
+ "end": { "line": 441, "character": 42 }
+ },
+ "context": {
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 441, "character": 33 },
+ "end": { "line": 441, "character": 42 }
+ },
+ "severity": 1,
+ "code": 7031,
+ "source": "deno-ts",
+ "message": "Binding element 'debugFlag' implicitly has an 'any' type."
+ }],
+ "only": [ "quickfix" ]
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
@@ -3763,12 +4811,13 @@ fn lsp_code_actions_deadlock() {
read_diagnostics(&mut client);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_completions() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -3787,10 +4836,7 @@ fn lsp_completions() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 5
- },
+ "position": { "line": 0, "character": 5 },
"context": {
"triggerKind": 2,
"triggerCharacter": "."
@@ -3808,20 +4854,44 @@ fn lsp_completions() {
let (maybe_res, maybe_err) = client
.write_request(
"completionItem/resolve",
- load_fixture("completion_resolve_params.json"),
+ json!({
+ "label": "build",
+ "kind": 6,
+ "sortText": "1",
+ "insertTextFormat": 1,
+ "data": {
+ "tsc": {
+ "specifier": "file:///a/file.ts",
+ "position": 5,
+ "name": "build",
+ "useCodeSnippet": false
+ }
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("completion_resolve_response.json"))
+ Some(json!({
+ "label": "build",
+ "kind": 6,
+ "detail": "const Deno.build: {\n target: string;\n arch: \"x86_64\" | \"aarch64\";\n os: \"darwin\" | \"linux\" | \"windows\" | \"freebsd\" | \"netbsd\" | \"aix\" | \"solaris\" | \"illumos\";\n vendor: string;\n env?: string | undefined;\n}",
+ "documentation": {
+ "kind": "markdown",
+ "value": "Information related to the build of the current Deno runtime.\n\nUsers are discouraged from code branching based on this information, as\nassumptions about what is available in what build environment might change\nover time. Developers should specifically sniff out the features they\nintend to use.\n\nThe intended use for the information is for logging and debugging purposes.\n\n*@category* - Runtime Environment"
+ },
+ "sortText": "1",
+ "insertTextFormat": 1
+ }))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_completions_private_fields() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -3840,10 +4910,7 @@ fn lsp_completions_private_fields() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 57
- },
+ "position": { "line": 0, "character": 57 },
"context": {
"triggerKind": 1
}
@@ -3859,12 +4926,13 @@ fn lsp_completions_private_fields() {
} else {
panic!("unexpected response");
}
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_completions_optional() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -3879,7 +4947,16 @@ fn lsp_completions_optional() {
let (maybe_res, maybe_err) = client
.write_request(
"textDocument/completion",
- load_fixture("completion_request_params_optional.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts"
+ },
+ "position": { "line": 8, "character": 4 },
+ "context": {
+ "triggerKind": 2,
+ "triggerCharacter": "."
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
@@ -3910,7 +4987,21 @@ fn lsp_completions_optional() {
let (maybe_res, maybe_err) = client
.write_request(
"completionItem/resolve",
- load_fixture("completion_resolve_params_optional.json"),
+ json!({
+ "label": "b?",
+ "kind": 5,
+ "sortText": "1",
+ "filterText": "b",
+ "insertText": "b",
+ "data": {
+ "tsc": {
+ "specifier": "file:///a/file.ts",
+ "position": 79,
+ "name": "b",
+ "useCodeSnippet": false
+ }
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
@@ -3929,12 +5020,13 @@ fn lsp_completions_optional() {
"insertText": "b"
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_completions_auto_import() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -3964,10 +5056,7 @@ fn lsp_completions_auto_import() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 2,
- "character": 0,
- },
+ "position": { "line": 2, "character": 0, },
"context": {
"triggerKind": 1,
}
@@ -4028,14 +5117,8 @@ fn lsp_completions_auto_import() {
"additionalTextEdits": [
{
"range": {
- "start": {
- "line": 0,
- "character": 0
- },
- "end": {
- "line": 0,
- "character": 0
- }
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 0, "character": 0 }
},
"newText": "import { foo } from \"./b.ts\";\n\n"
}
@@ -4046,7 +5129,8 @@ fn lsp_completions_auto_import() {
#[test]
fn lsp_completions_snippet() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -4065,10 +5149,7 @@ fn lsp_completions_snippet() {
"textDocument": {
"uri": "file:///a/a.tsx"
},
- "position": {
- "line": 5,
- "character": 13,
- },
+ "position": { "line": 5, "character": 13, },
"context": {
"triggerKind": 1,
}
@@ -4159,7 +5240,13 @@ fn lsp_completions_snippet() {
#[test]
fn lsp_completions_no_snippet() {
- let mut client = init("initialize_params_no_snippet.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize(|builder| {
+ builder.with_capabilities(|c| {
+ let doc = c.text_document.as_mut().unwrap();
+ doc.completion = None;
+ });
+ });
did_open(
&mut client,
json!({
@@ -4178,10 +5265,7 @@ fn lsp_completions_no_snippet() {
"textDocument": {
"uri": "file:///a/a.tsx"
},
- "position": {
- "line": 5,
- "character": 13,
- },
+ "position": { "line": 5, "character": 13, },
"context": {
"triggerKind": 1,
}
@@ -4225,8 +5309,9 @@ fn lsp_completions_no_snippet() {
#[test]
fn lsp_completions_npm() {
- let _g = http_server();
- let mut client = init("initialize_params.json");
+ let context = TestContextBuilder::new().use_http_server().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -4248,8 +5333,7 @@ fn lsp_completions_npm() {
"uris": [
{
"uri": "npm:@denotest/cjs-default-export",
- },
- {
+ }, {
"uri": "npm:chalk",
}
]
@@ -4271,14 +5355,8 @@ fn lsp_completions_npm() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 2,
- "character": 0
- },
- "end": {
- "line": 2,
- "character": 0
- }
+ "start": { "line": 2, "character": 0 },
+ "end": { "line": 2, "character": 0 }
},
"text": "cjsDefault."
}
@@ -4295,10 +5373,7 @@ fn lsp_completions_npm() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 2,
- "character": 11
- },
+ "position": { "line": 2, "character": 11 },
"context": {
"triggerKind": 2,
"triggerCharacter": "."
@@ -4318,13 +5393,39 @@ fn lsp_completions_npm() {
let (maybe_res, maybe_err) = client
.write_request(
"completionItem/resolve",
- load_fixture("completions/npm/resolve_params.json"),
+ json!({
+ "label": "MyClass",
+ "kind": 6,
+ "sortText": "1",
+ "insertTextFormat": 1,
+ "data": {
+ "tsc": {
+ "specifier": "file:///a/file.ts",
+ "position": 69,
+ "name": "MyClass",
+ "useCodeSnippet": false
+ }
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("completions/npm/resolve_response.json"))
+ Some(json!({
+ "label": "MyClass",
+ "kind": 6,
+ "sortText": "1",
+ "insertTextFormat": 1,
+ "data": {
+ "tsc": {
+ "specifier": "file:///a/file.ts",
+ "position": 69,
+ "name": "MyClass",
+ "useCodeSnippet": false
+ }
+ }
+ }))
);
// now check chalk, which is esm
@@ -4339,14 +5440,8 @@ fn lsp_completions_npm() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 2,
- "character": 0
- },
- "end": {
- "line": 2,
- "character": 11
- }
+ "start": { "line": 2, "character": 0 },
+ "end": { "line": 2, "character": 11 }
},
"text": "chalk."
}
@@ -4363,10 +5458,7 @@ fn lsp_completions_npm() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 2,
- "character": 6
- },
+ "position": { "line": 2, "character": 6 },
"context": {
"triggerKind": 2,
"triggerCharacter": "."
@@ -4383,13 +5475,14 @@ fn lsp_completions_npm() {
panic!("unexpected response");
}
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_npm_specifier_unopened_file() {
- let _g = http_server();
- let mut client = init("initialize_params.json");
+ let context = TestContextBuilder::new().use_http_server().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
// create other.ts, which re-exports an npm specifier
client.deno_dir().write(
@@ -4444,14 +5537,8 @@ fn lsp_npm_specifier_unopened_file() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 2,
- "character": 0
- },
- "end": {
- "line": 2,
- "character": 0
- }
+ "start": { "line": 2, "character": 0 },
+ "end": { "line": 2, "character": 0 }
},
"text": "chalk."
}
@@ -4469,10 +5556,7 @@ fn lsp_npm_specifier_unopened_file() {
"textDocument": {
"uri": main_url
},
- "position": {
- "line": 2,
- "character": 6
- },
+ "position": { "line": 2, "character": 6 },
"context": {
"triggerKind": 2,
"triggerCharacter": "."
@@ -4492,8 +5576,9 @@ fn lsp_npm_specifier_unopened_file() {
#[test]
fn lsp_completions_node_specifier() {
- let _g = http_server();
- let mut client = init("initialize_params.json");
+ let context = TestContextBuilder::new().use_http_server().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
let diagnostics = CollectedDiagnostics(did_open(
&mut client,
json!({
@@ -4578,9 +5663,7 @@ fn lsp_completions_node_specifier() {
},
"context": {
"diagnostics": json!(diagnostics),
- "only": [
- "quickfix"
- ]
+ "only": ["quickfix"]
}
}),
)
@@ -4737,13 +5820,16 @@ fn lsp_completions_node_specifier() {
panic!("unexpected response");
}
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_completions_registry() {
- let _g = http_server();
- let mut client = init("initialize_params_registry.json");
+ let context = TestContextBuilder::new().use_http_server().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.add_test_server_suggestions();
+ });
did_open(
&mut client,
json!({
@@ -4762,10 +5848,7 @@ fn lsp_completions_registry() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 46
- },
+ "position": { "line": 0, "character": 46 },
"context": {
"triggerKind": 2,
"triggerCharacter": "@"
@@ -4783,21 +5866,50 @@ fn lsp_completions_registry() {
let (maybe_res, maybe_err) = client
.write_request(
"completionItem/resolve",
- load_fixture("completion_resolve_params_registry.json"),
+ json!({
+ "label": "v2.0.0",
+ "kind": 19,
+ "detail": "(version)",
+ "sortText": "0000000003",
+ "filterText": "http://localhost:4545/x/a@v2.0.0",
+ "textEdit": {
+ "range": {
+ "start": { "line": 0, "character": 20 },
+ "end": { "line": 0, "character": 46 }
+ },
+ "newText": "http://localhost:4545/x/a@v2.0.0"
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("completion_resolve_response_registry.json"))
+ Some(json!({
+ "label": "v2.0.0",
+ "kind": 19,
+ "detail": "(version)",
+ "sortText": "0000000003",
+ "filterText": "http://localhost:4545/x/a@v2.0.0",
+ "textEdit": {
+ "range": {
+ "start": { "line": 0, "character": 20 },
+ "end": { "line": 0, "character": 46 }
+ },
+ "newText": "http://localhost:4545/x/a@v2.0.0"
+ }
+ }))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_completions_registry_empty() {
- let _g = http_server();
- let mut client = init("initialize_params_registry.json");
+ let context = TestContextBuilder::new().use_http_server().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.add_test_server_suggestions();
+ });
did_open(
&mut client,
json!({
@@ -4816,10 +5928,7 @@ fn lsp_completions_registry_empty() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 20
- },
+ "position": { "line": 0, "character": 20 },
"context": {
"triggerKind": 2,
"triggerCharacter": "\""
@@ -4830,15 +5939,46 @@ fn lsp_completions_registry_empty() {
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("completion_request_response_empty.json"))
+ Some(json!({
+ "isIncomplete": false,
+ "items": [{
+ "label": ".",
+ "kind": 19,
+ "detail": "(local)",
+ "sortText": "1",
+ "insertText": ".",
+ "commitCharacters": ["\"", "'"]
+ }, {
+ "label": "..",
+ "kind": 19,
+ "detail": "(local)",
+ "sortText": "1",
+ "insertText": "..",
+ "commitCharacters": ["\"", "'" ]
+ }, {
+ "label": "http://localhost:4545",
+ "kind": 19,
+ "detail": "(registry)",
+ "sortText": "2",
+ "textEdit": {
+ "range": {
+ "start": { "line": 0, "character": 20 },
+ "end": { "line": 0, "character": 20 }
+ },
+ "newText": "http://localhost:4545"
+ },
+ "commitCharacters": ["\"", "'", "/"]
+ }]
+ }))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_auto_discover_registry() {
- let _g = http_server();
- let mut client = init("initialize_params.json");
+ let context = TestContextBuilder::new().use_http_server().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -4857,10 +5997,7 @@ fn lsp_auto_discover_registry() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 46
- },
+ "position": { "line": 0, "character": 46 },
"context": {
"triggerKind": 2,
"triggerCharacter": "@"
@@ -4879,31 +6016,19 @@ fn lsp_auto_discover_registry() {
"suggestions": true,
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_cache_location() {
- let _g = http_server();
- let temp_dir = TempDir::new();
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params_registry.json"))
- .unwrap();
-
- params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap());
- if let Some(Value::Object(mut map)) = params.initialization_options {
- map.insert("cache".to_string(), json!(".cache"));
- params.initialization_options = Some(Value::Object(map));
- }
+ let context = TestContextBuilder::new().use_http_server().build();
+ let temp_dir = context.deno_dir();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_cache(".cache").add_test_server_suggestions();
+ });
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
- client.write_notification("initialized", json!({})).unwrap();
let mut session = TestSession::from_client(client);
-
session.did_open(json!({
"textDocument": {
"uri": "file:///a/file_01.ts",
@@ -4913,7 +6038,14 @@ fn lsp_cache_location() {
}
}));
let diagnostics =
- session.did_open(load_fixture("did_open_params_import_hover.json"));
+ session.did_open(json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "languageId": "typescript",
+ "version": 1,
+ "text": "import * as a from \"http://127.0.0.1:4545/xTypeScriptTypes.js\";\n// @deno-types=\"http://127.0.0.1:4545/type_definitions/foo.d.ts\"\nimport * as b from \"http://127.0.0.1:4545/type_definitions/foo.js\";\nimport * as c from \"http://127.0.0.1:4545/subdir/type_reference.js\";\nimport * as d from \"http://127.0.0.1:4545/subdir/mod1.ts\";\nimport * as e from \"data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=\";\nimport * as f from \"./file_01.ts\";\nimport * as g from \"http://localhost:4545/x/a/mod.ts\";\n\nconsole.log(a, b, c, d, e, f, g);\n"
+ }
+ }));
assert_eq!(diagnostics.viewed().len(), 7);
let (maybe_res, maybe_err) = session
.client
@@ -4937,10 +6069,7 @@ fn lsp_cache_location() {
"textDocument": {
"uri": "file:///a/file.ts",
},
- "position": {
- "line": 0,
- "character": 28
- }
+ "position": { "line": 0, "character": 28 }
}),
)
.unwrap();
@@ -4953,14 +6082,8 @@ fn lsp_cache_location() {
"value": "**Resolved Dependency**\n\n**Code**: http&#8203;://127.0.0.1:4545/xTypeScriptTypes.js\n\n**Types**: http&#8203;://127.0.0.1:4545/xTypeScriptTypes.d.ts\n"
},
"range": {
- "start": {
- "line": 0,
- "character": 19
- },
- "end":{
- "line": 0,
- "character": 62
- }
+ "start": { "line": 0, "character": 19 },
+ "end": { "line": 0, "character": 62 }
}
}))
);
@@ -4972,10 +6095,7 @@ fn lsp_cache_location() {
"textDocument": {
"uri": "file:///a/file.ts",
},
- "position": {
- "line": 7,
- "character": 28
- }
+ "position": { "line": 7, "character": 28 }
}),
)
.unwrap();
@@ -4988,14 +6108,8 @@ fn lsp_cache_location() {
"value": "**Resolved Dependency**\n\n**Code**: http&#8203;://localhost:4545/x/a/mod.ts\n\n\n---\n\n**a**\n\nmod.ts"
},
"range": {
- "start": {
- "line": 7,
- "character": 19
- },
- "end": {
- "line": 7,
- "character": 53
- }
+ "start": { "line": 7, "character": 19 },
+ "end": { "line": 7, "character": 53 }
}
}))
);
@@ -5010,19 +6124,17 @@ fn lsp_cache_location() {
/// and cache files.
#[test]
fn lsp_tls_cert() {
- let _g = http_server();
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params_tls_cert.json"))
- .unwrap();
+ let context = TestContextBuilder::new().use_http_server().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder
+ .set_suggest_imports_hosts(vec![
+ ("http://localhost:4545/".to_string(), true),
+ ("https://localhost:5545/".to_string(), true),
+ ])
+ .set_tls_certificate("");
+ });
- params.root_uri = Some(Url::from_file_path(testdata_path()).unwrap());
-
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
- client.write_notification("initialized", json!({})).unwrap();
let mut session = TestSession::from_client(client);
session.did_open(json!({
@@ -5033,8 +6145,14 @@ fn lsp_tls_cert() {
"text": "export const a = \"a\";\n",
}
}));
- let diagnostics =
- session.did_open(load_fixture("did_open_params_tls_cert.json"));
+ let diagnostics = session.did_open(json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "languageId": "typescript",
+ "version": 1,
+ "text": "import * as a from \"https://localhost:5545/xTypeScriptTypes.js\";\n// @deno-types=\"https://localhost:5545/type_definitions/foo.d.ts\"\nimport * as b from \"https://localhost:5545/type_definitions/foo.js\";\nimport * as c from \"https://localhost:5545/subdir/type_reference.js\";\nimport * as d from \"https://localhost:5545/subdir/mod1.ts\";\nimport * as e from \"data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=\";\nimport * as f from \"./file_01.ts\";\nimport * as g from \"http://localhost:4545/x/a/mod.ts\";\n\nconsole.log(a, b, c, d, e, f, g);\n"
+ }
+ }));
let diagnostics = diagnostics.viewed();
assert_eq!(diagnostics.len(), 7);
let (maybe_res, maybe_err) = session
@@ -5059,10 +6177,7 @@ fn lsp_tls_cert() {
"textDocument": {
"uri": "file:///a/file.ts",
},
- "position": {
- "line": 0,
- "character": 28
- }
+ "position": { "line": 0, "character": 28 }
}),
)
.unwrap();
@@ -5075,14 +6190,8 @@ fn lsp_tls_cert() {
"value": "**Resolved Dependency**\n\n**Code**: https&#8203;://localhost:5545/xTypeScriptTypes.js\n"
},
"range": {
- "start": {
- "line": 0,
- "character": 19
- },
- "end":{
- "line": 0,
- "character": 63
- }
+ "start": { "line": 0, "character": 19 },
+ "end": { "line": 0, "character": 63 }
}
}))
);
@@ -5094,10 +6203,7 @@ fn lsp_tls_cert() {
"textDocument": {
"uri": "file:///a/file.ts",
},
- "position": {
- "line": 7,
- "character": 28
- }
+ "position": { "line": 7, "character": 28 }
}),
)
.unwrap();
@@ -5110,14 +6216,8 @@ fn lsp_tls_cert() {
"value": "**Resolved Dependency**\n\n**Code**: http&#8203;://localhost:4545/x/a/mod.ts\n\n\n---\n\n**a**\n\nmod.ts"
},
"range": {
- "start": {
- "line": 7,
- "character": 19
- },
- "end": {
- "line": 7,
- "character": 53
- }
+ "start": { "line": 7, "character": 19 },
+ "end": { "line": 7, "character": 53 }
}
}))
);
@@ -5126,8 +6226,9 @@ fn lsp_tls_cert() {
#[test]
fn lsp_diagnostics_warn_redirect() {
- let _g = http_server();
- let mut client = init("initialize_params.json");
+ let context = TestContextBuilder::new().use_http_server().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -5201,13 +6302,14 @@ fn lsp_diagnostics_warn_redirect() {
version: Some(1),
}
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_redirect_quick_fix() {
- let _g = http_server();
- let mut client = init("initialize_params.json");
+ let context = TestContextBuilder::new().use_http_server().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -5247,20 +6349,12 @@ fn lsp_redirect_quick_fix() {
"uri": "file:///a/file.ts"
},
"range": {
- "start": {
- "line": 0,
- "character": 19
- },
- "end": {
- "line": 0,
- "character": 60
- }
+ "start": { "line": 0, "character": 19 },
+ "end": { "line": 0, "character": 60 }
},
"context": {
"diagnostics": diagnostics,
- "only": [
- "quickfix"
- ]
+ "only": ["quickfix"]
}
})),
)
@@ -5268,14 +6362,47 @@ fn lsp_redirect_quick_fix() {
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_action_redirect_response.json"))
+ Some(json!([{
+ "title": "Update specifier to its redirected specifier.",
+ "kind": "quickfix",
+ "diagnostics": [
+ {
+ "range": {
+ "start": { "line": 0, "character": 19 },
+ "end": { "line": 0, "character": 60 }
+ },
+ "severity": 3,
+ "code": "redirect",
+ "source": "deno",
+ "message": "The import of \"http://127.0.0.1:4545/x_deno_warning.js\" was redirected to \"http://127.0.0.1:4545/lsp/x_deno_warning_redirect.js\".",
+ "data": {
+ "specifier": "http://127.0.0.1:4545/x_deno_warning.js",
+ "redirect": "http://127.0.0.1:4545/lsp/x_deno_warning_redirect.js"
+ }
+ }
+ ],
+ "edit": {
+ "changes": {
+ "file:///a/file.ts": [
+ {
+ "range": {
+ "start": { "line": 0, "character": 19 },
+ "end": { "line": 0, "character": 60 }
+ },
+ "newText": "\"http://127.0.0.1:4545/lsp/x_deno_warning_redirect.js\""
+ }
+ ]
+ }
+ }
+ }]))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_diagnostics_deprecated() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
let diagnostics = did_open(
&mut client,
json!({
@@ -5294,50 +6421,48 @@ fn lsp_diagnostics_deprecated() {
"uri": "file:///a/file.ts",
"diagnostics": [],
"version": 1
- },
- {
+ }, {
"uri": "file:///a/file.ts",
"diagnostics": [],
"version": 1
- },
- {
+ }, {
"uri": "file:///a/file.ts",
"diagnostics": [
{
"range": {
- "start": {
- "line": 3,
- "character": 0
- },
- "end": {
- "line": 3,
- "character": 1
- }
+ "start": { "line": 3, "character": 0 },
+ "end": { "line": 3, "character": 1 }
},
"severity": 4,
"code": 6385,
"source": "deno-ts",
"message": "'a' is deprecated.",
"relatedInformation": [],
- "tags": [
- 2
- ]
+ "tags": [2]
}
],
"version": 1
}
])
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_diagnostics_deno_types() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
client
.write_notification(
"textDocument/didOpen",
- load_fixture("did_open_params_deno_types.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "languageId": "typescript",
+ "version": 1,
+ "text": "/// <reference types=\"https://example.com/a/b.d.ts\" />\n/// <reference path=\"https://example.com/a/c.ts\"\n\n// @deno-types=https://example.com/a/d.d.ts\nimport * as d from \"https://example.com/a/d.js\";\n\n// @deno-types=\"https://example.com/a/e.d.ts\"\nimport * as e from \"https://example.com/a/e.js\";\n\nconsole.log(d, e);\n"
+ }
+ }),
)
.unwrap();
let (id, method, _) = client.read_request::<Value>().unwrap();
@@ -5359,12 +6484,14 @@ fn lsp_diagnostics_deno_types() {
assert!(maybe_err.is_none());
let diagnostics = read_diagnostics(&mut client);
assert_eq!(diagnostics.viewed().len(), 5);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_diagnostics_refresh_dependents() {
- let mut session = TestSession::from_file("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
+ let mut session = TestSession::from_client(client);
session.did_open(json!({
"textDocument": {
"uri": "file:///a/file_00.ts",
@@ -5396,14 +6523,8 @@ fn lsp_diagnostics_refresh_dependents() {
"diagnostics": [
{
"range": {
- "start": {
- "line": 0,
- "character": 12
- },
- "end": {
- "line": 0,
- "character": 13
- }
+ "start": { "line": 0, "character": 12 },
+ "end": { "line": 0, "character": 13 }
},
"severity": 1,
"code": 2305,
@@ -5428,14 +6549,8 @@ fn lsp_diagnostics_refresh_dependents() {
"contentChanges": [
{
"range": {
- "start": {
- "line": 1,
- "character": 0
- },
- "end": {
- "line": 1,
- "character": 0
- }
+ "start": { "line": 1, "character": 0 },
+ "end": { "line": 1, "character": 0 }
},
"text": "export const b = \"b\";\n"
}
@@ -5466,7 +6581,8 @@ struct PerformanceAverages {
#[test]
fn lsp_performance() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -5485,10 +6601,7 @@ fn lsp_performance() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 19
- }
+ "position": { "line": 0, "character": 19 }
}),
)
.unwrap();
@@ -5503,12 +6616,13 @@ fn lsp_performance() {
} else {
panic!("unexpected result");
}
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_format_no_changes() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -5537,12 +6651,13 @@ fn lsp_format_no_changes() {
assert!(maybe_err.is_none());
assert_eq!(maybe_res, Some(json!(null)));
client.assert_no_notification("window/showMessage");
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_format_error() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -5570,12 +6685,13 @@ fn lsp_format_error() {
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(maybe_res, Some(json!(null)));
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_format_mbc() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -5604,36 +6720,64 @@ fn lsp_format_mbc() {
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(json!(load_fixture("formatting_mbc_response.json")))
+ Some(json!([{
+ "range": {
+ "start": { "line": 0, "character": 12 },
+ "end": { "line": 0, "character": 13 }
+ },
+ "newText": "\""
+ }, {
+ "range": {
+ "start": { "line": 0, "character": 21 },
+ "end": { "line": 0, "character": 22 }
+ },
+ "newText": "\";"
+ }, {
+ "range": {
+ "start": { "line": 1, "character": 12 },
+ "end": { "line": 1, "character": 13 }
+ },
+ "newText": "\""
+ }, {
+ "range": {
+ "start": { "line": 1, "character": 23 },
+ "end": { "line": 1, "character": 25 }
+ },
+ "newText": "\");"
+ }]))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_format_exclude_with_config() {
- let temp_dir = TempDir::new();
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
- let deno_fmt_jsonc =
- serde_json::to_vec_pretty(&load_fixture("deno.fmt.exclude.jsonc")).unwrap();
- fs::write(temp_dir.path().join("deno.fmt.jsonc"), deno_fmt_jsonc).unwrap();
-
- params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap());
- if let Some(Value::Object(mut map)) = params.initialization_options {
- map.insert("config".to_string(), json!("./deno.fmt.jsonc"));
- params.initialization_options = Some(Value::Object(map));
- }
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
+ temp_dir.write(
+ "deno.fmt.jsonc",
+ r#"{
+ "fmt": {
+ "files": {
+ "exclude": ["ignored.ts"]
+ },
+ "options": {
+ "useTabs": true,
+ "lineWidth": 40,
+ "indentWidth": 8,
+ "singleQuote": true,
+ "proseWrap": "always"
+ }
+ }
+ }"#,
+ );
- let file_uri =
- ModuleSpecifier::from_file_path(temp_dir.path().join("ignored.ts"))
- .unwrap()
- .to_string();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_config("./deno.fmt.jsonc");
+ });
+
+ let file_uri = temp_dir.uri().join("ignored.ts").unwrap();
did_open(
&mut client,
json!({
@@ -5661,31 +6805,38 @@ fn lsp_format_exclude_with_config() {
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(maybe_res, Some(json!(null)));
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_format_exclude_default_config() {
- let temp_dir = TempDir::new();
- let workspace_root = temp_dir.path().canonicalize().unwrap();
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
- let deno_jsonc =
- serde_json::to_vec_pretty(&load_fixture("deno.fmt.exclude.jsonc")).unwrap();
- fs::write(workspace_root.join("deno.jsonc"), deno_jsonc).unwrap();
-
- params.root_uri = Some(Url::from_file_path(workspace_root.clone()).unwrap());
-
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
- let file_uri =
- ModuleSpecifier::from_file_path(workspace_root.join("ignored.ts"))
- .unwrap()
- .to_string();
+ temp_dir.write(
+ "deno.fmt.jsonc",
+ r#"{
+ "fmt": {
+ "files": {
+ "exclude": ["ignored.ts"]
+ },
+ "options": {
+ "useTabs": true,
+ "lineWidth": 40,
+ "indentWidth": 8,
+ "singleQuote": true,
+ "proseWrap": "always"
+ }
+ }
+ }"#,
+ );
+
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_config("./deno.fmt.jsonc");
+ });
+
+ let file_uri = temp_dir.uri().join("ignored.ts").unwrap();
did_open(
&mut client,
json!({
@@ -5713,12 +6864,13 @@ fn lsp_format_exclude_default_config() {
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(maybe_res, Some(json!(null)));
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_format_json() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
client
.write_notification(
"textDocument/didOpen",
@@ -5756,25 +6908,17 @@ fn lsp_format_json() {
Some(json!([
{
"range": {
- "start": {
- "line": 0,
- "character": 1
- },
- "end": {
- "line": 0,
- "character": 1
- }
+ "start": { "line": 0, "character": 1 },
+ "end": { "line": 0, "character": 1 }
},
"newText": " "
- },
- {
+ }, {
"range": {
"start": { "line": 0, "character": 7 },
"end": { "line": 0, "character": 7 }
},
"newText": " "
- },
- {
+ }, {
"range": {
"start": { "line": 0, "character": 14 },
"end": { "line": 0, "character": 15 }
@@ -5783,12 +6927,13 @@ fn lsp_format_json() {
}
]))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_json_no_diagnostics() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
client
.write_notification(
"textDocument/didOpen",
@@ -5823,22 +6968,20 @@ fn lsp_json_no_diagnostics() {
"textDocument": {
"uri": "file:///a/file.json"
},
- "position": {
- "line": 0,
- "character": 3
- }
+ "position": { "line": 0, "character": 3 }
}),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(maybe_res, Some(json!(null)));
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_format_markdown() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
client
.write_notification(
"textDocument/didOpen",
@@ -5878,8 +7021,7 @@ fn lsp_format_markdown() {
"end": { "line": 0, "character": 3 }
},
"newText": ""
- },
- {
+ }, {
"range": {
"start": { "line": 0, "character": 15 },
"end": { "line": 0, "character": 15 }
@@ -5888,29 +7030,33 @@ fn lsp_format_markdown() {
}
]))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_format_with_config() {
- let temp_dir = TempDir::new();
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
- let deno_fmt_jsonc =
- serde_json::to_vec_pretty(&load_fixture("deno.fmt.jsonc")).unwrap();
- fs::write(temp_dir.path().join("deno.fmt.jsonc"), deno_fmt_jsonc).unwrap();
-
- params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap());
- if let Some(Value::Object(mut map)) = params.initialization_options {
- map.insert("config".to_string(), json!("./deno.fmt.jsonc"));
- params.initialization_options = Some(Value::Object(map));
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
+ temp_dir.write(
+ "deno.fmt.jsonc",
+ r#"{
+ "fmt": {
+ "options": {
+ "useTabs": true,
+ "lineWidth": 40,
+ "indentWidth": 8,
+ "singleQuote": true,
+ "proseWrap": "always"
+ }
+ }
}
+ "#,
+ );
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_config("./deno.fmt.jsonc");
+ });
client
.write_notification(
@@ -5947,116 +7093,62 @@ fn lsp_format_with_config() {
maybe_res,
Some(json!([{
"range": {
- "start": {
- "line": 1,
- "character": 0
- },
- "end": {
- "line": 1,
- "character": 0
- }
+ "start": { "line": 1, "character": 0 },
+ "end": { "line": 1, "character": 0 }
},
"newText": "\t"
- },
- {
+ }, {
"range": {
- "start": {
- "line": 1,
- "character": 23
- },
- "end": {
- "line": 1,
- "character": 24
- }
+ "start": { "line": 1, "character": 23 },
+ "end": { "line": 1, "character": 24 }
},
"newText": "\n\t\t'"
- },
- {
+ }, {
"range": {
- "start": {
- "line": 1,
- "character": 73
- },
- "end": {
- "line": 1,
- "character": 74
- }
+ "start": { "line": 1, "character": 73 },
+ "end": { "line": 1, "character": 74 }
},
"newText": "',\n\t"
- },
- {
+ }, {
"range": {
- "start": {
- "line": 2,
- "character": 0
- },
- "end": {
- "line": 2,
- "character": 0
- }
+ "start": { "line": 2, "character": 0 },
+ "end": { "line": 2, "character": 0 }
},
"newText": "\t"
- },
- {
+ }, {
"range": {
- "start": {
- "line": 3,
- "character": 0
- },
- "end": {
- "line": 3,
- "character": 0
- }
+ "start": { "line": 3, "character": 0 },
+ "end": { "line": 3, "character": 0 }
},
"newText": "\t"
- },
- {
+ }, {
"range": {
- "start": {
- "line": 3,
- "character": 12
- },
- "end": {
- "line": 3,
- "character": 13
- }
+ "start": { "line": 3, "character": 12 },
+ "end": { "line": 3, "character": 13 }
},
"newText": "'"
- },
- {
+ }, {
"range": {
- "start": {
- "line": 3,
- "character": 22
- },
- "end": {
- "line": 3,
- "character": 24
- }
+ "start": { "line": 3, "character": 22 },
+ "end": { "line": 3, "character": 24 }
},
"newText": "');"
- },
- {
+ }, {
"range": {
- "start": {
- "line": 4,
- "character": 1
- },
- "end": {
- "line": 4,
- "character": 1
- }
+ "start": { "line": 4, "character": 1 },
+ "end": { "line": 4, "character": 1 }
},
"newText": "\n"
}]
))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_markdown_no_diagnostics() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
client
.write_notification(
"textDocument/didOpen",
@@ -6091,23 +7183,21 @@ fn lsp_markdown_no_diagnostics() {
"textDocument": {
"uri": "file:///a/file.md"
},
- "position": {
- "line": 0,
- "character": 3
- }
+ "position": { "line": 0, "character": 3 }
}),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(maybe_res, Some(json!(null)));
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_configuration_did_change() {
- let _g = http_server();
- let mut client = init("initialize_params_did_config_change.json");
+ let context = TestContextBuilder::new().use_http_server().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -6162,10 +7252,7 @@ fn lsp_configuration_did_change() {
"textDocument": {
"uri": "file:///a/file.ts"
},
- "position": {
- "line": 0,
- "character": 46
- },
+ "position": { "line": 0, "character": 46 },
"context": {
"triggerKind": 2,
"triggerCharacter": "@"
@@ -6183,20 +7270,47 @@ fn lsp_configuration_did_change() {
let (maybe_res, maybe_err) = client
.write_request(
"completionItem/resolve",
- load_fixture("completion_resolve_params_registry.json"),
+ json!({
+ "label": "v2.0.0",
+ "kind": 19,
+ "detail": "(version)",
+ "sortText": "0000000003",
+ "filterText": "http://localhost:4545/x/a@v2.0.0",
+ "textEdit": {
+ "range": {
+ "start": { "line": 0, "character": 20 },
+ "end": { "line": 0, "character": 46 }
+ },
+ "newText": "http://localhost:4545/x/a@v2.0.0"
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("completion_resolve_response_registry.json"))
+ Some(json!({
+ "label": "v2.0.0",
+ "kind": 19,
+ "detail": "(version)",
+ "sortText": "0000000003",
+ "filterText": "http://localhost:4545/x/a@v2.0.0",
+ "textEdit": {
+ "range": {
+ "start": { "line": 0, "character": 20 },
+ "end": { "line": 0, "character": 46 }
+ },
+ "newText": "http://localhost:4545/x/a@v2.0.0"
+ }
+ }))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_workspace_symbol() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -6237,80 +7351,54 @@ fn lsp_workspace_symbol() {
"location": {
"uri": "file:///a/file.ts",
"range": {
- "start": {
- "line": 1,
- "character": 2
- },
- "end": {
- "line": 1,
- "character": 17
- }
+ "start": { "line": 1, "character": 2 },
+ "end": { "line": 1, "character": 17 }
}
},
"containerName": "A"
- },
- {
+ }, {
"name": "fieldB",
"kind": 8,
"location": {
"uri": "file:///a/file.ts",
"range": {
- "start": {
- "line": 2,
- "character": 2
- },
- "end": {
- "line": 2,
- "character": 17
- }
+ "start": { "line": 2, "character": 2 },
+ "end": { "line": 2, "character": 17 }
}
},
"containerName": "A"
- },
- {
+ }, {
"name": "fieldC",
"kind": 8,
"location": {
"uri": "file:///a/file_01.ts",
"range": {
- "start": {
- "line": 1,
- "character": 2
- },
- "end": {
- "line": 1,
- "character": 17
- }
+ "start": { "line": 1, "character": 2 },
+ "end": { "line": 1, "character": 17 }
}
},
"containerName": "B"
- },
- {
+ }, {
"name": "fieldD",
"kind": 8,
"location": {
"uri": "file:///a/file_01.ts",
"range": {
- "start": {
- "line": 2,
- "character": 2
- },
- "end": {
- "line": 2,
- "character": 17
- }
+ "start": { "line": 2, "character": 2 },
+ "end": { "line": 2, "character": 17 }
}
},
"containerName": "B"
}
]))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_code_actions_ignore_lint() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -6325,21 +7413,121 @@ fn lsp_code_actions_ignore_lint() {
let (maybe_res, maybe_err) = client
.write_request(
"textDocument/codeAction",
- load_fixture("code_action_ignore_lint_params.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts"
+ },
+ "range": {
+ "start": { "line": 1, "character": 5 },
+ "end": { "line": 1, "character": 12 }
+ },
+ "context": {
+ "diagnostics": [
+ {
+ "range": {
+ "start": { "line": 1, "character": 5 },
+ "end": { "line": 1, "character": 12 }
+ },
+ "severity": 1,
+ "code": "prefer-const",
+ "source": "deno-lint",
+ "message": "'message' is never reassigned\nUse 'const' instead",
+ "relatedInformation": []
+ }
+ ],
+ "only": ["quickfix"]
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_action_ignore_lint_response.json"))
+ Some(json!([{
+ "title": "Disable prefer-const for this line",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 1, "character": 5 },
+ "end": { "line": 1, "character": 12 }
+ },
+ "severity": 1,
+ "code": "prefer-const",
+ "source": "deno-lint",
+ "message": "'message' is never reassigned\nUse 'const' instead",
+ "relatedInformation": []
+ }],
+ "edit": {
+ "changes": {
+ "file:///a/file.ts": [{
+ "range": {
+ "start": { "line": 1, "character": 0 },
+ "end": { "line": 1, "character": 0 }
+ },
+ "newText": "// deno-lint-ignore prefer-const\n"
+ }]
+ }
+ }
+ }, {
+ "title": "Disable prefer-const for the entire file",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 1, "character": 5 },
+ "end": { "line": 1, "character": 12 }
+ },
+ "severity": 1,
+ "code": "prefer-const",
+ "source": "deno-lint",
+ "message": "'message' is never reassigned\nUse 'const' instead",
+ "relatedInformation": []
+ }],
+ "edit": {
+ "changes": {
+ "file:///a/file.ts": [{
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 0, "character": 0 }
+ },
+ "newText": "// deno-lint-ignore-file prefer-const\n"
+ }]
+ }
+ }
+ }, {
+ "title": "Ignore lint errors for the entire file",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 1, "character": 5 },
+ "end": { "line": 1, "character": 12 }
+ },
+ "severity": 1,
+ "code": "prefer-const",
+ "source": "deno-lint",
+ "message": "'message' is never reassigned\nUse 'const' instead",
+ "relatedInformation": []
+ }],
+ "edit": {
+ "changes": {
+ "file:///a/file.ts": [{
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 0, "character": 0 }
+ },
+ "newText": "// deno-lint-ignore-file\n"
+ }]
+ }
+ }
+ }]))
);
- shutdown(&mut client);
+ client.shutdown();
}
/// This test exercises updating an existing deno-lint-ignore-file comment.
#[test]
fn lsp_code_actions_update_ignore_lint() {
- let mut client = init("initialize_params.json");
+ let mut client = LspClientBuilder::new().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -6359,40 +7547,148 @@ console.log(snake_case);
let (maybe_res, maybe_err) = client
.write_request(
"textDocument/codeAction",
- load_fixture("code_action_update_ignore_lint_params.json"),
+ json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts"
+ },
+ "range": {
+ "start": { "line": 3, "character": 5 },
+ "end": { "line": 3, "character": 15 }
+ },
+ "context": {
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 3, "character": 5 },
+ "end": { "line": 3, "character": 15 }
+ },
+ "severity": 1,
+ "code": "prefer-const",
+ "source": "deno-lint",
+ "message": "'snake_case' is never reassigned\nUse 'const' instead",
+ "relatedInformation": []
+ }],
+ "only": ["quickfix"]
+ }
+ }),
)
.unwrap();
assert!(maybe_err.is_none());
assert_eq!(
maybe_res,
- Some(load_fixture("code_action_update_ignore_lint_response.json"))
+ Some(json!([{
+ "title": "Disable prefer-const for this line",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 3, "character": 5 },
+ "end": { "line": 3, "character": 15 }
+ },
+ "severity": 1,
+ "code": "prefer-const",
+ "source": "deno-lint",
+ "message": "'snake_case' is never reassigned\nUse 'const' instead",
+ "relatedInformation": []
+ }],
+ "edit": {
+ "changes": {
+ "file:///a/file.ts": [{
+ "range": {
+ "start": { "line": 3, "character": 0 },
+ "end": { "line": 3, "character": 0 }
+ },
+ "newText": "// deno-lint-ignore prefer-const\n"
+ }]
+ }
+ }
+ }, {
+ "title": "Disable prefer-const for the entire file",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 3, "character": 5 },
+ "end": { "line": 3, "character": 15 }
+ },
+ "severity": 1,
+ "code": "prefer-const",
+ "source": "deno-lint",
+ "message": "'snake_case' is never reassigned\nUse 'const' instead",
+ "relatedInformation": []
+ }],
+ "edit": {
+ "changes": {
+ "file:///a/file.ts": [{
+ "range": {
+ "start": { "line": 1, "character": 34 },
+ "end": { "line": 1, "character": 34 }
+ },
+ "newText": " prefer-const"
+ }]
+ }
+ }
+ }, {
+ "title": "Ignore lint errors for the entire file",
+ "kind": "quickfix",
+ "diagnostics": [{
+ "range": {
+ "start": { "line": 3, "character": 5 },
+ "end": { "line": 3, "character": 15 }
+ },
+ "severity": 1,
+ "code": "prefer-const",
+ "source": "deno-lint",
+ "message": "'snake_case' is never reassigned\nUse 'const' instead",
+ "relatedInformation": []
+ }],
+ "edit": {
+ "changes": {
+ "file:///a/file.ts": [{
+ "range": {
+ "start": { "line": 0, "character": 0 },
+ "end": { "line": 0, "character": 0 }
+ },
+ "newText": "// deno-lint-ignore-file\n"
+ }]
+ }
+ }
+ }]))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_lint_with_config() {
- let temp_dir = TempDir::new();
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
- let deno_lint_jsonc =
- serde_json::to_vec_pretty(&load_fixture("deno.lint.jsonc")).unwrap();
- fs::write(temp_dir.path().join("deno.lint.jsonc"), deno_lint_jsonc).unwrap();
-
- params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap());
- if let Some(Value::Object(mut map)) = params.initialization_options {
- map.insert("config".to_string(), json!("./deno.lint.jsonc"));
- params.initialization_options = Some(Value::Object(map));
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
+
+ temp_dir.write(
+ "deno.lint.jsonc",
+ r#"{
+ "lint": {
+ "rules": {
+ "exclude": ["camelcase"],
+ "include": ["ban-untagged-todo"],
+ "tags": []
+ }
+ }
}
+ "#,
+ );
+
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_config("./deno.lint.jsonc");
+ });
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
let mut session = TestSession::from_client(client);
- let diagnostics = session.did_open(load_fixture("did_open_lint.json"));
+ let diagnostics = session.did_open(json!({
+ "textDocument": {
+ "uri": "file:///a/file.ts",
+ "languageId": "typescript",
+ "version": 1,
+ "text": "// TODO: fixme\nexport async function non_camel_case() {\nconsole.log(\"finished!\")\n}"
+ }
+ }));
let diagnostics = diagnostics.viewed();
assert_eq!(diagnostics.len(), 1);
assert_eq!(
@@ -6404,25 +7700,29 @@ fn lsp_lint_with_config() {
#[test]
fn lsp_lint_exclude_with_config() {
- let temp_dir = TempDir::new();
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
- let deno_lint_jsonc =
- serde_json::to_vec_pretty(&load_fixture("deno.lint.exclude.jsonc"))
- .unwrap();
- fs::write(temp_dir.path().join("deno.lint.jsonc"), deno_lint_jsonc).unwrap();
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
- params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap());
- if let Some(Value::Object(mut map)) = params.initialization_options {
- map.insert("config".to_string(), json!("./deno.lint.jsonc"));
- params.initialization_options = Some(Value::Object(map));
- }
+ temp_dir.write(
+ "deno.lint.jsonc",
+ r#"{
+ "lint": {
+ "files": {
+ "exclude": ["ignored.ts"]
+ },
+ "rules": {
+ "exclude": ["camelcase"],
+ "include": ["ban-untagged-todo"],
+ "tags": []
+ }
+ }
+ }"#,
+ );
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
+ let mut client = context.new_lsp_command().build();
+ client.initialize(|builder| {
+ builder.set_config("./deno.lint.jsonc");
+ });
let diagnostics = did_open(
&mut client,
@@ -6440,13 +7740,14 @@ fn lsp_lint_exclude_with_config() {
.flat_map(|x| x.diagnostics)
.collect::<Vec<_>>();
assert_eq!(diagnostics, Vec::new());
- shutdown(&mut client);
+ client.shutdown();
}
#[test]
fn lsp_jsx_import_source_pragma() {
- let _g = http_server();
- let mut client = init("initialize_params.json");
+ let context = TestContextBuilder::new().use_http_server().build();
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
did_open(
&mut client,
json!({
@@ -6475,11 +7776,9 @@ export function B() {
"referrer": {
"uri": "file:///a/file.tsx",
},
- "uris": [
- {
- "uri": "http://127.0.0.1:4545/jsx/jsx-runtime",
- }
- ],
+ "uris": [{
+ "uri": "http://127.0.0.1:4545/jsx/jsx-runtime",
+ }],
}),
)
.unwrap();
@@ -6492,10 +7791,7 @@ export function B() {
"textDocument": {
"uri": "file:///a/file.tsx"
},
- "position": {
- "line": 0,
- "character": 25
- }
+ "position": { "line": 0, "character": 25 }
}),
)
.unwrap();
@@ -6508,18 +7804,12 @@ export function B() {
"value": "**Resolved Dependency**\n\n**Code**: http&#8203;://localhost:4545/jsx/jsx-runtime\n",
},
"range": {
- "start": {
- "line": 0,
- "character": 21
- },
- "end": {
- "line": 0,
- "character": 46
- }
+ "start": { "line": 0, "character": 21 },
+ "end": { "line": 0, "character": 46 }
}
}))
);
- shutdown(&mut client);
+ client.shutdown();
}
#[derive(Debug, Clone, Deserialize, PartialEq)]
@@ -6562,15 +7852,9 @@ struct TestRunResponseParams {
#[test]
fn lsp_testing_api() {
- let mut params: lsp::InitializeParams =
- serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
- let temp_dir = TempDir::new();
+ let context = TestContextBuilder::new().build();
+ let temp_dir = context.deno_dir();
- let root_specifier =
- ensure_directory_specifier(Url::from_file_path(temp_dir.path()).unwrap());
-
- let module_path = temp_dir.path().join("./test.ts");
- let specifier = ModuleSpecifier::from_file_path(&module_path).unwrap();
let contents = r#"
Deno.test({
name: "test a",
@@ -6579,18 +7863,12 @@ Deno.test({
}
});
"#;
- fs::write(&module_path, contents).unwrap();
- fs::write(temp_dir.path().join("./deno.jsonc"), r#"{}"#).unwrap();
-
- params.root_uri = Some(root_specifier);
-
- let deno_exe = deno_exe_path();
- let mut client = LspClient::new(&deno_exe, false).unwrap();
- client
- .write_request::<_, _, Value>("initialize", params)
- .unwrap();
+ temp_dir.write("./test.ts", contents);
+ temp_dir.write("./deno.jsonc", "{}");
+ let specifier = temp_dir.uri().join("test.ts").unwrap();
- client.write_notification("initialized", json!({})).unwrap();
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
client
.write_notification(
@@ -6763,5 +8041,5 @@ Deno.test({
_ => panic!("unexpected message {}", json!(notification)),
}
- shutdown(&mut client);
+ client.shutdown();
}