2022-01-07 22:09:52 -05:00
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
2021-05-17 16:45:13 -04:00
2021-11-24 15:14:19 -05:00
use deno_ast ::ModuleSpecifier ;
2022-01-24 15:30:01 -05:00
use deno_core ::serde ::de ::DeserializeOwned ;
2021-05-17 16:45:13 -04:00
use deno_core ::serde ::Deserialize ;
use deno_core ::serde ::Serialize ;
use deno_core ::serde_json ;
use deno_core ::serde_json ::json ;
use deno_core ::serde_json ::Value ;
use deno_core ::url ::Url ;
use lspower ::lsp ;
2021-09-15 06:34:17 -04:00
use pretty_assertions ::assert_eq ;
2022-01-24 18:04:24 -05:00
use std ::collections ::HashSet ;
2021-05-17 16:45:13 -04:00
use std ::fs ;
use tempfile ::TempDir ;
use test_util ::deno_exe_path ;
use test_util ::http_server ;
use test_util ::lsp ::LspClient ;
2021-08-11 10:20:47 -04:00
use test_util ::testdata_path ;
2021-05-17 16:45:13 -04:00
fn load_fixture ( path : & str ) -> Value {
2022-01-24 15:30:01 -05:00
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 ( )
2021-05-17 16:45:13 -04:00
}
2021-06-21 17:18:32 -04:00
fn load_fixture_str ( path : & str ) -> String {
2021-08-11 10:20:47 -04:00
let fixtures_path = testdata_path ( ) . join ( " lsp " ) ;
2021-06-21 17:18:32 -04:00
let path = fixtures_path . join ( path ) ;
fs ::read_to_string ( path ) . unwrap ( )
}
2021-05-17 16:45:13 -04:00
fn init ( init_path : & str ) -> LspClient {
let deno_exe = deno_exe_path ( ) ;
let mut client = LspClient ::new ( & deno_exe ) . unwrap ( ) ;
client
. write_request ::< _ , _ , Value > ( " initialize " , load_fixture ( init_path ) )
. unwrap ( ) ;
client . write_notification ( " initialized " , json! ( { } ) ) . unwrap ( ) ;
client
}
2021-06-06 01:00:17 -04:00
fn did_open < V > (
client : & mut LspClient ,
params : V ,
) -> Vec < lsp ::PublishDiagnosticsParams >
2021-05-17 16:45:13 -04:00
where
V : Serialize ,
{
client
. write_notification ( " textDocument/didOpen " , params )
. unwrap ( ) ;
2021-05-20 05:56:48 -04:00
2022-02-02 18:02:59 -05:00
handle_configuration_request ( client ) ;
read_diagnostics ( client ) . 0
}
fn handle_configuration_request ( client : & mut LspClient ) {
2021-05-20 05:56:48 -04:00
let ( id , method , _ ) = client . read_request ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " workspace/configuration " ) ;
client
2021-06-07 07:38:07 -04:00
. write_response (
id ,
2022-01-17 20:10:17 -05:00
json! ( [ {
2021-06-07 07:38:07 -04:00
" enable " : true ,
" codeLens " : {
" test " : true
}
2022-01-17 20:10:17 -05:00
} ] ) ,
2021-06-07 07:38:07 -04:00
)
2021-05-20 05:56:48 -04:00
. unwrap ( ) ;
2022-01-24 15:30:01 -05:00
}
fn read_diagnostics ( client : & mut LspClient ) -> CollectedDiagnostics {
// diagnostics come in batches of three unless they're cancelled
2021-06-06 01:00:17 -04:00
let mut diagnostics = vec! [ ] ;
for _ in 0 .. 3 {
let ( method , response ) = client
. read_notification ::< lsp ::PublishDiagnosticsParams > ( )
. unwrap ( ) ;
assert_eq! ( method , " textDocument/publishDiagnostics " ) ;
diagnostics . push ( response . unwrap ( ) ) ;
}
2022-01-24 15:30:01 -05:00
CollectedDiagnostics ( diagnostics )
2021-05-17 16:45:13 -04:00
}
fn shutdown ( client : & mut LspClient ) {
client
. write_request ::< _ , _ , Value > ( " shutdown " , json! ( null ) )
. unwrap ( ) ;
client . write_notification ( " exit " , json! ( null ) ) . unwrap ( ) ;
}
2022-01-24 15:30:01 -05:00
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 ,
open_file_count : 0 ,
}
}
pub fn did_open < V > ( & mut self , params : V ) -> CollectedDiagnostics
where
V : Serialize ,
{
self
. client
. write_notification ( " textDocument/didOpen " , params )
. unwrap ( ) ;
let ( id , method , _ ) = self . client . read_request ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " workspace/configuration " ) ;
self
. client
. write_response (
id ,
json! ( [ {
" enable " : true ,
" codeLens " : {
" test " : true
}
} ] ) ,
)
. unwrap ( ) ;
self . open_file_count + = 1 ;
self . read_diagnostics ( )
}
pub fn read_diagnostics ( & mut self ) -> CollectedDiagnostics {
let mut all_diagnostics = Vec ::new ( ) ;
for _ in 0 .. self . open_file_count {
all_diagnostics . extend ( read_diagnostics ( & mut self . client ) . 0 ) ;
}
CollectedDiagnostics ( all_diagnostics )
}
pub fn shutdown_and_exit ( & mut self ) {
shutdown ( & mut self . client ) ;
}
}
#[ derive(Debug, Clone) ]
struct CollectedDiagnostics ( Vec < lsp ::PublishDiagnosticsParams > ) ;
impl CollectedDiagnostics {
2022-01-24 18:04:24 -05:00
/// Gets the diagnostics that the editor will see after all the publishes.
pub fn viewed ( & self ) -> Vec < lsp ::Diagnostic > {
2022-01-24 15:30:01 -05:00
self
2022-01-24 18:04:24 -05:00
. viewed_messages ( )
. into_iter ( )
. flat_map ( | m | m . diagnostics )
2022-01-24 15:30:01 -05:00
. collect ( )
}
2022-01-24 18:04:24 -05:00
/// Gets the messages that the editor will see after all the publishes.
pub fn viewed_messages ( & self ) -> Vec < lsp ::PublishDiagnosticsParams > {
// go over the publishes in reverse order in order to get
// the final messages that will be shown in the editor
let mut messages = Vec ::new ( ) ;
let mut had_specifier = HashSet ::new ( ) ;
for message in self . 0. iter ( ) . rev ( ) {
if had_specifier . insert ( message . uri . clone ( ) ) {
messages . insert ( 0 , message . clone ( ) ) ;
}
}
messages
}
2022-01-24 15:30:01 -05:00
pub fn with_source ( & self , source : & str ) -> lsp ::PublishDiagnosticsParams {
self
2022-01-24 18:04:24 -05:00
. viewed_messages ( )
2022-01-24 15:30:01 -05:00
. iter ( )
. find ( | p | {
p . diagnostics
. iter ( )
. any ( | d | d . source = = Some ( source . to_string ( ) ) )
} )
. map ( ToOwned ::to_owned )
. unwrap ( )
}
pub fn with_file_and_source (
& self ,
specifier : & str ,
source : & str ,
) -> lsp ::PublishDiagnosticsParams {
let specifier = ModuleSpecifier ::parse ( specifier ) . unwrap ( ) ;
self
2022-01-24 18:04:24 -05:00
. viewed_messages ( )
2022-01-24 15:30:01 -05:00
. iter ( )
. find ( | p | {
p . uri = = specifier
& & p
. diagnostics
. iter ( )
. any ( | d | d . source = = Some ( source . to_string ( ) ) )
} )
. map ( ToOwned ::to_owned )
. unwrap ( )
}
}
2021-05-17 16:45:13 -04:00
#[ test ]
fn lsp_startup_shutdown ( ) {
let mut client = init ( " initialize_params.json " ) ;
shutdown ( & mut client ) ;
}
2021-06-06 01:00:17 -04:00
#[ test ]
fn lsp_init_tsconfig ( ) {
let temp_dir = TempDir ::new ( ) . expect ( " could not create temp dir " ) ;
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 deno_exe = deno_exe_path ( ) ;
let mut client = LspClient ::new ( & deno_exe ) . unwrap ( ) ;
client
. write_request ::< _ , _ , Value > ( " initialize " , params )
. unwrap ( ) ;
client . write_notification ( " initialized " , json! ( { } ) ) . unwrap ( ) ;
let diagnostics = did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " location.pathname; \n "
}
} ) ,
) ;
let diagnostics = diagnostics . into_iter ( ) . flat_map ( | x | x . diagnostics ) ;
assert_eq! ( diagnostics . count ( ) , 0 ) ;
2021-06-21 17:18:32 -04:00
shutdown ( & mut client ) ;
}
#[ 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 ( ) . expect ( " could not create temp dir " ) ;
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 deno_exe = deno_exe_path ( ) ;
let mut client = LspClient ::new ( & deno_exe ) . unwrap ( ) ;
client
. write_request ::< _ , _ , Value > ( " initialize " , params )
. unwrap ( ) ;
client . write_notification ( " initialized " , json! ( { } ) ) . unwrap ( ) ;
let diagnostics = did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : Url ::from_file_path ( temp_dir . path ( ) . join ( " test.ts " ) ) . unwrap ( ) ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " console.log(a); \n "
}
} ) ,
) ;
let diagnostics = diagnostics . into_iter ( ) . flat_map ( | x | x . diagnostics ) ;
assert_eq! ( diagnostics . count ( ) , 0 ) ;
shutdown ( & mut client ) ;
}
2021-06-24 08:41:04 -04:00
#[ test ]
fn lsp_tsconfig_bad_config_path ( ) {
let mut client = init ( " initialize_params_bad_config_option.json " ) ;
let ( method , maybe_params ) = client . read_notification ( ) . unwrap ( ) ;
assert_eq! ( method , " window/showMessage " ) ;
assert_eq! ( maybe_params , Some ( lsp ::ShowMessageParams {
2021-11-24 20:10:12 -05:00
typ : lsp ::MessageType ::WARNING ,
2021-06-24 08:41:04 -04:00
message : " The path to the configuration file ( \" bad_tsconfig.json \" ) is not resolvable. " . to_string ( )
} ) ) ;
let diagnostics = did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " console.log(Deno.args); \n "
}
} ) ,
) ;
let diagnostics = diagnostics . into_iter ( ) . flat_map ( | x | x . diagnostics ) ;
assert_eq! ( diagnostics . count ( ) , 0 ) ;
}
2021-06-21 17:18:32 -04:00
#[ test ]
fn lsp_triple_slash_types ( ) {
let mut params : lsp ::InitializeParams =
serde_json ::from_value ( load_fixture ( " initialize_params.json " ) ) . unwrap ( ) ;
let temp_dir = TempDir ::new ( ) . expect ( " could not create temp dir " ) ;
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 ) . unwrap ( ) ;
client
. write_request ::< _ , _ , Value > ( " initialize " , params )
. unwrap ( ) ;
client . write_notification ( " initialized " , json! ( { } ) ) . unwrap ( ) ;
let diagnostics = did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : Url ::from_file_path ( temp_dir . path ( ) . join ( " test.ts " ) ) . unwrap ( ) ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " /// <reference types= \" ./a.d.ts \" /> \n \n console.log(a); \n "
}
} ) ,
) ;
let diagnostics = diagnostics . into_iter ( ) . flat_map ( | x | x . diagnostics ) ;
assert_eq! ( diagnostics . count ( ) , 0 ) ;
2021-06-06 01:00:17 -04:00
shutdown ( & mut client ) ;
}
2021-07-25 01:33:42 -04:00
#[ test ]
fn lsp_import_map ( ) {
let temp_dir = TempDir ::new ( ) . expect ( " could not create temp dir " ) ;
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 deno_exe = deno_exe_path ( ) ;
let mut client = LspClient ::new ( & deno_exe ) . unwrap ( ) ;
client
. write_request ::< _ , _ , Value > ( " initialize " , params )
. unwrap ( ) ;
client . write_notification ( " initialized " , json! ( { } ) ) . unwrap ( ) ;
let uri = Url ::from_file_path ( temp_dir . path ( ) . join ( " a.ts " ) ) . unwrap ( ) ;
let diagnostics = did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : uri ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import { b } from \" /~/b.ts \" ; \n \n console.log(b); \n "
}
} ) ,
) ;
let diagnostics = diagnostics . into_iter ( ) . flat_map ( | x | x . diagnostics ) ;
assert_eq! ( diagnostics . count ( ) , 0 ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : uri
} ,
" position " : {
" line " : 2 ,
" character " : 12
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : [
{
" language " : " typescript " ,
" value " :" (alias) const b: \" b \" \n import b "
} ,
" "
] ,
" range " : {
" start " : {
" line " : 2 ,
" character " : 12
} ,
" end " : {
" line " : 2 ,
" character " : 13
}
}
} ) )
) ;
shutdown ( & mut client ) ;
}
2021-09-13 00:19:23 -04:00
#[ test ]
fn lsp_import_map_data_url ( ) {
let mut client = init ( " initialize_params_import_map.json " ) ;
let diagnostics = did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import example from \" example \" ; \n "
}
} ) ,
) ;
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.
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 ) ;
}
2022-02-22 18:51:14 -05:00
#[ test ]
fn lsp_import_map_config_file ( ) {
let temp_dir = TempDir ::new ( ) . expect ( " could not create temp dir " ) ;
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 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 ( ) ;
let deno_exe = deno_exe_path ( ) ;
let mut client = LspClient ::new ( & deno_exe ) . unwrap ( ) ;
client
. write_request ::< _ , _ , Value > ( " initialize " , params )
. unwrap ( ) ;
client . write_notification ( " initialized " , json! ( { } ) ) . unwrap ( ) ;
let uri = Url ::from_file_path ( temp_dir . path ( ) . join ( " a.ts " ) ) . unwrap ( ) ;
let diagnostics = did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : uri ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import { b } from \" /~/b.ts \" ; \n \n console.log(b); \n "
}
} ) ,
) ;
let diagnostics = diagnostics . into_iter ( ) . flat_map ( | x | x . diagnostics ) ;
assert_eq! ( diagnostics . count ( ) , 0 ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : uri
} ,
" position " : {
" line " : 2 ,
" character " : 12
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : [
{
" language " : " typescript " ,
" value " :" (alias) const b: \" b \" \n import b "
} ,
" "
] ,
" range " : {
" start " : {
" line " : 2 ,
" character " : 12
} ,
" end " : {
" line " : 2 ,
" character " : 13
}
}
} ) )
) ;
shutdown ( & mut client ) ;
}
2021-12-15 22:53:17 -05:00
#[ test ]
fn lsp_import_assertions ( ) {
let mut client = init ( " initialize_params_import_map.json " ) ;
client
. write_notification (
" textDocument/didOpen " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/test.json " ,
" languageId " : " json " ,
" version " : 1 ,
" text " : " { \" a \" :1} "
}
} ) ,
)
. unwrap ( ) ;
2022-02-02 18:02:59 -05:00
handle_configuration_request ( & mut client ) ;
2021-12-15 22:53:17 -05:00
2022-01-24 15:30:01 -05:00
let diagnostics = CollectedDiagnostics ( did_open (
2021-12-15 22:53:17 -05:00
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/a.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import a from \" ./test.json \" ; \n \n console.log(a); \n "
}
} ) ,
2022-01-24 15:30:01 -05:00
) ) ;
2021-12-15 22:53:17 -05:00
assert_eq! (
2022-01-24 15:30:01 -05:00
json! (
diagnostics
. with_file_and_source ( " file:///a/a.ts " , " deno " )
. diagnostics
) ,
2021-12-15 22:53:17 -05:00
json! ( [
{
" 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. "
}
] )
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/codeAction " ,
load_fixture ( " code_action_params_import_assertion.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_action_response_import_assertion.json " ) )
) ;
shutdown ( & mut client ) ;
}
2022-02-09 15:13:50 -05:00
#[ test ]
fn lsp_import_map_import_completions ( ) {
let temp_dir = TempDir ::new ( ) . expect ( " could not create temp dir " ) ;
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 deno_exe = deno_exe_path ( ) ;
let mut client = LspClient ::new ( & deno_exe ) . unwrap ( ) ;
client
. write_request ::< _ , _ , Value > ( " initialize " , params )
. unwrap ( ) ;
client . write_notification ( " initialized " , json! ( { } ) ) . unwrap ( ) ;
let uri = Url ::from_file_path ( temp_dir . path ( ) . join ( " a.ts " ) ) . unwrap ( ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : uri ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import * as a from \" /~/b.ts \" ; \n import * as b from \" \" "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/completion " ,
json! ( {
" textDocument " : {
" uri " : uri
} ,
" position " : {
" line " : 1 ,
" character " : 20
} ,
" context " : {
" triggerKind " : 2 ,
" triggerCharacter " : " \" "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" isIncomplete " : false ,
" items " : [
{
" label " : " . " ,
" kind " : 19 ,
" detail " : " (local) " ,
" sortText " : " 1 " ,
" insertText " : " . "
} ,
{
" label " : " .. " ,
" kind " : 19 ,
" detail " : " (local) " ,
" sortText " : " 1 " ,
" insertText " : " .. "
} ,
{
" label " : " std " ,
" kind " : 19 ,
" detail " : " (import map) " ,
" sortText " : " std " ,
" insertText " : " std "
} ,
{
" label " : " fs " ,
" kind " : 17 ,
" detail " : " (import map) " ,
" sortText " : " fs " ,
" insertText " : " fs "
} ,
{
" label " : " /~ " ,
" kind " : 19 ,
" detail " : " (import map) " ,
" sortText " : " /~ " ,
" insertText " : " /~ "
}
]
} ) )
) ;
client
. write_notification (
" textDocument/didChange " ,
json! ( {
" textDocument " : {
" uri " : uri ,
" version " : 2
} ,
" contentChanges " : [
{
" range " : {
" start " : {
" line " : 1 ,
" character " : 20
} ,
" end " : {
" line " : 1 ,
" character " : 20
}
} ,
" text " : " /~/ "
}
]
} ) ,
)
. unwrap ( ) ;
let ( method , _ ) = client . read_notification ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " textDocument/publishDiagnostics " ) ;
let ( method , _ ) = client . read_notification ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " textDocument/publishDiagnostics " ) ;
let ( method , _ ) = client . read_notification ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " textDocument/publishDiagnostics " ) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/completion " ,
json! ( {
" textDocument " : {
" uri " : uri
} ,
" position " : {
" line " : 1 ,
" character " : 23
} ,
" context " : {
" triggerKind " : 2 ,
" triggerCharacter " : " / "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" isIncomplete " : false ,
" items " : [
{
" label " : " b.ts " ,
" kind " : 9 ,
" detail " : " (import map) " ,
" sortText " : " 1 " ,
" filterText " : " /~/b.ts " ,
" textEdit " : {
" range " : {
" start " : {
" line " : 1 ,
" character " : 20
} ,
" end " : {
" line " : 1 ,
" character " : 23
}
} ,
" newText " : " /~/b.ts "
}
}
]
} ) )
) ;
shutdown ( & mut client ) ;
}
2021-05-17 16:45:13 -04:00
#[ test ]
fn lsp_hover ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " console.log(Deno.args); \n "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 19
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : [
{
" language " : " typescript " ,
" value " : " const Deno.args: string[] "
} ,
" Returns the script arguments to the program. If for example we run a \n program: \n \n deno run --allow-read https://deno.land/std/examples/cat.ts /etc/passwd \n \n Then `Deno.args` will contain: \n \n [ \" /etc/passwd \" ] "
] ,
" range " : {
" start " : {
" line " : 0 ,
" character " : 17
} ,
" end " : {
" line " : 0 ,
" character " : 21
}
}
} ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_hover_asset ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " console.log(Date.now()); \n "
}
} ) ,
) ;
let ( _ , maybe_error ) = client
. write_request ::< _ , _ , Value > (
" textDocument/definition " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 14
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_error . is_none ( ) ) ;
let ( _ , maybe_error ) = client
. write_request ::< _ , _ , Value > (
" deno/virtualTextDocument " ,
json! ( {
" textDocument " : {
2021-10-28 19:56:01 -04:00
" uri " : " deno:asset/lib.deno.shared_globals.d.ts "
2021-05-17 16:45:13 -04:00
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_error . is_none ( ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
2021-10-28 19:56:01 -04:00
" uri " : " deno:asset/lib.es2015.symbol.wellknown.d.ts "
2021-05-17 16:45:13 -04:00
} ,
" position " : {
" line " : 109 ,
" character " : 13
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : [
{
" language " : " typescript " ,
" value " : " interface Date " ,
} ,
" Enables basic storage and retrieval of dates and times. "
] ,
" range " : {
" start " : {
" line " : 109 ,
" character " : 10 ,
} ,
" end " : {
" line " : 109 ,
" character " : 14 ,
}
}
} ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_hover_disabled ( ) {
let mut client = init ( " initialize_params_disabled.json " ) ;
client
. write_notification (
" textDocument/didOpen " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " console.log(Date.now()); \n "
}
} ) ,
)
. unwrap ( ) ;
2021-05-20 05:56:48 -04:00
let ( id , method , _ ) = client . read_request ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " workspace/configuration " ) ;
client
2022-01-17 20:10:17 -05:00
. write_response ( id , json! ( [ { " enable " : false } ] ) )
2021-05-20 05:56:48 -04:00
. unwrap ( ) ;
2021-05-17 16:45:13 -04:00
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 19
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! ( maybe_res , Some ( json! ( null ) ) ) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_hover_unstable_disabled ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
2021-08-06 17:28:10 -04:00
" text " : " console.log(Deno.dlopen); \n "
2021-05-17 16:45:13 -04:00
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 19
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : [
{
" language " : " typescript " ,
" value " : " any "
}
] ,
" range " : {
" start " : {
" line " : 0 ,
" character " : 17
} ,
" end " : {
" line " : 0 ,
2021-08-06 17:28:10 -04:00
" character " : 23
2021-05-17 16:45:13 -04:00
}
}
} ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_hover_unstable_enabled ( ) {
let mut client = init ( " initialize_params_unstable.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
2021-08-06 17:28:10 -04:00
" text " : " console.log(Deno.ppid); \n "
2021-05-17 16:45:13 -04:00
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 19
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " :[
{
" language " :" typescript " ,
2021-08-06 17:28:10 -04:00
" value " :" const Deno.ppid: number "
2021-05-17 16:45:13 -04:00
} ,
2021-08-06 17:28:10 -04:00
" The pid of the current process's parent. "
2021-05-17 16:45:13 -04:00
] ,
" range " :{
" start " :{
" line " :0 ,
" character " :17
} ,
" end " :{
" line " :0 ,
2021-08-06 17:28:10 -04:00
" character " :21
2021-05-17 16:45:13 -04:00
}
}
} ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_hover_change_mbc ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " const a = `编写软件很难`; \n const b = `👍🦕😃`; \n console.log(a, b); \n "
}
} ) ,
) ;
client
. write_notification (
" textDocument/didChange " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" version " : 2
} ,
" contentChanges " : [
{
" range " : {
" start " : {
" line " : 1 ,
" character " : 11
} ,
" end " : {
" line " : 1 ,
" character " : 13
}
} ,
" text " : " "
}
]
} ) ,
)
. unwrap ( ) ;
let ( method , _ ) = client . read_notification ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " textDocument/publishDiagnostics " ) ;
let ( method , _ ) = client . read_notification ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " textDocument/publishDiagnostics " ) ;
let ( method , _ ) = client . read_notification ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " textDocument/publishDiagnostics " ) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 2 ,
" character " : 14
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : [
{
" language " : " typescript " ,
" value " : " const b: \" 😃 \" " ,
} ,
" " ,
] ,
" range " : {
" start " : {
" line " : 2 ,
" character " : 13 ,
} ,
" end " : {
" line " : 2 ,
" character " : 14 ,
} ,
}
} ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_hover_closed_document ( ) {
let temp_dir = TempDir ::new ( )
. expect ( " could not create temp dir " )
. into_path ( ) ;
let a_path = temp_dir . join ( " a.ts " ) ;
fs ::write ( a_path , r # "export const a = "a";"# ) . expect ( " could not write file " ) ;
let b_path = temp_dir . join ( " b.ts " ) ;
fs ::write ( & b_path , r # "export * from "./a.ts";"# )
. expect ( " could not write file " ) ;
let b_specifier =
Url ::from_file_path ( b_path ) . expect ( " could not convert path " ) ;
let c_path = temp_dir . join ( " c.ts " ) ;
fs ::write ( & c_path , " import { a } from \" ./b.ts \" ; \n console.log(a); \n " )
. expect ( " could not write file " ) ;
let c_specifier =
Url ::from_file_path ( c_path ) . expect ( " could not convert path " ) ;
let mut client = init ( " initialize_params.json " ) ;
client
. write_notification (
" textDocument/didOpen " ,
json! ( {
" textDocument " : {
" uri " : b_specifier ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : r #" export * from " . / a . ts " ; " #
}
} ) ,
)
. unwrap ( ) ;
2021-05-20 05:56:48 -04:00
let ( id , method , _ ) = client . read_request ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " workspace/configuration " ) ;
client
2022-01-17 20:10:17 -05:00
. write_response ( id , json! ( [ { " enable " : true } ] ) )
2021-05-20 05:56:48 -04:00
. unwrap ( ) ;
2021-05-17 16:45:13 -04:00
client
. write_notification (
" textDocument/didOpen " ,
json! ( {
" textDocument " : {
" uri " : c_specifier ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import { a } from \" ./b.ts \" ; \n console.log(a); \n " ,
}
} ) ,
)
. unwrap ( ) ;
2021-05-20 05:56:48 -04:00
let ( id , method , _ ) = client . read_request ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " workspace/configuration " ) ;
client
2022-01-17 20:10:17 -05:00
. write_response ( id , json! ( [ { " enable " : true } ] ) )
2021-05-20 05:56:48 -04:00
. unwrap ( ) ;
2021-05-17 16:45:13 -04:00
let ( method , _ ) = client . read_notification ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " textDocument/publishDiagnostics " ) ;
let ( method , _ ) = client . read_notification ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " textDocument/publishDiagnostics " ) ;
let ( method , _ ) = client . read_notification ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " textDocument/publishDiagnostics " ) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : c_specifier ,
} ,
" position " : {
" line " : 0 ,
" character " : 10
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : [
{
" language " : " typescript " ,
" value " : " (alias) const a: \" a \" \n import a "
} ,
" "
] ,
" range " : {
" start " : {
" line " : 0 ,
" character " : 9
} ,
" end " : {
" line " : 0 ,
" character " : 10
}
}
} ) )
) ;
client
. write_notification (
" textDocument/didClose " ,
json! ( {
" textDocument " : {
" uri " : b_specifier ,
}
} ) ,
)
. unwrap ( ) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : c_specifier ,
} ,
" position " : {
" line " : 0 ,
" character " : 10
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : [
{
" language " : " typescript " ,
" value " : " (alias) const a: \" a \" \n import a "
} ,
" "
] ,
" range " : {
" start " : {
" line " : 0 ,
" character " : 9
} ,
" end " : {
" line " : 0 ,
" character " : 10
}
}
} ) )
) ;
shutdown ( & mut client ) ;
}
2021-06-24 19:06:51 -04:00
#[ test ]
fn lsp_hover_dependency ( ) {
let _g = http_server ( ) ;
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file_01.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " export const a = \" a \" ; \n " ,
}
} ) ,
) ;
did_open (
& mut client ,
load_fixture ( " did_open_params_import_hover.json " ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" deno/cache " ,
json! ( {
" referrer " : {
" uri " : " file:///a/file.ts " ,
} ,
" uris " : [ ] ,
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
} ,
" position " : {
" line " : 0 ,
" character " : 28
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : {
" kind " : " markdown " ,
" value " : " **Resolved Dependency** \n \n **Code**: http​://127.0.0.1:4545/xTypeScriptTypes.js \n "
} ,
" range " : {
" start " : {
" line " : 0 ,
2021-10-28 19:56:01 -04:00
" character " : 19
2021-06-24 19:06:51 -04:00
} ,
" end " :{
" line " : 0 ,
2021-10-28 19:56:01 -04:00
" character " : 62
2021-06-24 19:06:51 -04:00
}
}
} ) )
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
} ,
" position " : {
" line " : 3 ,
" character " : 28
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : {
" kind " : " markdown " ,
2021-08-11 10:20:47 -04:00
" value " : " **Resolved Dependency** \n \n **Code**: http​://127.0.0.1:4545/subdir/type_reference.js \n "
2021-06-24 19:06:51 -04:00
} ,
" range " : {
" start " : {
" line " : 3 ,
2021-10-28 19:56:01 -04:00
" character " : 19
2021-06-24 19:06:51 -04:00
} ,
" end " :{
" line " : 3 ,
2021-10-28 19:56:01 -04:00
" character " : 67
2021-06-24 19:06:51 -04:00
}
}
} ) )
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
} ,
" position " : {
" line " : 4 ,
" character " : 28
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : {
" kind " : " markdown " ,
2021-08-11 10:20:47 -04:00
" value " : " **Resolved Dependency** \n \n **Code**: http​://127.0.0.1:4545/subdir/mod1.ts \n "
2021-06-24 19:06:51 -04:00
} ,
" range " : {
" start " : {
" line " : 4 ,
2021-10-28 19:56:01 -04:00
" character " : 19
2021-06-24 19:06:51 -04:00
} ,
" end " :{
" line " : 4 ,
2021-10-28 19:56:01 -04:00
" character " : 57
2021-06-24 19:06:51 -04:00
}
}
} ) )
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
} ,
" position " : {
" line " : 5 ,
" character " : 28
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : {
" kind " : " markdown " ,
" value " : " **Resolved Dependency** \n \n **Code**: _(a data url)_ \n "
} ,
" range " : {
" start " : {
" line " : 5 ,
2021-10-28 19:56:01 -04:00
" character " : 19
2021-06-24 19:06:51 -04:00
} ,
" end " :{
" line " : 5 ,
2021-10-28 19:56:01 -04:00
" character " : 132
2021-06-24 19:06:51 -04:00
}
}
} ) )
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
} ,
" position " : {
" line " : 6 ,
" character " : 28
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : {
" kind " : " markdown " ,
" value " : " **Resolved Dependency** \n \n **Code**: file​:///a/file_01.ts \n "
} ,
" range " : {
" start " : {
" line " : 6 ,
2021-10-28 19:56:01 -04:00
" character " : 19
2021-06-24 19:06:51 -04:00
} ,
" end " :{
" line " : 6 ,
2021-10-28 19:56:01 -04:00
" character " : 33
2021-06-24 19:06:51 -04:00
}
}
} ) )
) ;
}
2021-11-16 17:23:25 -05:00
// This tests for a regression covered by denoland/deno#12753 where the lsp was
// unable to resolve dependencies when there was an invalid syntax in the module
2021-11-15 21:59:33 -05:00
#[ test ]
2021-11-16 17:23:25 -05:00
fn lsp_hover_deps_preserved_when_invalid_parse ( ) {
2021-11-15 21:59:33 -05:00
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file1.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " export type Foo = { bar(): string }; \n "
}
} ) ,
) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file2.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import { Foo } from './file1.ts'; declare const f: Foo; f \n "
}
} ) ,
) ;
let ( maybe_res , maybe_error ) = client
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file2.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 56
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_error . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : [
{
" language " : " typescript " ,
" value " : " const f: Foo " ,
} ,
" "
] ,
" range " : {
" start " : {
" line " : 0 ,
" character " : 56 ,
} ,
" end " : {
" line " : 0 ,
" character " : 57 ,
}
}
} ) )
) ;
client
. write_notification (
" textDocument/didChange " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file2.ts " ,
" version " : 2
} ,
" contentChanges " : [
{
" range " : {
" start " : {
" line " : 0 ,
" character " : 57
} ,
" end " : {
" line " : 0 ,
" character " : 58
}
} ,
" text " : " . "
}
]
} ) ,
)
. unwrap ( ) ;
let ( maybe_res , maybe_error ) = client
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file2.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 56
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_error . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : [
{
" language " : " typescript " ,
" value " : " const f: Foo " ,
} ,
" "
] ,
" range " : {
" start " : {
" line " : 0 ,
" character " : 56 ,
} ,
" end " : {
" line " : 0 ,
" character " : 57 ,
}
}
} ) )
) ;
shutdown ( & mut client ) ;
}
2021-11-07 19:50:48 -05:00
#[ test ]
fn lsp_hover_typescript_types ( ) {
let _g = http_server ( ) ;
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
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 \n console.log(a.foo); \n " ,
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" deno/cache " ,
json! ( {
" referrer " : {
" uri " : " file:///a/file.ts " ,
} ,
" uris " : [
{
" uri " : " http://127.0.0.1:4545/xTypeScriptTypes.js " ,
}
] ,
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 24
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_res . is_some ( ) ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
json! ( maybe_res . unwrap ( ) ) ,
json! ( {
" contents " : {
" kind " : " markdown " ,
" value " : " **Resolved Dependency** \n \n **Code**: http​://127.0.0.1:4545/xTypeScriptTypes.js \n \n **Types**: http​://127.0.0.1:4545/xTypeScriptTypes.d.ts \n "
} ,
" range " : {
" start " : {
" line " : 0 ,
" character " : 19
} ,
" end " : {
" line " : 0 ,
" character " : 62
}
}
} )
) ;
shutdown ( & mut client ) ;
}
2022-02-09 18:08:53 -05:00
#[ test ]
fn lsp_hover_jsdoc_symbol_link ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/b.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " export function hello() {} \n "
}
} ) ,
) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import { hello } from \" ./b.ts \" ; \n \n hello(); \n \n const b = \" b \" ; \n \n /** JSDoc {@link hello} and {@linkcode b} */ \n function a() {} \n "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 7 ,
" character " : 10
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : [
{
" language " : " typescript " ,
" value " : " function a(): void "
} ,
" JSDoc [hello](file:///a/b.ts#L1,1) and [`b`](file:///a/file.ts#L5,7) "
] ,
" range " : {
" start " : {
" line " : 7 ,
" character " : 9
} ,
" end " : {
" line " : 7 ,
" character " : 10
}
}
} ) )
) ;
shutdown ( & mut client ) ;
}
2021-11-22 19:09:19 -05:00
#[ test ]
fn lsp_goto_type_definition ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " interface A { \n a: string; \n } \n \n export class B implements A { \n a = \" a \" ; \n log() { \n console.log(this.a); \n } \n } \n \n const b = new B(); \n b; \n " ,
}
} ) ,
) ;
let ( maybe_res , maybe_error ) = client
. write_request ::< _ , _ , Value > (
" textDocument/typeDefinition " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 12 ,
" character " : 1
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_error . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( [
{
" targetUri " : " file:///a/file.ts " ,
" targetRange " : {
" start " : {
" line " : 4 ,
" character " : 0
} ,
" end " : {
" line " : 9 ,
" character " : 1
}
} ,
" targetSelectionRange " : {
" start " : {
" line " : 4 ,
" character " : 13
} ,
" end " : {
" line " : 4 ,
" character " : 14
}
}
}
] ) )
) ;
shutdown ( & mut client ) ;
}
2021-05-17 16:45:13 -04:00
#[ test ]
fn lsp_call_hierarchy ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " function foo() { \n return false; \n } \n \n class Bar { \n baz() { \n return foo(); \n } \n } \n \n function main() { \n const bar = new Bar(); \n bar.baz(); \n } \n \n main(); "
}
} ) ,
) ;
let ( maybe_res , maybe_error ) = client
. write_request (
" textDocument/prepareCallHierarchy " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 5 ,
" character " : 3
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_error . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " prepare_call_hierarchy_response.json " ) )
) ;
let ( maybe_res , maybe_error ) = client
. write_request (
" callHierarchy/incomingCalls " ,
load_fixture ( " incoming_calls_params.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_error . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " incoming_calls_response.json " ) )
) ;
let ( maybe_res , maybe_error ) = client
. write_request (
" callHierarchy/outgoingCalls " ,
load_fixture ( " outgoing_calls_params.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_error . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " outgoing_calls_response.json " ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_format_mbc ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " const bar = '👍🇺🇸😃' \n console.log('hello deno') \n "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/formatting " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" options " : {
" tabSize " : 2 ,
" insertSpaces " : true
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( load_fixture ( " formatting_mbc_response.json " ) ) )
) ;
shutdown ( & mut client ) ;
}
2021-11-24 15:14:19 -05:00
#[ test ]
fn lsp_format_exclude_with_config ( ) {
let temp_dir = TempDir ::new ( ) . unwrap ( ) ;
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 deno_exe = deno_exe_path ( ) ;
let mut client = LspClient ::new ( & deno_exe ) . unwrap ( ) ;
client
. write_request ::< _ , _ , Value > ( " initialize " , params )
. unwrap ( ) ;
let file_uri =
ModuleSpecifier ::from_file_path ( temp_dir . path ( ) . join ( " ignored.ts " ) )
. unwrap ( )
. to_string ( ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : file_uri ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " function myFunc(){} "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/formatting " ,
json! ( {
" textDocument " : {
" uri " : file_uri
} ,
" options " : {
" tabSize " : 2 ,
" insertSpaces " : true
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! ( maybe_res , Some ( json! ( null ) ) ) ;
shutdown ( & mut client ) ;
}
2022-01-17 20:10:17 -05:00
#[ test ]
fn lsp_format_exclude_default_config ( ) {
let temp_dir = TempDir ::new ( ) . unwrap ( ) ;
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 ) . unwrap ( ) ;
client
. write_request ::< _ , _ , Value > ( " initialize " , params )
. unwrap ( ) ;
let file_uri =
ModuleSpecifier ::from_file_path ( workspace_root . join ( " ignored.ts " ) )
. unwrap ( )
. to_string ( ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : file_uri ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " function myFunc(){} "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/formatting " ,
json! ( {
" textDocument " : {
" uri " : file_uri
} ,
" options " : {
" tabSize " : 2 ,
" insertSpaces " : true
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! ( maybe_res , Some ( json! ( null ) ) ) ;
shutdown ( & mut client ) ;
}
2021-05-17 16:45:13 -04:00
#[ test ]
fn lsp_large_doc_changes ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open ( & mut client , load_fixture ( " did_open_params_large.json " ) ) ;
client
. write_notification (
" textDocument/didChange " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" version " : 2
} ,
" contentChanges " : [
{
" range " : {
" start " : {
" line " : 444 ,
" character " : 11
} ,
" end " : {
" line " : 444 ,
" character " : 14
}
} ,
" text " : " +++ "
}
]
} ) ,
)
. unwrap ( ) ;
client
. write_notification (
" textDocument/didChange " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" version " : 2
} ,
" contentChanges " : [
{
" range " : {
" start " : {
" line " : 445 ,
" character " : 4
} ,
" end " : {
" line " : 445 ,
" character " : 4
}
} ,
" text " : " // "
}
]
} ) ,
)
. unwrap ( ) ;
client
. write_notification (
2021-05-20 17:35:37 -04:00
" textDocument/didChange " ,
2021-05-17 16:45:13 -04:00
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" version " : 2
} ,
" contentChanges " : [
{
" range " : {
" start " : {
" line " : 477 ,
" character " : 4
} ,
" end " : {
" line " : 477 ,
" character " : 9
}
} ,
" text " : " error "
}
]
} ) ,
)
. unwrap ( ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 421 ,
" character " : 30
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_res . is_some ( ) ) ;
assert! ( maybe_err . is_none ( ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 444 ,
" character " : 6
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_res . is_some ( ) ) ;
assert! ( maybe_err . is_none ( ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 461 ,
" character " : 34
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_res . is_some ( ) ) ;
assert! ( maybe_err . is_none ( ) ) ;
shutdown ( & mut client ) ;
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 ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/documentSymbol " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " document_symbol_response.json " ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_folding_range ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " // #region 1 \n /* \n * Some comment \n */ \n class Foo { \n bar(a, b) { \n if (a === b) { \n return true; \n } \n return false; \n } \n } \n // #endregion "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/foldingRange " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
}
} ) ,
)
. unwrap ( ) ;
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
}
] ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_rename ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
2021-06-19 11:23:50 -04:00
// this should not rename in comments and strings
" text " : " let variable = 'a'; // variable \n console.log(variable); \n \" variable \" ; \n "
2021-05-17 16:45:13 -04:00
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/rename " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" 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 ) ;
}
#[ test ]
fn lsp_selection_range ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " class Foo { \n bar(a, b) { \n if (a === b) { \n return true; \n } \n return false; \n } \n } "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/selectionRange " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" positions " : [
{
" line " : 2 ,
" character " : 8
}
]
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " selection_range_response.json " ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_semantic_tokens ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
load_fixture ( " did_open_params_semantic_tokens.json " ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/semanticTokens/full " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" data " : [
0 , 5 , 6 , 1 , 1 , 0 , 9 , 6 , 8 , 9 , 0 , 8 , 6 , 8 , 9 , 2 , 15 , 3 , 10 , 5 , 0 , 4 , 1 ,
6 , 1 , 0 , 12 , 7 , 2 , 16 , 1 , 8 , 1 , 7 , 41 , 0 , 4 , 1 , 6 , 0 , 0 , 2 , 5 , 11 , 16 ,
1 , 9 , 1 , 7 , 40 , 3 , 10 , 4 , 2 , 1 , 1 , 11 , 1 , 9 , 9 , 1 , 2 , 3 , 11 , 1 , 3 , 6 , 3 ,
0 , 1 , 0 , 15 , 4 , 2 , 0 , 1 , 30 , 1 , 6 , 9 , 1 , 2 , 3 , 11 , 1 , 1 , 9 , 9 , 9 , 3 , 0 ,
16 , 3 , 0 , 0 , 1 , 17 , 12 , 11 , 3 , 0 , 24 , 3 , 0 , 0 , 0 , 4 , 9 , 9 , 2
]
} ) )
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/semanticTokens/range " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" range " : {
" start " : {
" line " : 0 ,
" character " : 0
} ,
" end " : {
" line " : 6 ,
" character " : 0
}
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" data " : [
0 , 5 , 6 , 1 , 1 , 0 , 9 , 6 , 8 , 9 , 0 , 8 , 6 , 8 , 9 , 2 , 15 , 3 , 10 , 5 , 0 , 4 , 1 ,
6 , 1 , 0 , 12 , 7 , 2 , 16 , 1 , 8 , 1 , 7 , 41 , 0 , 4 , 1 , 6 , 0 , 0 , 2 , 5 , 11 , 16 ,
1 , 9 , 1 , 7 , 40
]
} ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_code_lens ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " class A { \n a = \" a \" ; \n \n b() { \n console.log(this.a); \n } \n \n c() { \n this.a = \" c \" ; \n } \n } \n \n const a = new A(); \n a.b(); \n "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/codeLens " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! ( maybe_res , Some ( load_fixture ( " code_lens_response.json " ) ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" codeLens/resolve " ,
json! ( {
" range " : {
" start " : {
" line " : 0 ,
" character " : 6
} ,
" end " : {
" line " : 0 ,
" character " : 7
}
} ,
" data " : {
" specifier " : " file:///a/file.ts " ,
" source " : " references "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_lens_resolve_response.json " ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_code_lens_impl ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
2021-06-04 17:31:44 -04:00
" text " : " interface A { \n b(): void; \n } \n \n class B implements A { \n b() { \n console.log( \" b \" ); \n } \n } \n \n interface C { \n c: string; \n } \n "
2021-05-17 16:45:13 -04:00
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/codeLens " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_lens_response_impl.json " ) )
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" codeLens/resolve " ,
json! ( {
" range " : {
" start " : {
" line " : 0 ,
" character " : 10
} ,
" end " : {
" line " : 0 ,
" character " : 11
}
} ,
" data " : {
" specifier " : " file:///a/file.ts " ,
" source " : " implementations "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_lens_resolve_response_impl.json " ) )
) ;
2021-06-04 17:31:44 -04:00
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" codeLens/resolve " ,
json! ( {
" range " : {
" start " : {
" line " : 10 ,
" character " : 10
} ,
" end " : {
" line " : 10 ,
" character " : 11
}
} ,
" data " : {
" specifier " : " file:///a/file.ts " ,
" source " : " implementations "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" range " : {
" start " : {
" line " : 10 ,
" character " : 10
} ,
" end " : {
" line " : 10 ,
" character " : 11
}
} ,
" command " : {
" title " : " 0 implementations " ,
" command " : " "
}
} ) )
) ;
2021-05-17 16:45:13 -04:00
shutdown ( & mut client ) ;
2021-06-07 07:38:07 -04:00
}
#[ test ]
fn lsp_code_lens_test ( ) {
let mut client = init ( " initialize_params_code_lens_test.json " ) ;
did_open (
& mut client ,
load_fixture ( " did_open_params_test_code_lens.json " ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/codeLens " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_lens_response_test.json " ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_code_lens_test_disabled ( ) {
let mut client = init ( " initialize_params_code_lens_test_disabled.json " ) ;
client
. write_notification (
" textDocument/didOpen " ,
load_fixture ( " did_open_params_test_code_lens.json " ) ,
)
. unwrap ( ) ;
let ( id , method , _ ) = client . read_request ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " workspace/configuration " ) ;
client
. write_response (
id ,
2022-01-17 20:10:17 -05:00
json! ( [ {
2021-06-07 07:38:07 -04:00
" enable " : true ,
" codeLens " : {
" test " : false
}
2022-01-17 20:10:17 -05:00
} ] ) ,
2021-06-07 07:38:07 -04:00
)
. unwrap ( ) ;
let ( method , _ ) = client . read_notification ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " textDocument/publishDiagnostics " ) ;
let ( method , _ ) = client . read_notification ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " textDocument/publishDiagnostics " ) ;
let ( method , _ ) = client . read_notification ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " textDocument/publishDiagnostics " ) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/codeLens " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! ( maybe_res , Some ( json! ( [ ] ) ) ) ;
shutdown ( & mut client ) ;
2021-05-17 16:45:13 -04:00
}
#[ test ]
fn lsp_code_lens_non_doc_nav_tree ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " console.log(Date.now()); \n "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/references " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 3
} ,
" context " : {
" includeDeclaration " : true
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" deno/virtualTextDocument " ,
json! ( {
" textDocument " : {
2021-10-28 19:56:01 -04:00
" uri " : " deno:asset/lib.deno.shared_globals.d.ts "
2021-05-17 16:45:13 -04:00
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Vec < lsp ::CodeLens > > (
" textDocument/codeLens " ,
json! ( {
" textDocument " : {
2021-10-28 19:56:01 -04:00
" uri " : " deno:asset/lib.deno.shared_globals.d.ts "
2021-05-17 16:45:13 -04:00
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
let res = maybe_res . unwrap ( ) ;
assert! ( res . len ( ) > 50 ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , lsp ::CodeLens > (
" codeLens/resolve " ,
json! ( {
" range " : {
" start " : {
" line " : 416 ,
" character " : 12
} ,
" end " : {
" line " : 416 ,
" character " : 19
}
} ,
" data " : {
" specifier " : " asset:///lib.deno.shared_globals.d.ts " ,
" source " : " references "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
shutdown ( & mut client ) ;
}
2021-06-04 17:31:44 -04:00
#[ test ]
fn lsp_nav_tree_updates ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " interface A { \n b(): void; \n } \n \n class B implements A { \n b() { \n console.log( \" b \" ); \n } \n } \n \n interface C { \n c: string; \n } \n "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/codeLens " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_lens_response_impl.json " ) )
) ;
client
. write_notification (
" textDocument/didChange " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" version " : 2
} ,
" contentChanges " : [
{
" range " : {
" start " : {
" line " : 10 ,
" character " : 0
} ,
" end " : {
" line " : 13 ,
" character " : 0
}
} ,
" text " : " "
}
]
} ) ,
)
. unwrap ( ) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/codeLens " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_lens_response_changed.json " ) )
) ;
shutdown ( & mut client ) ;
}
2021-05-17 16:45:13 -04:00
#[ test ]
fn lsp_signature_help ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " /** \n * Adds two numbers. \n * @param a This is a first number. \n * @param b This is a second number. \n */ \n function add(a: number, b: number) { \n return a + b; \n } \n \n add( "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/signatureHelp " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" character " : 4 ,
" line " : 9
} ,
" context " : {
" triggerKind " : 2 ,
" triggerCharacter " : " ( " ,
" isRetrigger " : false
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" signatures " : [
{
" label " : " add(a: number, b: number): number " ,
2021-11-07 17:26:11 -05:00
" documentation " : {
" kind " : " markdown " ,
" value " : " Adds two numbers. "
} ,
2021-05-17 16:45:13 -04:00
" parameters " : [
{
" label " : " a: number " ,
2021-11-07 17:26:11 -05:00
" documentation " : {
" kind " : " markdown " ,
" value " : " This is a first number. "
}
2021-05-17 16:45:13 -04:00
} ,
{
" label " : " b: number " ,
2021-11-07 17:26:11 -05:00
" documentation " : {
" kind " : " markdown " ,
" value " : " This is a second number. "
}
2021-05-17 16:45:13 -04:00
}
]
}
] ,
" activeSignature " : 0 ,
" activeParameter " : 0
} ) )
) ;
client
. write_notification (
" textDocument/didChange " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" version " : 2
} ,
" contentChanges " : [
{
" range " : {
" start " : {
" line " : 9 ,
" character " : 4
} ,
" end " : {
" line " : 9 ,
" character " : 4
}
} ,
" text " : " 123, "
}
]
} ) ,
)
. unwrap ( ) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/signatureHelp " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" character " : 8 ,
" line " : 9
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" signatures " : [
{
" label " : " add(a: number, b: number): number " ,
2021-11-07 17:26:11 -05:00
" documentation " : {
" kind " : " markdown " ,
" value " : " Adds two numbers. "
} ,
2021-05-17 16:45:13 -04:00
" parameters " : [
{
" label " : " a: number " ,
2021-11-07 17:26:11 -05:00
" documentation " : {
" kind " : " markdown " ,
" value " : " This is a first number. "
}
2021-05-17 16:45:13 -04:00
} ,
{
" label " : " b: number " ,
2021-11-07 17:26:11 -05:00
" documentation " : {
" kind " : " markdown " ,
" value " : " This is a second number. "
}
2021-05-17 16:45:13 -04:00
}
]
}
] ,
" activeSignature " : 0 ,
" activeParameter " : 1
} ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_code_actions ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " export function a(): void { \n await Promise.resolve( \" a \" ); \n } \n \n export function b(): void { \n await Promise.resolve( \" b \" ); \n } \n "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/codeAction " ,
load_fixture ( " code_action_params.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! ( maybe_res , Some ( load_fixture ( " code_action_response.json " ) ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" codeAction/resolve " ,
load_fixture ( " code_action_resolve_params.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_action_resolve_response.json " ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_code_actions_deno_cache ( ) {
2022-01-24 18:04:24 -05:00
let mut session = TestSession ::from_file ( " initialize_params.json " ) ;
let diagnostics = session . did_open ( json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import * as a from \" https://deno.land/x/a/mod.ts \" ; \n \n console.log(a); \n "
}
} ) ) ;
2022-01-24 15:30:01 -05:00
assert_eq! (
diagnostics . with_source ( " deno " ) ,
load_fixture_as ( " diagnostics_deno_deps.json " )
) ;
2021-05-19 08:28:23 -04:00
2022-01-24 18:04:24 -05:00
let ( maybe_res , maybe_err ) = session
. client
2021-05-17 16:45:13 -04:00
. write_request (
" textDocument/codeAction " ,
load_fixture ( " code_action_params_cache.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_action_response_cache.json " ) )
) ;
2022-01-24 18:04:24 -05:00
session . shutdown_and_exit ( ) ;
2021-05-17 16:45:13 -04:00
}
2021-05-29 07:21:11 -04:00
#[ test ]
fn lsp_code_actions_imports ( ) {
2022-01-24 15:30:01 -05:00
let mut session = TestSession ::from_file ( " initialize_params.json " ) ;
session . did_open ( json! ( {
" textDocument " : {
" uri " : " file:///a/file00.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " export const abc = \" abc \" ; \n export const def = \" def \" ; \n "
}
} ) ) ;
session . did_open ( json! ( {
" textDocument " : {
" uri " : " file:///a/file01.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " \n console.log(abc); \n console.log(def) \n "
}
} ) ) ;
2021-05-29 07:21:11 -04:00
2022-01-24 15:30:01 -05:00
let ( maybe_res , maybe_err ) = session
. client
2021-05-29 07:21:11 -04:00
. write_request (
" textDocument/codeAction " ,
load_fixture ( " code_action_params_imports.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_action_response_imports.json " ) )
) ;
2022-01-24 15:30:01 -05:00
let ( maybe_res , maybe_err ) = session
. client
2021-05-29 07:21:11 -04:00
. write_request (
" codeAction/resolve " ,
load_fixture ( " code_action_resolve_params_imports.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_action_resolve_response_imports.json " ) )
) ;
2022-01-24 15:30:01 -05:00
session . shutdown_and_exit ( ) ;
2021-05-29 07:21:11 -04:00
}
2021-08-05 21:46:32 -04:00
#[ test ]
fn lsp_code_actions_refactor ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " var x: { a?: number; b?: string } = {}; \n "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/codeAction " ,
load_fixture ( " code_action_params_refactor.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_action_response_refactor.json " ) )
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" codeAction/resolve " ,
load_fixture ( " code_action_resolve_params_refactor.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_action_resolve_response_refactor.json " ) )
) ;
shutdown ( & mut client ) ;
}
2021-08-09 19:56:34 -04:00
#[ test ]
fn lsp_code_actions_refactor_no_disabled_support ( ) {
let mut client = init ( " initialize_params_ca_no_disabled.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " interface A { \n a: string; \n } \n \n interface B { \n b: string; \n } \n \n class AB implements A, B { \n a = \" a \" ; \n b = \" b \" ; \n } \n \n new AB().a; \n "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/codeAction " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" range " : {
" start " : {
" line " : 0 ,
" character " : 0
} ,
" end " : {
" line " : 14 ,
" character " : 0
}
} ,
" context " : {
" diagnostics " : [ ] ,
" only " : [
" refactor "
]
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_action_response_no_disabled.json " ) )
) ;
shutdown ( & mut client ) ;
}
2021-05-20 17:35:37 -04:00
#[ test ]
fn lsp_code_actions_deadlock ( ) {
let mut client = init ( " initialize_params.json " ) ;
client
. write_notification (
" textDocument/didOpen " ,
load_fixture ( " did_open_params_large.json " ) ,
)
. unwrap ( ) ;
let ( id , method , _ ) = client . read_request ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " workspace/configuration " ) ;
client
2022-01-17 20:10:17 -05:00
. write_response ( id , json! ( [ { " enable " : true } ] ) )
2021-05-20 17:35:37 -04:00
. unwrap ( ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/semanticTokens/full " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
2022-01-24 15:30:01 -05:00
read_diagnostics ( & mut client ) ;
2021-05-20 17:35:37 -04:00
client
. write_notification (
" textDocument/didChange " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" version " : 2
} ,
" contentChanges " : [
{
" range " : {
" start " : {
" line " : 444 ,
" character " : 11
} ,
" end " : {
" line " : 444 ,
" character " : 14
}
} ,
" text " : " +++ "
}
]
} ) ,
)
. unwrap ( ) ;
client
. write_notification (
" textDocument/didChange " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" version " : 2
} ,
" contentChanges " : [
{
" range " : {
" start " : {
" line " : 445 ,
" character " : 4
} ,
" end " : {
" line " : 445 ,
" character " : 4
}
} ,
" text " : " // "
}
]
} ) ,
)
. unwrap ( ) ;
client
. write_notification (
" textDocument/didChange " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" version " : 2
} ,
" contentChanges " : [
{
" range " : {
" start " : {
" line " : 477 ,
" character " : 4
} ,
" end " : {
" line " : 477 ,
" character " : 9
}
} ,
" text " : " error "
}
]
} ) ,
)
. unwrap ( ) ;
// diagnostics only trigger after changes have elapsed in a separate thread,
// so we need to delay the next messages a little bit to attempt to create a
// potential for a deadlock with the codeAction
std ::thread ::sleep ( std ::time ::Duration ::from_millis ( 50 ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
} ,
" position " : {
" line " : 609 ,
" character " : 33 ,
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/codeAction " ,
load_fixture ( " code_action_params_deadlock.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
2022-01-24 15:30:01 -05:00
read_diagnostics ( & mut client ) ;
2021-05-20 17:35:37 -04:00
shutdown ( & mut client ) ;
}
2021-05-17 16:45:13 -04:00
#[ test ]
fn lsp_completions ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " Deno. "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/completion " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 5
} ,
" context " : {
" triggerKind " : 2 ,
" triggerCharacter " : " . "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
if let Some ( lsp ::CompletionResponse ::List ( list ) ) = maybe_res {
assert! ( ! list . is_incomplete ) ;
assert! ( list . items . len ( ) > 90 ) ;
} else {
panic! ( " unexpected response " ) ;
}
let ( maybe_res , maybe_err ) = client
. write_request (
" completionItem/resolve " ,
load_fixture ( " completion_resolve_params.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " completion_resolve_response.json " ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_completions_optional ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " interface A { \n b?: string; \n } \n \n const o: A = {}; \n \n function c(s: string) {} \n \n c(o.) "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/completion " ,
load_fixture ( " completion_request_params_optional.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" isIncomplete " : false ,
" items " : [
{
" label " : " b? " ,
" kind " : 5 ,
2021-08-26 20:12:59 -04:00
" sortText " : " 11 " ,
2021-05-17 16:45:13 -04:00
" filterText " : " b " ,
" insertText " : " b " ,
" data " : {
" tsc " : {
" specifier " : " file:///a/file.ts " ,
" position " : 79 ,
" name " : " b " ,
" useCodeSnippet " : false
}
}
}
]
} ) )
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" completionItem/resolve " ,
load_fixture ( " completion_resolve_params_optional.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" label " : " b? " ,
" kind " : 5 ,
" detail " : " (property) A.b?: string | undefined " ,
" documentation " : {
" kind " : " markdown " ,
" value " : " "
} ,
" sortText " : " 1 " ,
" filterText " : " b " ,
" insertText " : " b "
} ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_completions_registry ( ) {
let _g = http_server ( ) ;
let mut client = init ( " initialize_params_registry.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import * as a from \" http://localhost:4545/x/a@ \" "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/completion " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 46
} ,
" context " : {
" triggerKind " : 2 ,
" triggerCharacter " : " @ "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
if let Some ( lsp ::CompletionResponse ::List ( list ) ) = maybe_res {
assert! ( ! list . is_incomplete ) ;
assert_eq! ( list . items . len ( ) , 3 ) ;
} else {
panic! ( " unexpected response " ) ;
}
let ( maybe_res , maybe_err ) = client
. write_request (
" completionItem/resolve " ,
load_fixture ( " completion_resolve_params_registry.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " completion_resolve_response_registry.json " ) )
) ;
shutdown ( & mut client ) ;
}
#[ test ]
fn lsp_completions_registry_empty ( ) {
let _g = http_server ( ) ;
let mut client = init ( " initialize_params_registry.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import * as a from \" \" "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/completion " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 20
} ,
" context " : {
" triggerKind " : 2 ,
" triggerCharacter " : " \" "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " completion_request_response_empty.json " ) )
) ;
shutdown ( & mut client ) ;
}
2021-06-01 07:53:08 -04:00
#[ test ]
fn lsp_auto_discover_registry ( ) {
let _g = http_server ( ) ;
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import * as a from \" http://localhost:4545/x/a@ \" "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/completion " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 46
} ,
" context " : {
" triggerKind " : 2 ,
" triggerCharacter " : " @ "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
let ( method , maybe_res ) = client . read_notification ( ) . unwrap ( ) ;
assert_eq! ( method , " deno/registryState " ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" origin " : " http://localhost:4545 " ,
" suggestions " : true ,
} ) )
) ;
shutdown ( & mut client ) ;
}
2021-07-27 17:25:09 -04:00
#[ test ]
fn lsp_cache_location ( ) {
let _g = http_server ( ) ;
let temp_dir = TempDir ::new ( ) . expect ( " could not create temp dir " ) ;
let mut params : lsp ::InitializeParams =
2022-01-06 19:27:13 -05:00
serde_json ::from_value ( load_fixture ( " initialize_params_registry.json " ) )
. unwrap ( ) ;
2021-07-27 17:25:09 -04:00
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 deno_exe = deno_exe_path ( ) ;
let mut client = LspClient ::new ( & deno_exe ) . unwrap ( ) ;
client
. write_request ::< _ , _ , Value > ( " initialize " , params )
. unwrap ( ) ;
client . write_notification ( " initialized " , json! ( { } ) ) . unwrap ( ) ;
2022-01-24 18:04:24 -05:00
let mut session = TestSession ::from_client ( client ) ;
session . did_open ( json! ( {
" textDocument " : {
" uri " : " file:///a/file_01.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " export const a = \" a \" ; \n " ,
}
} ) ) ;
let diagnostics =
session . did_open ( load_fixture ( " did_open_params_import_hover.json " ) ) ;
assert_eq! ( diagnostics . viewed ( ) . len ( ) , 7 ) ;
let ( maybe_res , maybe_err ) = session
. client
2021-07-27 17:25:09 -04:00
. write_request ::< _ , _ , Value > (
" deno/cache " ,
json! ( {
" referrer " : {
" uri " : " file:///a/file.ts " ,
} ,
" uris " : [ ] ,
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
2022-01-24 18:04:24 -05:00
let ( maybe_res , maybe_err ) = session
. client
2021-07-27 17:25:09 -04:00
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
} ,
" position " : {
" line " : 0 ,
" character " : 28
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : {
" kind " : " markdown " ,
" value " : " **Resolved Dependency** \n \n **Code**: http​://127.0.0.1:4545/xTypeScriptTypes.js \n "
} ,
" range " : {
" start " : {
" line " : 0 ,
2021-10-28 19:56:01 -04:00
" character " : 19
2021-07-27 17:25:09 -04:00
} ,
" end " :{
" line " : 0 ,
2021-10-28 19:56:01 -04:00
" character " : 62
2021-07-27 17:25:09 -04:00
}
}
} ) )
) ;
2022-01-24 18:04:24 -05:00
let ( maybe_res , maybe_err ) = session
. client
2022-01-06 19:27:13 -05:00
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
} ,
" position " : {
" line " : 7 ,
" character " : 28
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : {
" kind " : " markdown " ,
" value " : " **Resolved Dependency** \n \n **Code**: http​://localhost:4545/x/a/mod.ts \n \n \n --- \n \n **a** \n \n mod.ts "
} ,
" range " : {
" start " : {
" line " : 7 ,
" character " : 19
} ,
" end " : {
" line " : 7 ,
" character " : 53
}
}
} ) )
) ;
2021-07-27 17:25:09 -04:00
let cache_path = temp_dir . path ( ) . join ( " .cache " ) ;
assert! ( cache_path . is_dir ( ) ) ;
assert! ( cache_path . join ( " gen " ) . is_dir ( ) ) ;
2022-01-24 18:04:24 -05:00
session . shutdown_and_exit ( ) ;
2021-07-27 17:25:09 -04:00
}
2022-01-23 19:27:52 -05:00
/// Sets the TLS root certificate on startup, which allows the LSP to connect to
/// the custom signed test server and be able to retrieve the registry config
/// 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 ( ) ;
params . root_uri = Some ( Url ::from_file_path ( testdata_path ( ) ) . unwrap ( ) ) ;
let deno_exe = deno_exe_path ( ) ;
let mut client = LspClient ::new ( & deno_exe ) . unwrap ( ) ;
client
. write_request ::< _ , _ , Value > ( " initialize " , params )
. unwrap ( ) ;
client . write_notification ( " initialized " , json! ( { } ) ) . unwrap ( ) ;
2022-01-24 15:30:01 -05:00
let mut session = TestSession ::from_client ( client ) ;
session . did_open ( json! ( {
" textDocument " : {
" uri " : " file:///a/file_01.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " export const a = \" a \" ; \n " ,
}
} ) ) ;
2022-01-23 19:27:52 -05:00
let diagnostics =
2022-01-24 15:30:01 -05:00
session . did_open ( load_fixture ( " did_open_params_tls_cert.json " ) ) ;
2022-01-24 18:04:24 -05:00
let diagnostics = diagnostics . viewed ( ) ;
2022-01-24 15:30:01 -05:00
assert_eq! ( diagnostics . len ( ) , 7 ) ;
let ( maybe_res , maybe_err ) = session
. client
2022-01-23 19:27:52 -05:00
. write_request ::< _ , _ , Value > (
" deno/cache " ,
json! ( {
" referrer " : {
" uri " : " file:///a/file.ts " ,
} ,
" uris " : [ ] ,
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
2022-01-24 15:30:01 -05:00
let ( maybe_res , maybe_err ) = session
. client
2022-01-23 19:27:52 -05:00
. write_request (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
} ,
" position " : {
" line " : 0 ,
" character " : 28
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : {
" kind " : " markdown " ,
" value " : " **Resolved Dependency** \n \n **Code**: https​://localhost:5545/xTypeScriptTypes.js \n "
} ,
" range " : {
" start " : {
" line " : 0 ,
" character " : 19
} ,
" end " :{
" line " : 0 ,
" character " : 63
}
}
} ) )
) ;
2022-01-24 15:30:01 -05:00
let ( maybe_res , maybe_err ) = session
. client
2022-01-23 19:27:52 -05:00
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
} ,
" position " : {
" line " : 7 ,
" character " : 28
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : {
" kind " : " markdown " ,
" value " : " **Resolved Dependency** \n \n **Code**: http​://localhost:4545/x/a/mod.ts \n \n \n --- \n \n **a** \n \n mod.ts "
} ,
" range " : {
" start " : {
" line " : 7 ,
" character " : 19
} ,
" end " : {
" line " : 7 ,
" character " : 53
}
}
} ) )
) ;
2022-01-24 15:30:01 -05:00
session . shutdown_and_exit ( ) ;
2022-01-23 19:27:52 -05:00
}
2021-05-18 06:19:52 -04:00
#[ test ]
2022-02-04 02:14:57 -05:00
fn lsp_diagnostics_warn_redirect ( ) {
2021-05-18 06:19:52 -04:00
let _g = http_server ( ) ;
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
2021-08-11 10:20:47 -04:00
" text " : " import * as a from \" http://127.0.0.1:4545/x_deno_warning.js \" ; \n \n console.log(a) \n " ,
2021-05-18 06:19:52 -04:00
} ,
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" deno/cache " ,
json! ( {
" referrer " : {
" uri " : " file:///a/file.ts " ,
} ,
" uris " : [
{
2021-08-11 10:20:47 -04:00
" uri " : " http://127.0.0.1:4545/x_deno_warning.js " ,
2021-05-18 06:19:52 -04:00
}
] ,
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
2022-01-24 15:30:01 -05:00
let diagnostics = read_diagnostics ( & mut client ) ;
2021-05-18 06:19:52 -04:00
assert_eq! (
2022-01-24 15:30:01 -05:00
diagnostics . with_source ( " deno " ) ,
lsp ::PublishDiagnosticsParams {
2021-05-18 06:19:52 -04:00
uri : Url ::parse ( " file:///a/file.ts " ) . unwrap ( ) ,
2022-02-04 02:14:57 -05:00
diagnostics : vec ! [
lsp ::Diagnostic {
range : lsp ::Range {
start : lsp ::Position {
line : 0 ,
character : 19
} ,
end : lsp ::Position {
line : 0 ,
character : 60
}
2021-05-18 06:19:52 -04:00
} ,
2022-02-04 02:14:57 -05:00
severity : Some ( lsp ::DiagnosticSeverity ::WARNING ) ,
code : Some ( lsp ::NumberOrString ::String ( " deno-warn " . to_string ( ) ) ) ,
source : Some ( " deno " . to_string ( ) ) ,
message : " foobar " . to_string ( ) ,
.. Default ::default ( )
} ,
lsp ::Diagnostic {
range : lsp ::Range {
start : lsp ::Position {
line : 0 ,
character : 19
} ,
end : lsp ::Position {
line : 0 ,
character : 60
}
} ,
severity : Some ( lsp ::DiagnosticSeverity ::INFORMATION ) ,
code : Some ( lsp ::NumberOrString ::String ( " redirect " . to_string ( ) ) ) ,
source : Some ( " deno " . to_string ( ) ) ,
message : " The import of \" http://127.0.0.1:4545/x_deno_warning.js \" was redirected to \" http://127.0.0.1:4545/x_deno_warning_redirect.js \" . " . to_string ( ) ,
data : Some ( json! ( { " specifier " : " http://127.0.0.1:4545/x_deno_warning.js " , " redirect " : " http://127.0.0.1:4545/x_deno_warning_redirect.js " } ) ) ,
.. Default ::default ( )
}
] ,
2021-05-18 06:19:52 -04:00
version : Some ( 1 ) ,
2022-01-24 15:30:01 -05:00
}
2021-05-18 06:19:52 -04:00
) ;
shutdown ( & mut client ) ;
}
2022-02-04 02:14:57 -05:00
#[ test ]
fn lsp_redirect_quick_fix ( ) {
let _g = http_server ( ) ;
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import * as a from \" http://127.0.0.1:4545/x_deno_warning.js \" ; \n \n console.log(a) \n " ,
} ,
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" deno/cache " ,
json! ( {
" referrer " : {
" uri " : " file:///a/file.ts " ,
} ,
" uris " : [
{
" uri " : " http://127.0.0.1:4545/x_deno_warning.js " ,
}
] ,
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
let diagnostics = read_diagnostics ( & mut client )
. with_source ( " deno " )
. diagnostics ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/codeAction " ,
json! ( json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" range " : {
" start " : {
" line " : 0 ,
" character " : 19
} ,
" end " : {
" line " : 0 ,
" character " : 60
}
} ,
" context " : {
" diagnostics " : diagnostics ,
" only " : [
" quickfix "
]
}
} ) ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_action_redirect_response.json " ) )
) ;
shutdown ( & mut client ) ;
}
2021-11-17 21:05:20 -05:00
#[ test ]
fn lsp_diagnostics_deprecated ( ) {
let mut client = init ( " initialize_params.json " ) ;
let diagnostics = did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " /** @deprecated */ \n export const a = \" a \" ; \n \n a; \n " ,
} ,
} ) ,
) ;
assert_eq! (
json! ( diagnostics ) ,
json! ( [
{
" 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
}
} ,
" severity " : 4 ,
" code " : 6385 ,
" source " : " deno-ts " ,
" message " : " 'a' is deprecated. " ,
" relatedInformation " : [ ] ,
" tags " : [
2
]
}
] ,
" version " : 1
}
] )
) ;
shutdown ( & mut client ) ;
}
2021-05-24 22:34:01 -04:00
#[ test ]
fn lsp_diagnostics_deno_types ( ) {
let mut client = init ( " initialize_params.json " ) ;
client
. write_notification (
" textDocument/didOpen " ,
load_fixture ( " did_open_params_deno_types.json " ) ,
)
. unwrap ( ) ;
let ( id , method , _ ) = client . read_request ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " workspace/configuration " ) ;
client
2022-01-17 20:10:17 -05:00
. write_response ( id , json! ( [ { " enable " : true } ] ) )
2021-05-24 22:34:01 -04:00
. unwrap ( ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/documentSymbol " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_res . is_some ( ) ) ;
assert! ( maybe_err . is_none ( ) ) ;
2022-01-24 15:30:01 -05:00
let diagnostics = read_diagnostics ( & mut client ) ;
2022-01-24 18:04:24 -05:00
assert_eq! ( diagnostics . viewed ( ) . len ( ) , 5 ) ;
2021-05-24 22:34:01 -04:00
shutdown ( & mut client ) ;
}
2021-06-03 07:13:53 -04:00
#[ test ]
fn lsp_diagnostics_refresh_dependents ( ) {
2022-01-24 15:30:01 -05:00
let mut session = TestSession ::from_file ( " initialize_params.json " ) ;
session . did_open ( json! ( {
" textDocument " : {
" uri " : " file:///a/file_00.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " export const a = \" a \" ; \n " ,
} ,
} ) ) ;
session . did_open ( json! ( {
" textDocument " : {
" uri " : " file:///a/file_01.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " export * from \" ./file_00.ts \" ; \n " ,
} ,
} ) ) ;
let diagnostics = session . did_open ( json! ( {
" textDocument " : {
" uri " : " file:///a/file_02.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import { a, b } from \" ./file_01.ts \" ; \n \n console.log(a, b); \n "
}
} ) ) ;
2021-06-03 07:13:53 -04:00
assert_eq! (
2022-01-24 15:30:01 -05:00
json! ( diagnostics . with_file_and_source ( " file:///a/file_02.ts " , " deno-ts " ) ) ,
2022-01-17 20:10:17 -05:00
json! ( {
2021-06-03 07:13:53 -04:00
" uri " : " file:///a/file_02.ts " ,
" diagnostics " : [
{
" range " : {
" start " : {
" line " : 0 ,
" character " : 12
} ,
" end " : {
" line " : 0 ,
" character " : 13
}
} ,
" severity " : 1 ,
" code " : 2305 ,
" source " : " deno-ts " ,
" message " : " Module ' \" ./file_01.ts \" ' has no exported member 'b'. "
}
] ,
" version " : 1
2022-01-17 20:10:17 -05:00
} )
2021-06-03 07:13:53 -04:00
) ;
2022-01-24 15:30:01 -05:00
// fix the code causing the diagnostic
session
. client
2021-06-03 07:13:53 -04:00
. write_notification (
" textDocument/didChange " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file_00.ts " ,
" version " : 2
} ,
" contentChanges " : [
{
" range " : {
" start " : {
" line " : 1 ,
" character " : 0
} ,
" end " : {
" line " : 1 ,
" character " : 0
}
} ,
" text " : " export const b = \" b \" ; \n "
}
]
} ) ,
)
. unwrap ( ) ;
2022-01-24 15:30:01 -05:00
let diagnostics = session . read_diagnostics ( ) ;
2022-01-24 18:04:24 -05:00
assert_eq! ( diagnostics . viewed ( ) . len ( ) , 0 ) ; // no diagnostics now
2021-06-03 07:13:53 -04:00
2022-01-24 15:30:01 -05:00
session . shutdown_and_exit ( ) ;
assert_eq! ( session . client . queue_len ( ) , 0 ) ;
2021-06-03 07:13:53 -04:00
}
2021-05-17 16:45:13 -04:00
#[ derive(Deserialize) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct PerformanceAverage {
pub name : String ,
pub count : u32 ,
pub average_duration : u32 ,
}
#[ derive(Deserialize) ]
#[ serde(rename_all = " camelCase " ) ]
struct PerformanceAverages {
averages : Vec < PerformanceAverage > ,
}
#[ test ]
fn lsp_performance ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " console.log(Deno.args); \n "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 19
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , PerformanceAverages > ( " deno/performance " , json! ( { } ) )
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
if let Some ( res ) = maybe_res {
2022-01-24 15:30:01 -05:00
assert_eq! ( res . averages . len ( ) , 13 ) ;
2021-05-17 16:45:13 -04:00
} else {
panic! ( " unexpected result " ) ;
}
shutdown ( & mut client ) ;
}
2021-05-18 02:35:46 -04:00
#[ test ]
fn lsp_format_json ( ) {
let mut client = init ( " initialize_params.json " ) ;
client
. write_notification (
" textDocument/didOpen " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.json " ,
" languageId " : " json " ,
" version " : 1 ,
" text " : " { \" key \" : \" value \" } "
}
} ) ,
)
. unwrap ( ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/formatting " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.json "
} ,
" options " : {
" tabSize " : 2 ,
" insertSpaces " : true
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( [
{
" range " : {
" 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 }
} ,
" newText " : " } \n "
}
] ) )
) ;
shutdown ( & mut client ) ;
}
2021-06-02 06:29:58 -04:00
#[ test ]
fn lsp_json_no_diagnostics ( ) {
let mut client = init ( " initialize_params.json " ) ;
client
. write_notification (
" textDocument/didOpen " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.json " ,
" languageId " : " json " ,
" version " : 1 ,
" text " : " { \" key \" : \" value \" } "
}
} ) ,
)
. unwrap ( ) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/semanticTokens/full " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.json "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! ( maybe_res , Some ( json! ( null ) ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.json "
} ,
" position " : {
" line " : 0 ,
" character " : 3
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! ( maybe_res , Some ( json! ( null ) ) ) ;
shutdown ( & mut client ) ;
}
2021-05-18 02:35:46 -04:00
#[ test ]
fn lsp_format_markdown ( ) {
let mut client = init ( " initialize_params.json " ) ;
client
. write_notification (
" textDocument/didOpen " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.md " ,
" languageId " : " markdown " ,
" version " : 1 ,
" text " : " # Hello World "
}
} ) ,
)
. unwrap ( ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/formatting " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.md "
} ,
" options " : {
" tabSize " : 2 ,
" insertSpaces " : true
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( [
{
" range " : {
" start " : { " line " : 0 , " character " : 1 } ,
" end " : { " line " : 0 , " character " : 3 }
} ,
" newText " : " "
} ,
{
" range " : {
" start " : { " line " : 0 , " character " : 15 } ,
" end " : { " line " : 0 , " character " : 15 }
} ,
" newText " : " \n "
}
] ) )
) ;
shutdown ( & mut client ) ;
}
2021-06-01 05:24:36 -04:00
2021-09-13 14:19:10 -04:00
#[ test ]
fn lsp_format_with_config ( ) {
let temp_dir = TempDir ::new ( ) . expect ( " could not create temp dir " ) ;
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 deno_exe = deno_exe_path ( ) ;
let mut client = LspClient ::new ( & deno_exe ) . unwrap ( ) ;
client
. write_request ::< _ , _ , Value > ( " initialize " , params )
. unwrap ( ) ;
client
. write_notification (
" textDocument/didOpen " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " export async function someVeryLongFunctionName() { \n const response = fetch( \" http://localhost:4545/some/non/existent/path.json \" ); \n console.log(response.text()); \n console.log( \" finished! \" ) \n } "
}
} ) ,
)
. unwrap ( ) ;
// The options below should be ignored in favor of configuration from config file.
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/formatting " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" options " : {
" tabSize " : 2 ,
" insertSpaces " : true
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( [ {
" range " : {
" start " : {
" line " : 1 ,
" character " : 0
} ,
" end " : {
" line " : 1 ,
" character " : 0
}
} ,
" newText " : " \t "
} ,
{
" range " : {
" 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
}
} ,
" newText " : " ', \n \t "
} ,
{
" range " : {
" start " : {
" line " : 2 ,
" character " : 0
} ,
" end " : {
" line " : 2 ,
" character " : 0
}
} ,
" newText " : " \t "
} ,
{
" range " : {
" start " : {
" line " : 3 ,
" character " : 0
} ,
" end " : {
" line " : 3 ,
" character " : 0
}
} ,
" newText " : " \t "
} ,
{
" range " : {
" start " : {
" line " : 3 ,
" character " : 12
} ,
" end " : {
" line " : 3 ,
" character " : 13
}
} ,
" newText " : " ' "
} ,
{
" range " : {
" start " : {
" line " : 3 ,
" character " : 22
} ,
" end " : {
" line " : 3 ,
" character " : 24
}
} ,
" newText " : " '); "
} ,
{
" range " : {
" start " : {
" line " : 4 ,
" character " : 1
} ,
" end " : {
" line " : 4 ,
" character " : 1
}
} ,
" newText " : " \n "
} ]
) )
) ;
shutdown ( & mut client ) ;
}
2021-06-02 06:29:58 -04:00
#[ test ]
fn lsp_markdown_no_diagnostics ( ) {
let mut client = init ( " initialize_params.json " ) ;
client
. write_notification (
" textDocument/didOpen " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.md " ,
" languageId " : " markdown " ,
" version " : 1 ,
" text " : " # Hello World "
}
} ) ,
)
. unwrap ( ) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/semanticTokens/full " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.md "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! ( maybe_res , Some ( json! ( null ) ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.md "
} ,
" position " : {
" line " : 0 ,
" character " : 3
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! ( maybe_res , Some ( json! ( null ) ) ) ;
shutdown ( & mut client ) ;
}
2021-06-01 05:24:36 -04:00
#[ test ]
fn lsp_configuration_did_change ( ) {
let _g = http_server ( ) ;
let mut client = init ( " initialize_params_did_config_change.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " import * as a from \" http://localhost:4545/x/a@ \" "
}
} ) ,
) ;
client
. write_notification (
" workspace/didChangeConfiguration " ,
json! ( {
" settings " : { }
} ) ,
)
. unwrap ( ) ;
let ( id , method , _ ) = client . read_request ::< Value > ( ) . unwrap ( ) ;
assert_eq! ( method , " workspace/configuration " ) ;
client
. write_response (
id ,
json! ( [ {
" enable " : true ,
" codeLens " : {
" implementations " : true ,
" references " : true
} ,
" importMap " : null ,
" lint " : true ,
" suggest " : {
" autoImports " : true ,
" completeFunctionCalls " : false ,
" names " : true ,
" paths " : true ,
" imports " : {
" hosts " : {
" http://localhost:4545/ " : true
}
}
} ,
" unstable " : false
} ] ) ,
)
. unwrap ( ) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/completion " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts "
} ,
" position " : {
" line " : 0 ,
" character " : 46
} ,
" context " : {
" triggerKind " : 2 ,
" triggerCharacter " : " @ "
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
if let Some ( lsp ::CompletionResponse ::List ( list ) ) = maybe_res {
assert! ( ! list . is_incomplete ) ;
assert_eq! ( list . items . len ( ) , 3 ) ;
} else {
panic! ( " unexpected response " ) ;
}
let ( maybe_res , maybe_err ) = client
. write_request (
" completionItem/resolve " ,
load_fixture ( " completion_resolve_params_registry.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " completion_resolve_response_registry.json " ) )
) ;
shutdown ( & mut client ) ;
}
2021-06-21 02:43:35 -04:00
2021-11-22 19:08:56 -05:00
#[ test ]
fn lsp_workspace_symbol ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " export class A { \n fieldA: string; \n fieldB: string; \n } \n " ,
}
} ) ,
) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file_01.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " export class B { \n fieldC: string; \n fieldD: string; \n } \n " ,
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" workspace/symbol " ,
json! ( {
" query " : " field "
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( [
{
" name " : " fieldA " ,
" kind " : 8 ,
" location " : {
" uri " : " file:///a/file.ts " ,
" range " : {
" 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
}
}
} ,
" containerName " : " A "
} ,
{
" name " : " fieldC " ,
" kind " : 8 ,
" location " : {
" uri " : " file:///a/file_01.ts " ,
" range " : {
" 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
}
}
} ,
" containerName " : " B "
}
] ) )
) ;
shutdown ( & mut client ) ;
}
2021-06-21 02:43:35 -04:00
#[ test ]
fn lsp_code_actions_ignore_lint ( ) {
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " let message = 'Hello, Deno!'; \n console.log(message); \n "
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/codeAction " ,
load_fixture ( " code_action_ignore_lint_params.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_action_ignore_lint_response.json " ) )
) ;
shutdown ( & mut client ) ;
}
2021-09-14 08:16:51 -04:00
/// 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 " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.ts " ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " :
" #!/usr/bin/env -S deno run
// deno-lint-ignore-file camelcase
let snake_case = ' Hello , Deno ! ' ;
console . log ( snake_case ) ;
" ,
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request (
" textDocument/codeAction " ,
load_fixture ( " code_action_update_ignore_lint_params.json " ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( load_fixture ( " code_action_update_ignore_lint_response.json " ) )
) ;
shutdown ( & mut client ) ;
}
2021-10-11 18:02:33 -04:00
#[ test ]
fn lsp_lint_with_config ( ) {
let temp_dir = TempDir ::new ( ) . expect ( " could not create temp dir " ) ;
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 deno_exe = deno_exe_path ( ) ;
let mut client = LspClient ::new ( & deno_exe ) . unwrap ( ) ;
client
. write_request ::< _ , _ , Value > ( " initialize " , params )
. unwrap ( ) ;
2022-01-24 18:04:24 -05:00
let mut session = TestSession ::from_client ( client ) ;
2021-10-11 18:02:33 -04:00
2022-01-24 18:04:24 -05:00
let diagnostics = session . did_open ( load_fixture ( " did_open_lint.json " ) ) ;
let diagnostics = diagnostics . viewed ( ) ;
2022-01-24 15:30:01 -05:00
assert_eq! ( diagnostics . len ( ) , 1 ) ;
assert_eq! (
diagnostics [ 0 ] . code ,
Some ( lsp ::NumberOrString ::String ( " ban-untagged-todo " . to_string ( ) ) )
) ;
2022-01-24 18:04:24 -05:00
session . shutdown_and_exit ( ) ;
2021-10-11 18:02:33 -04:00
}
2021-11-08 20:26:39 -05:00
2021-11-24 15:14:19 -05:00
#[ test ]
fn lsp_lint_exclude_with_config ( ) {
let temp_dir = TempDir ::new ( ) . unwrap ( ) ;
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 ( ) ;
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 deno_exe = deno_exe_path ( ) ;
let mut client = LspClient ::new ( & deno_exe ) . unwrap ( ) ;
client
. write_request ::< _ , _ , Value > ( " initialize " , params )
. unwrap ( ) ;
let diagnostics = did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : ModuleSpecifier ::from_file_path ( temp_dir . path ( ) . join ( " ignored.ts " ) ) . unwrap ( ) . to_string ( ) ,
" languageId " : " typescript " ,
" version " : 1 ,
" text " : " // TODO: fixme \n export async function non_camel_case() { \n console.log( \" finished! \" ) \n } "
}
} ) ,
) ;
let diagnostics = diagnostics
. into_iter ( )
. flat_map ( | x | x . diagnostics )
. collect ::< Vec < _ > > ( ) ;
assert_eq! ( diagnostics , Vec ::new ( ) ) ;
shutdown ( & mut client ) ;
}
2021-11-08 20:26:39 -05:00
#[ test ]
fn lsp_jsx_import_source_pragma ( ) {
let _g = http_server ( ) ;
let mut client = init ( " initialize_params.json " ) ;
did_open (
& mut client ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.tsx " ,
" languageId " : " typescriptreact " ,
" version " : 1 ,
" text " :
" /** @jsxImportSource http://localhost:4545/jsx */
function A ( ) {
return \ " hello \" ;
}
export function B ( ) {
return < A > < / A > ;
}
" ,
}
} ) ,
) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" deno/cache " ,
json! ( {
" referrer " : {
" uri " : " file:///a/file.tsx " ,
} ,
" uris " : [
{
" uri " : " http://127.0.0.1:4545/jsx/jsx-runtime " ,
}
] ,
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert! ( maybe_res . is_some ( ) ) ;
let ( maybe_res , maybe_err ) = client
. write_request ::< _ , _ , Value > (
" textDocument/hover " ,
json! ( {
" textDocument " : {
" uri " : " file:///a/file.tsx "
} ,
" position " : {
" line " : 0 ,
" character " : 25
}
} ) ,
)
. unwrap ( ) ;
assert! ( maybe_err . is_none ( ) ) ;
assert_eq! (
maybe_res ,
Some ( json! ( {
" contents " : {
" kind " : " markdown " ,
" value " : " **Resolved Dependency** \n \n **Code**: http​://localhost:4545/jsx/jsx-runtime \n " ,
} ,
" range " : {
" start " : {
" line " : 0 ,
" character " : 21
} ,
" end " : {
" line " : 0 ,
" character " : 46
}
}
} ) )
) ;
shutdown ( & mut client ) ;
}