diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index e45d6d52b4..e6a1614746 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -93,7 +93,7 @@ const FILE_EXTENSION_KIND_MODIFIERS: &[&str] = &[".d.ts", ".ts", ".tsx", ".js", ".jsx", ".json"]; type Request = ( - RequestMethod, + TscRequest, Arc, oneshot::Sender>, CancellationToken, @@ -149,7 +149,7 @@ pub struct TsServer { impl TsServer { pub fn new(performance: Arc, cache: Arc) -> Self { - let specifier_map = Arc::new(TscSpecifierMap::default()); + let specifier_map = Arc::new(TscSpecifierMap::new()); let specifier_map_ = specifier_map.clone(); let (tx, mut rx) = mpsc::unbounded_channel::(); let _join_handle = thread::spawn(move || { @@ -184,7 +184,13 @@ impl TsServer { specifiers: Vec, token: CancellationToken, ) -> Result>, AnyError> { - let req = RequestMethod::GetDiagnostics(specifiers); + let req = TscRequest { + method: "$getDiagnostics", + args: json!([specifiers + .into_iter() + .map(|s| self.specifier_map.denormalize(&s)) + .collect::>(),]), + }; let diagnostics_map_ = self.request_with_cancellation::>>(snapshot, req, token).await?; let mut diagnostics_map = HashMap::new(); for (mut specifier, mut diagnostics) in diagnostics_map_ { @@ -203,9 +209,10 @@ impl TsServer { specifier: ModuleSpecifier, position: u32, ) -> Result>, LspError> { - let req = RequestMethod::FindReferences { - specifier, - position, + let req = TscRequest { + method: "findReferences", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6230 + args: json!([self.specifier_map.denormalize(&specifier), position]), }; self .request::>>(snapshot, req) @@ -227,9 +234,12 @@ impl TsServer { snapshot: Arc, specifier: ModuleSpecifier, ) -> Result { - self - .request(snapshot, RequestMethod::GetNavigationTree(specifier)) - .await + let req = TscRequest { + method: "getNavigationTree", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6235 + args: json!([self.specifier_map.denormalize(&specifier)]), + }; + self.request(snapshot, req).await } pub async fn configure( @@ -237,22 +247,25 @@ impl TsServer { snapshot: Arc, tsconfig: TsConfig, ) -> Result { - self - .request(snapshot, RequestMethod::Configure(tsconfig)) - .await + let req = TscRequest { + method: "$configure", + args: json!([tsconfig]), + }; + self.request(snapshot, req).await } pub async fn get_supported_code_fixes( &self, snapshot: Arc, ) -> Result, LspError> { - self - .request(snapshot, RequestMethod::GetSupportedCodeFixes) - .await - .map_err(|err| { - log::error!("Unable to get fixable diagnostics: {}", err); - LspError::internal_error() - }) + let req = TscRequest { + method: "$getSupportedCodeFixes", + args: json!([]), + }; + self.request(snapshot, req).await.map_err(|err| { + log::error!("Unable to get fixable diagnostics: {}", err); + LspError::internal_error() + }) } pub async fn get_quick_info( @@ -261,7 +274,11 @@ impl TsServer { specifier: ModuleSpecifier, position: u32, ) -> Result, LspError> { - let req = RequestMethod::GetQuickInfo((specifier, position)); + let req = TscRequest { + method: "getQuickInfoAtPosition", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6214 + args: json!([self.specifier_map.denormalize(&specifier), position]), + }; self.request(snapshot, req).await.map_err(|err| { log::error!("Unable to get quick info: {}", err); LspError::internal_error() @@ -277,14 +294,21 @@ impl TsServer { format_code_settings: FormatCodeSettings, preferences: UserPreferences, ) -> Vec { - let req = RequestMethod::GetCodeFixes(( - specifier, - range.start, - range.end, - codes, - format_code_settings, - preferences, - )); + let mut format_code_settings = json!(format_code_settings); + let format_object = format_code_settings.as_object_mut().unwrap(); + format_object.insert("indentStyle".to_string(), json!(1)); + let req = TscRequest { + method: "getCodeFixesAtPosition", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6257 + args: json!([ + self.specifier_map.denormalize(&specifier), + range.start, + range.end, + codes, + format_code_settings, + preferences, + ]), + }; let result = self .request::>(snapshot, req) .await @@ -315,15 +339,17 @@ impl TsServer { preferences: Option, only: String, ) -> Result, LspError> { - let req = RequestMethod::GetApplicableRefactors(( - specifier.clone(), - TextSpan { - start: range.start, - length: range.end - range.start, - }, - preferences, - only, - )); + let req = TscRequest { + method: "getApplicableRefactors", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6274 + args: json!([ + self.specifier_map.denormalize(&specifier), + { "pos": range.start, "end": range.end }, + preferences.unwrap_or_default(), + json!(null), + only, + ]), + }; self.request(snapshot, req).await.map_err(|err| { log::error!("Failed to request to tsserver {}", err); LspError::invalid_request() @@ -337,12 +363,22 @@ impl TsServer { format_code_settings: FormatCodeSettings, preferences: UserPreferences, ) -> Result { - let req = RequestMethod::GetCombinedCodeFix(( - code_action_data.specifier.clone(), - json!(code_action_data.fix_id.clone()), - format_code_settings, - preferences, - )); + let mut format_code_settings = json!(format_code_settings); + let format_object = format_code_settings.as_object_mut().unwrap(); + format_object.insert("indentStyle".to_string(), json!(1)); + let req = TscRequest { + method: "getCombinedCodeFix", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6258 + args: json!([ + { + "type": "file", + "fileName": self.specifier_map.denormalize(&code_action_data.specifier), + }, + &code_action_data.fix_id, + format_code_settings, + preferences, + ]), + }; self .request::(snapshot, req) .await @@ -367,17 +403,27 @@ impl TsServer { action_name: String, preferences: Option, ) -> Result { - let req = RequestMethod::GetEditsForRefactor(( - specifier, - format_code_settings, - TextSpan { - start: range.start, - length: range.end - range.start, - }, - refactor_name, - action_name, - preferences, - )); + let mut format_code_settings = json!(format_code_settings); + let format_object = format_code_settings.as_object_mut().unwrap(); + format_object.insert("indentStyle".to_string(), json!(2)); + format_object.insert( + "insertSpaceBeforeAndAfterBinaryOperators".to_string(), + json!(true), + ); + format_object + .insert("insertSpaceAfterCommaDelimiter".to_string(), json!(true)); + let req = TscRequest { + method: "getEditsForRefactor", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6275 + args: json!([ + self.specifier_map.denormalize(&specifier), + format_code_settings, + { "pos": range.start, "end": range.end }, + refactor_name, + action_name, + preferences, + ]), + }; self .request::(snapshot, req) .await @@ -399,12 +445,16 @@ impl TsServer { format_code_settings: FormatCodeSettings, user_preferences: UserPreferences, ) -> Result, LspError> { - let req = RequestMethod::GetEditsForFileRename(( - old_specifier, - new_specifier, - format_code_settings, - user_preferences, - )); + let req = TscRequest { + method: "getEditsForFileRename", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6281 + args: json!([ + self.specifier_map.denormalize(&old_specifier), + self.specifier_map.denormalize(&new_specifier), + format_code_settings, + user_preferences, + ]), + }; self .request::>(snapshot, req) .await @@ -427,11 +477,18 @@ impl TsServer { position: u32, files_to_search: Vec, ) -> Result>, LspError> { - let req = RequestMethod::GetDocumentHighlights(( - specifier, - position, - files_to_search, - )); + let req = TscRequest { + method: "getDocumentHighlights", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6231 + args: json!([ + self.specifier_map.denormalize(&specifier), + position, + files_to_search + .into_iter() + .map(|s| self.specifier_map.denormalize(&s)) + .collect::>(), + ]), + }; self.request(snapshot, req).await.map_err(|err| { log::error!("Unable to get document highlights from TypeScript: {}", err); LspError::internal_error() @@ -444,7 +501,11 @@ impl TsServer { specifier: ModuleSpecifier, position: u32, ) -> Result, LspError> { - let req = RequestMethod::GetDefinition((specifier, position)); + let req = TscRequest { + method: "getDefinitionAndBoundSpan", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6226 + args: json!([self.specifier_map.denormalize(&specifier), position]), + }; self .request::>(snapshot, req) .await @@ -466,9 +527,10 @@ impl TsServer { specifier: ModuleSpecifier, position: u32, ) -> Result>, LspError> { - let req = RequestMethod::GetTypeDefinition { - specifier, - position, + let req = TscRequest { + method: "getTypeDefinitionAtPosition", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6227 + args: json!([self.specifier_map.denormalize(&specifier), position]), }; self .request::>>(snapshot, req) @@ -493,12 +555,16 @@ impl TsServer { options: GetCompletionsAtPositionOptions, format_code_settings: FormatCodeSettings, ) -> Option { - let req = RequestMethod::GetCompletions(( - specifier, - position, - options, - format_code_settings, - )); + let req = TscRequest { + method: "getCompletionsAtPosition", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6193 + args: json!([ + self.specifier_map.denormalize(&specifier), + position, + options, + format_code_settings, + ]), + }; match self.request(snapshot, req).await { Ok(maybe_info) => maybe_info, Err(err) => { @@ -513,7 +579,19 @@ impl TsServer { snapshot: Arc, args: GetCompletionDetailsArgs, ) -> Result, AnyError> { - let req = RequestMethod::GetCompletionDetails(args); + let req = TscRequest { + method: "getCompletionEntryDetails", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6205 + args: json!([ + self.specifier_map.denormalize(&args.specifier), + args.position, + args.name, + args.format_code_settings.unwrap_or_default(), + args.source, + args.preferences, + args.data, + ]), + }; self .request::>(snapshot, req) .await @@ -531,7 +609,11 @@ impl TsServer { specifier: ModuleSpecifier, position: u32, ) -> Result>, LspError> { - let req = RequestMethod::GetImplementation((specifier, position)); + let req = TscRequest { + method: "getImplementationAtPosition", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6228 + args: json!([self.specifier_map.denormalize(&specifier), position]), + }; self .request::>>(snapshot, req) .await @@ -552,7 +634,11 @@ impl TsServer { snapshot: Arc, specifier: ModuleSpecifier, ) -> Result, LspError> { - let req = RequestMethod::GetOutliningSpans(specifier); + let req = TscRequest { + method: "getOutliningSpans", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6240 + args: json!([self.specifier_map.denormalize(&specifier)]), + }; self.request(snapshot, req).await.map_err(|err| { log::error!("Failed to request to tsserver {}", err); LspError::invalid_request() @@ -565,8 +651,11 @@ impl TsServer { specifier: ModuleSpecifier, position: u32, ) -> Result, LspError> { - let req = - RequestMethod::ProvideCallHierarchyIncomingCalls((specifier, position)); + let req = TscRequest { + method: "provideCallHierarchyIncomingCalls", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6237 + args: json!([self.specifier_map.denormalize(&specifier), position]), + }; self .request::>(snapshot, req) .await @@ -588,8 +677,11 @@ impl TsServer { specifier: ModuleSpecifier, position: u32, ) -> Result, LspError> { - let req = - RequestMethod::ProvideCallHierarchyOutgoingCalls((specifier, position)); + let req = TscRequest { + method: "provideCallHierarchyOutgoingCalls", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6238 + args: json!([self.specifier_map.denormalize(&specifier), position]), + }; self .request::>(snapshot, req) .await @@ -611,7 +703,11 @@ impl TsServer { specifier: ModuleSpecifier, position: u32, ) -> Result>, LspError> { - let req = RequestMethod::PrepareCallHierarchy((specifier, position)); + let req = TscRequest { + method: "prepareCallHierarchy", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6236 + args: json!([self.specifier_map.denormalize(&specifier), position]), + }; self .request::>>(snapshot, req) .await @@ -641,12 +737,16 @@ impl TsServer { specifier: ModuleSpecifier, position: u32, ) -> Result>, LspError> { - let req = RequestMethod::FindRenameLocations { - specifier, - position, - find_in_strings: false, - find_in_comments: false, - provide_prefix_and_suffix_text_for_rename: false, + let req = TscRequest { + method: "findRenameLocations", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6221 + args: json!([ + self.specifier_map.denormalize(&specifier), + position, + false, + false, + false, + ]), }; self .request::>>(snapshot, req) @@ -669,8 +769,11 @@ impl TsServer { specifier: ModuleSpecifier, position: u32, ) -> Result { - let req = RequestMethod::GetSmartSelectionRange((specifier, position)); - + let req = TscRequest { + method: "getSmartSelectionRange", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6224 + args: json!([self.specifier_map.denormalize(&specifier), position]), + }; self.request(snapshot, req).await.map_err(|err| { log::error!("Failed to request to tsserver {}", err); LspError::invalid_request() @@ -683,13 +786,18 @@ impl TsServer { specifier: ModuleSpecifier, range: Range, ) -> Result { - let req = RequestMethod::GetEncodedSemanticClassifications(( - specifier, - TextSpan { - start: range.start, - length: range.end - range.start, - }, - )); + let req = TscRequest { + method: "getEncodedSemanticClassifications", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6183 + args: json!([ + self.specifier_map.denormalize(&specifier), + TextSpan { + start: range.start, + length: range.end - range.start, + }, + "2020", + ]), + }; self.request(snapshot, req).await.map_err(|err| { log::error!("Failed to request to tsserver {}", err); LspError::invalid_request() @@ -703,8 +811,15 @@ impl TsServer { position: u32, options: SignatureHelpItemsOptions, ) -> Result, LspError> { - let req = - RequestMethod::GetSignatureHelpItems((specifier, position, options)); + let req = TscRequest { + method: "getSignatureHelpItems", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6217 + args: json!([ + self.specifier_map.denormalize(&specifier), + position, + options, + ]), + }; self.request(snapshot, req).await.map_err(|err| { log::error!("Failed to request to tsserver: {}", err); LspError::invalid_request() @@ -716,7 +831,18 @@ impl TsServer { snapshot: Arc, args: GetNavigateToItemsArgs, ) -> Result, LspError> { - let req = RequestMethod::GetNavigateToItems(args); + let req = TscRequest { + method: "getNavigateToItems", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6233 + args: json!([ + args.search, + args.max_result_count, + args.file.map(|f| match resolve_url(&f) { + Ok(s) => self.specifier_map.denormalize(&s), + Err(_) => f, + }), + ]), + }; self .request::>(snapshot, req) .await @@ -739,11 +865,15 @@ impl TsServer { text_span: TextSpan, user_preferences: UserPreferences, ) -> Result>, LspError> { - let req = RequestMethod::ProvideInlayHints(( - specifier, - text_span, - user_preferences, - )); + let req = TscRequest { + method: "provideInlayHints", + // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6239 + args: json!([ + self.specifier_map.denormalize(&specifier), + text_span, + user_preferences, + ]), + }; self.request(snapshot, req).await.map_err(|err| { log::error!("Unable to get inlay hints: {}", err); LspError::internal_error() @@ -751,16 +881,17 @@ impl TsServer { } pub async fn restart(&self, snapshot: Arc) { - let _: bool = self - .request(snapshot, RequestMethod::Restart) - .await - .unwrap(); + let req = TscRequest { + method: "$restart", + args: json!([]), + }; + self.request::(snapshot, req).await.unwrap(); } async fn request( &self, snapshot: Arc, - req: RequestMethod, + req: TscRequest, ) -> Result where R: de::DeserializeOwned, @@ -773,7 +904,7 @@ impl TsServer { async fn request_with_cancellation( &self, snapshot: Arc, - req: RequestMethod, + req: TscRequest, token: CancellationToken, ) -> Result where @@ -930,10 +1061,11 @@ async fn get_isolate_assets( ts_server: &TsServer, state_snapshot: Arc, ) -> Vec { - let res: Value = ts_server - .request(state_snapshot, RequestMethod::GetAssets) - .await - .unwrap(); + let req = TscRequest { + method: "$getAssets", + args: json!([]), + }; + let res: Value = ts_server.request(state_snapshot, req).await.unwrap(); let response_assets = match res { Value::Array(value) => value, _ => unreachable!(), @@ -1277,6 +1409,7 @@ pub struct SymbolDisplayPart { // This is only on `JSDocLinkDisplayPart` which extends `SymbolDisplayPart` // but is only used as an upcast of a `SymbolDisplayPart` and not explicitly // returned by any API, so it is safe to add it as an optional value. + #[serde(skip_serializing_if = "Option::is_none")] target: Option, } @@ -1442,7 +1575,7 @@ pub struct DocumentSpan { } impl DocumentSpan { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -1457,7 +1590,7 @@ impl DocumentSpan { line_index: Arc, language_server: &language_server::Inner, ) -> Option { - let target_specifier = normalize_specifier(&self.file_name).ok()?; + let target_specifier = resolve_url(&self.file_name).ok()?; let target_asset_or_doc = language_server.get_maybe_asset_or_document(&target_specifier)?; let target_line_index = target_asset_or_doc.line_index(); @@ -1502,7 +1635,7 @@ impl DocumentSpan { &self, language_server: &language_server::Inner, ) -> Option { - let specifier = normalize_specifier(&self.file_name).ok()?; + let specifier = resolve_url(&self.file_name).ok()?; let asset_or_doc = language_server.get_maybe_asset_or_document(&specifier)?; let line_index = asset_or_doc.line_index(); @@ -1549,7 +1682,7 @@ pub struct NavigateToItem { } impl NavigateToItem { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -1563,7 +1696,7 @@ impl NavigateToItem { &self, language_server: &language_server::Inner, ) -> Option { - let specifier = normalize_specifier(&self.file_name).ok()?; + let specifier = resolve_url(&self.file_name).ok()?; let asset_or_doc = language_server.get_asset_or_document(&specifier).ok()?; let line_index = asset_or_doc.line_index(); @@ -1810,7 +1943,7 @@ pub struct ImplementationLocation { } impl ImplementationLocation { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -1823,7 +1956,7 @@ impl ImplementationLocation { line_index: Arc, language_server: &language_server::Inner, ) -> lsp::Location { - let specifier = normalize_specifier(&self.document_span.file_name) + let specifier = resolve_url(&self.document_span.file_name) .unwrap_or_else(|_| ModuleSpecifier::parse("deno://invalid").unwrap()); let uri = language_server .url_map @@ -1857,7 +1990,7 @@ pub struct RenameLocation { } impl RenameLocation { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -1881,7 +2014,7 @@ impl RenameLocations { lsp::TextDocumentEdit, > = HashMap::new(); for location in self.locations.iter() { - let specifier = normalize_specifier(&location.document_span.file_name)?; + let specifier = resolve_url(&location.document_span.file_name)?; let uri = language_server.url_map.normalize_specifier(&specifier)?; let asset_or_doc = language_server.get_asset_or_document(&specifier)?; @@ -1955,7 +2088,7 @@ pub struct DefinitionInfo { } impl DefinitionInfo { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -1972,7 +2105,7 @@ pub struct DefinitionInfoAndBoundSpan { } impl DefinitionInfoAndBoundSpan { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -2068,7 +2201,7 @@ pub struct FileTextChanges { } impl FileTextChanges { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -2080,7 +2213,7 @@ impl FileTextChanges { &self, language_server: &language_server::Inner, ) -> Result { - let specifier = normalize_specifier(&self.file_name)?; + let specifier = resolve_url(&self.file_name)?; let asset_or_doc = language_server.get_asset_or_document(&specifier)?; let edits = self .text_changes @@ -2101,7 +2234,7 @@ impl FileTextChanges { language_server: &language_server::Inner, ) -> Result, AnyError> { let mut ops = Vec::::new(); - let specifier = normalize_specifier(&self.file_name)?; + let specifier = resolve_url(&self.file_name)?; let maybe_asset_or_document = if !self.is_new_file.unwrap_or(false) { let asset_or_doc = language_server.get_asset_or_document(&specifier)?; Some(asset_or_doc) @@ -2355,7 +2488,7 @@ pub struct RefactorEditInfo { } impl RefactorEditInfo { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -2383,7 +2516,7 @@ pub struct CodeAction { } impl CodeAction { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -2416,7 +2549,7 @@ pub struct CodeFixAction { } impl CodeFixAction { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -2435,7 +2568,7 @@ pub struct CombinedCodeActions { } impl CombinedCodeActions { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -2454,7 +2587,7 @@ pub struct ReferencedSymbol { } impl ReferencedSymbol { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -2474,7 +2607,7 @@ pub struct ReferencedSymbolDefinitionInfo { } impl ReferencedSymbolDefinitionInfo { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -2493,7 +2626,7 @@ pub struct ReferencedSymbolEntry { } impl ReferencedSymbolEntry { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -2512,7 +2645,7 @@ pub struct ReferenceEntry { } impl ReferenceEntry { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -2527,7 +2660,7 @@ impl ReferenceEntry { line_index: Arc, url_map: &LspUrlMap, ) -> lsp::Location { - let specifier = normalize_specifier(&self.document_span.file_name) + let specifier = resolve_url(&self.document_span.file_name) .unwrap_or_else(|_| INVALID_SPECIFIER.clone()); let uri = url_map .normalize_specifier(&specifier) @@ -2554,7 +2687,7 @@ pub struct CallHierarchyItem { } impl CallHierarchyItem { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -2567,7 +2700,7 @@ impl CallHierarchyItem { language_server: &language_server::Inner, maybe_root_path: Option<&Path>, ) -> Option { - let target_specifier = normalize_specifier(&self.file).ok()?; + let target_specifier = resolve_url(&self.file).ok()?; let target_asset_or_doc = language_server.get_maybe_asset_or_document(&target_specifier)?; @@ -2584,8 +2717,8 @@ impl CallHierarchyItem { language_server: &language_server::Inner, maybe_root_path: Option<&Path>, ) -> lsp::CallHierarchyItem { - let target_specifier = normalize_specifier(&self.file) - .unwrap_or_else(|_| INVALID_SPECIFIER.clone()); + let target_specifier = + resolve_url(&self.file).unwrap_or_else(|_| INVALID_SPECIFIER.clone()); let uri = language_server .url_map .normalize_specifier(&target_specifier) @@ -2661,7 +2794,7 @@ pub struct CallHierarchyIncomingCall { } impl CallHierarchyIncomingCall { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -2674,7 +2807,7 @@ impl CallHierarchyIncomingCall { language_server: &language_server::Inner, maybe_root_path: Option<&Path>, ) -> Option { - let target_specifier = normalize_specifier(&self.from.file).ok()?; + let target_specifier = resolve_url(&self.from.file).ok()?; let target_asset_or_doc = language_server.get_maybe_asset_or_document(&target_specifier)?; @@ -2701,7 +2834,7 @@ pub struct CallHierarchyOutgoingCall { } impl CallHierarchyOutgoingCall { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -2715,7 +2848,7 @@ impl CallHierarchyOutgoingCall { language_server: &language_server::Inner, maybe_root_path: Option<&Path>, ) -> Option { - let target_specifier = normalize_specifier(&self.to.file).ok()?; + let target_specifier = resolve_url(&self.to.file).ok()?; let target_asset_or_doc = language_server.get_maybe_asset_or_document(&target_specifier)?; @@ -2753,8 +2886,7 @@ fn parse_code_actions( let asset_or_doc = language_server.get_asset_or_document(&data.specifier)?; for change in &ts_action.changes { - let change_specifier = normalize_specifier(&change.file_name)?; - if data.specifier == change_specifier { + if data.specifier.as_str() == change.file_name { additional_text_edits.extend(change.text_changes.iter().map(|tc| { let mut text_edit = tc.as_text_edit(asset_or_doc.line_index()); if let Some(specifier_rewrite) = &data.specifier_rewrite { @@ -2779,9 +2911,7 @@ fn parse_code_actions( .changes .clone() .into_iter() - .filter(|ch| { - normalize_specifier(&ch.file_name).unwrap() == data.specifier - }) + .filter(|ch| ch.file_name == data.specifier.as_str()) .collect(); json!({ "commands": ca.commands, @@ -2855,16 +2985,19 @@ fn get_parameters_from_parts(parts: &[SymbolDisplayPart]) -> Vec { pub struct CompletionEntryDetails { display_parts: Vec, documentation: Option>, + #[serde(skip_serializing_if = "Option::is_none")] tags: Option>, name: String, kind: ScriptElementKind, kind_modifiers: String, + #[serde(skip_serializing_if = "Option::is_none")] code_actions: Option>, + #[serde(skip_serializing_if = "Option::is_none")] source_display: Option>, } impl CompletionEntryDetails { - pub fn normalize( + fn normalize( &mut self, specifier_map: &TscSpecifierMap, ) -> Result<(), AnyError> { @@ -3211,9 +3344,7 @@ impl CompletionEntry { if let Ok(import_data) = serde_json::from_value::(data.clone()) { - if let Ok(import_specifier) = - normalize_specifier(import_data.file_name) - { + if let Ok(import_specifier) = resolve_url(&import_data.file_name) { if let Some(new_module_specifier) = language_server .get_ts_response_import_mapper() .check_specifier(&import_specifier, specifier) @@ -3521,6 +3652,10 @@ pub struct TscSpecifierMap { } impl TscSpecifierMap { + pub fn new() -> Self { + Self::default() + } + /// Convert the specifier to one compatible with tsc. Cache the resulting /// mapping in case it needs to be reversed. // TODO(nayeemrmn): Factor in out-of-band media type here. @@ -3632,13 +3767,6 @@ impl State { } } -fn normalize_specifier>( - specifier: S, -) -> Result { - resolve_url(specifier.as_ref().replace(".d.ts.d.ts", ".d.ts").as_str()) - .map_err(|err| err.into()) -} - #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] struct SpecifierArgs { @@ -4214,404 +4342,20 @@ pub struct GetNavigateToItemsArgs { pub file: Option, } -/// Methods that are supported by the Language Service in the compiler isolate. -#[derive(Debug)] -enum RequestMethod { - /// Configure the compilation settings for the server. - Configure(TsConfig), - /// Get rename locations at a given position. - FindRenameLocations { - specifier: ModuleSpecifier, - position: u32, - find_in_strings: bool, - find_in_comments: bool, - provide_prefix_and_suffix_text_for_rename: bool, - }, - GetAssets, - /// Retrieve the possible refactor info for a range of a file. - GetApplicableRefactors( - (ModuleSpecifier, TextSpan, Option, String), - ), - /// Retrieve the refactor edit info for a range. - GetEditsForRefactor( - ( - ModuleSpecifier, - FormatCodeSettings, - TextSpan, - String, - String, - Option, - ), - ), - /// Retrieve the refactor edit info for a range. - GetEditsForFileRename( - ( - ModuleSpecifier, - ModuleSpecifier, - FormatCodeSettings, - UserPreferences, - ), - ), - /// Retrieve code fixes for a range of a file with the provided error codes. - GetCodeFixes( - ( - ModuleSpecifier, - u32, - u32, - Vec, - FormatCodeSettings, - UserPreferences, - ), - ), - /// Get completion information at a given position (IntelliSense). - GetCompletions( - ( - ModuleSpecifier, - u32, - GetCompletionsAtPositionOptions, - FormatCodeSettings, - ), - ), - /// Get details about a specific completion entry. - GetCompletionDetails(GetCompletionDetailsArgs), - /// Retrieve the combined code fixes for a fix id for a module. - GetCombinedCodeFix( - (ModuleSpecifier, Value, FormatCodeSettings, UserPreferences), - ), - /// Get declaration information for a specific position. - GetDefinition((ModuleSpecifier, u32)), - /// Return diagnostics for given file. - GetDiagnostics(Vec), - /// Return document highlights at position. - GetDocumentHighlights((ModuleSpecifier, u32, Vec)), - /// Get semantic highlights information for a particular file. - GetEncodedSemanticClassifications((ModuleSpecifier, TextSpan)), - /// Get implementation information for a specific position. - GetImplementation((ModuleSpecifier, u32)), - /// Get "navigate to" items, which are converted to workspace symbols - GetNavigateToItems(GetNavigateToItemsArgs), - /// Get a "navigation tree" for a specifier. - GetNavigationTree(ModuleSpecifier), - /// Get outlining spans for a specifier. - GetOutliningSpans(ModuleSpecifier), - /// Return quick info at position (hover information). - GetQuickInfo((ModuleSpecifier, u32)), - /// Finds the document references for a specific position. - FindReferences { - specifier: ModuleSpecifier, - position: u32, - }, - /// Get signature help items for a specific position. - GetSignatureHelpItems((ModuleSpecifier, u32, SignatureHelpItemsOptions)), - /// Get a selection range for a specific position. - GetSmartSelectionRange((ModuleSpecifier, u32)), - /// Get the diagnostic codes that support some form of code fix. - GetSupportedCodeFixes, - /// Get the type definition information for a specific position. - GetTypeDefinition { - specifier: ModuleSpecifier, - position: u32, - }, - /// Resolve a call hierarchy item for a specific position. - PrepareCallHierarchy((ModuleSpecifier, u32)), - /// Resolve incoming call hierarchy items for a specific position. - ProvideCallHierarchyIncomingCalls((ModuleSpecifier, u32)), - /// Resolve outgoing call hierarchy items for a specific position. - ProvideCallHierarchyOutgoingCalls((ModuleSpecifier, u32)), - /// Resolve inlay hints for a specific text span - ProvideInlayHints((ModuleSpecifier, TextSpan, UserPreferences)), - - // Special request, used only internally by the LSP - Restart, -} - -impl RequestMethod { - fn to_value(&self, state: &mut State, id: usize) -> Value { - match self { - RequestMethod::Configure(config) => json!({ - "id": id, - "method": "configure", - "compilerOptions": config, - }), - RequestMethod::FindRenameLocations { - specifier, - position, - find_in_strings, - find_in_comments, - provide_prefix_and_suffix_text_for_rename, - } => { - json!({ - "id": id, - "method": "findRenameLocations", - "specifier": state.specifier_map.denormalize(specifier), - "position": position, - "findInStrings": find_in_strings, - "findInComments": find_in_comments, - "providePrefixAndSuffixTextForRename": provide_prefix_and_suffix_text_for_rename - }) - } - RequestMethod::GetAssets => json!({ - "id": id, - "method": "getAssets", - }), - RequestMethod::GetApplicableRefactors(( - specifier, - span, - preferences, - kind, - )) => json!({ - "id": id, - "method": "getApplicableRefactors", - "specifier": state.specifier_map.denormalize(specifier), - "range": { "pos": span.start, "end": span.start + span.length }, - "preferences": preferences, - "kind": kind, - }), - RequestMethod::GetEditsForRefactor(( - specifier, - format_code_settings, - span, - refactor_name, - action_name, - preferences, - )) => json!({ - "id": id, - "method": "getEditsForRefactor", - "specifier": state.specifier_map.denormalize(specifier), - "formatCodeSettings": format_code_settings, - "range": { "pos": span.start, "end": span.start + span.length}, - "refactorName": refactor_name, - "actionName": action_name, - "preferences": preferences, - }), - RequestMethod::GetEditsForFileRename(( - old_specifier, - new_specifier, - format_code_settings, - preferences, - )) => json!({ - "id": id, - "method": "getEditsForFileRename", - "oldSpecifier": state.specifier_map.denormalize(old_specifier), - "newSpecifier": state.specifier_map.denormalize(new_specifier), - "formatCodeSettings": format_code_settings, - "preferences": preferences, - }), - RequestMethod::GetCodeFixes(( - specifier, - start_pos, - end_pos, - error_codes, - format_code_settings, - preferences, - )) => json!({ - "id": id, - "method": "getCodeFixes", - "specifier": state.specifier_map.denormalize(specifier), - "startPosition": start_pos, - "endPosition": end_pos, - "errorCodes": error_codes, - "formatCodeSettings": format_code_settings, - "preferences": preferences, - }), - RequestMethod::GetCombinedCodeFix(( - specifier, - fix_id, - format_code_settings, - preferences, - )) => json!({ - "id": id, - "method": "getCombinedCodeFix", - "specifier": state.specifier_map.denormalize(specifier), - "fixId": fix_id, - "formatCodeSettings": format_code_settings, - "preferences": preferences, - }), - RequestMethod::GetCompletionDetails(args) => { - let mut args = json!(args); - let specifier = - args.as_object_mut().unwrap().get_mut("specifier").unwrap(); - if let Ok(s) = ModuleSpecifier::parse(specifier.as_str().unwrap()) { - *specifier = json!(state.specifier_map.denormalize(&s)); - } - json!({ - "id": id, - "method": "getCompletionDetails", - "args": args - }) - } - RequestMethod::GetCompletions(( - specifier, - position, - preferences, - format_code_settings, - )) => { - json!({ - "id": id, - "method": "getCompletions", - "specifier": state.specifier_map.denormalize(specifier), - "position": position, - "preferences": preferences, - "formatCodeSettings": format_code_settings, - }) - } - RequestMethod::GetDefinition((specifier, position)) => json!({ - "id": id, - "method": "getDefinition", - "specifier": state.specifier_map.denormalize(specifier), - "position": position, - }), - RequestMethod::GetDiagnostics(specifiers) => json!({ - "id": id, - "method": "getDiagnostics", - "specifiers": specifiers.iter().map(|s| state.specifier_map.denormalize(s)).collect::>(), - }), - RequestMethod::GetDocumentHighlights(( - specifier, - position, - files_to_search, - )) => json!({ - "id": id, - "method": "getDocumentHighlights", - "specifier": state.specifier_map.denormalize(specifier), - "position": position, - "filesToSearch": files_to_search.iter().map(|s| state.specifier_map.denormalize(s)).collect::>(), - }), - RequestMethod::GetEncodedSemanticClassifications((specifier, span)) => { - json!({ - "id": id, - "method": "getEncodedSemanticClassifications", - "specifier": state.specifier_map.denormalize(specifier), - "span": span, - }) - } - RequestMethod::GetImplementation((specifier, position)) => json!({ - "id": id, - "method": "getImplementation", - "specifier": state.specifier_map.denormalize(specifier), - "position": position, - }), - RequestMethod::GetNavigateToItems(GetNavigateToItemsArgs { - search, - max_result_count, - file, - }) => json!({ - "id": id, - "method": "getNavigateToItems", - "search": search, - "maxResultCount": max_result_count, - "file": file, - }), - RequestMethod::GetNavigationTree(specifier) => json!({ - "id": id, - "method": "getNavigationTree", - "specifier": state.specifier_map.denormalize(specifier), - }), - RequestMethod::GetOutliningSpans(specifier) => json!({ - "id": id, - "method": "getOutliningSpans", - "specifier": state.specifier_map.denormalize(specifier), - }), - RequestMethod::GetQuickInfo((specifier, position)) => json!({ - "id": id, - "method": "getQuickInfo", - "specifier": state.specifier_map.denormalize(specifier), - "position": position, - }), - RequestMethod::FindReferences { - specifier, - position, - } => json!({ - "id": id, - "method": "findReferences", - "specifier": state.specifier_map.denormalize(specifier), - "position": position, - }), - RequestMethod::GetSignatureHelpItems((specifier, position, options)) => { - json!({ - "id": id, - "method": "getSignatureHelpItems", - "specifier": state.specifier_map.denormalize(specifier), - "position": position, - "options": options, - }) - } - RequestMethod::GetSmartSelectionRange((specifier, position)) => { - json!({ - "id": id, - "method": "getSmartSelectionRange", - "specifier": state.specifier_map.denormalize(specifier), - "position": position - }) - } - RequestMethod::GetSupportedCodeFixes => json!({ - "id": id, - "method": "getSupportedCodeFixes", - }), - RequestMethod::GetTypeDefinition { - specifier, - position, - } => json!({ - "id": id, - "method": "getTypeDefinition", - "specifier": state.specifier_map.denormalize(specifier), - "position": position - }), - RequestMethod::PrepareCallHierarchy((specifier, position)) => { - json!({ - "id": id, - "method": "prepareCallHierarchy", - "specifier": state.specifier_map.denormalize(specifier), - "position": position - }) - } - RequestMethod::ProvideCallHierarchyIncomingCalls(( - specifier, - position, - )) => { - json!({ - "id": id, - "method": "provideCallHierarchyIncomingCalls", - "specifier": state.specifier_map.denormalize(specifier), - "position": position - }) - } - RequestMethod::ProvideCallHierarchyOutgoingCalls(( - specifier, - position, - )) => { - json!({ - "id": id, - "method": "provideCallHierarchyOutgoingCalls", - "specifier": state.specifier_map.denormalize(specifier), - "position": position - }) - } - RequestMethod::ProvideInlayHints((specifier, span, preferences)) => { - json!({ - "id": id, - "method": "provideInlayHints", - "specifier": state.specifier_map.denormalize(specifier), - "span": span, - "preferences": preferences, - }) - } - RequestMethod::Restart => json!({ - "id": id, - "method": "restart", - }), - } - } +#[derive(Clone, Debug)] +struct TscRequest { + method: &'static str, + args: Value, } /// Send a request into a runtime and return the JSON value of the response. fn request( runtime: &mut JsRuntime, state_snapshot: Arc, - method: RequestMethod, + request: TscRequest, token: CancellationToken, ) -> Result { - let (performance, request_params) = { + let (performance, id) = { let op_state = runtime.op_state(); let mut op_state = op_state.borrow_mut(); let state = op_state.borrow_mut::(); @@ -4619,10 +4363,18 @@ fn request( state.token = token; state.last_id += 1; let id = state.last_id; - (state.performance.clone(), method.to_value(state, id)) + (state.performance.clone(), id) }; - let mark = performance.mark("request", Some(request_params.clone())); - let request_src = format!("globalThis.serverRequest({request_params});"); + let mark = + performance.mark("request", Some((request.method, request.args.clone()))); + assert!( + request.args.is_array(), + "Internal error: expected args to be array" + ); + let request_src = format!( + "globalThis.serverRequest({id}, \"{}\", {});", + request.method, &request.args + ); runtime.execute_script(located_script_name!(), request_src.into())?; let op_state = runtime.op_state(); @@ -4653,10 +4405,8 @@ mod tests { use crate::lsp::documents::Documents; use crate::lsp::documents::LanguageId; use crate::lsp::text::LineIndex; - use crate::tsc::AssetText; use pretty_assertions::assert_eq; use std::path::Path; - use std::path::PathBuf; use test_util::TempDir; fn mock_state_snapshot( @@ -4688,30 +4438,23 @@ mod tests { } } - fn setup( + async fn setup( temp_dir: &TempDir, - debug: bool, config: Value, sources: &[(&str, &str, i32, LanguageId)], - ) -> (JsRuntime, Arc, PathBuf) { + ) -> (TsServer, Arc, Arc) { let location = temp_dir.path().join("deps").to_path_buf(); let cache = Arc::new(GlobalHttpCache::new(location.clone(), RealDenoCacheEnv)); - let state_snapshot = Arc::new(mock_state_snapshot(sources, &location)); - let mut runtime = js_runtime(Default::default(), cache, Default::default()); - start(&mut runtime, debug).unwrap(); + let snapshot = Arc::new(mock_state_snapshot(sources, &location)); + let performance = Arc::new(Performance::default()); + let ts_server = TsServer::new(performance, cache.clone()); let ts_config = TsConfig::new(config); - assert_eq!( - request( - &mut runtime, - state_snapshot.clone(), - RequestMethod::Configure(ts_config), - Default::default(), - ) - .expect("failed request"), - json!(true) - ); - (runtime, state_snapshot, location) + assert!(ts_server + .configure(snapshot.clone(), ts_config,) + .await + .unwrap()); + (ts_server, snapshot, cache) } #[test] @@ -4729,57 +4472,48 @@ mod tests { assert_eq!(actual, r"test [`a link`](http://deno.land/x/mod.ts) test"); } - #[test] - fn test_project_configure() { + #[tokio::test] + async fn test_project_configure() { let temp_dir = TempDir::new(); setup( &temp_dir, - false, json!({ "target": "esnext", "module": "esnext", "noEmit": true, }), &[], - ); + ) + .await; } - #[test] - fn test_project_reconfigure() { + #[tokio::test] + async fn test_project_reconfigure() { let temp_dir = TempDir::new(); - let (mut runtime, state_snapshot, _) = setup( + let (ts_server, snapshot, _) = setup( &temp_dir, - false, json!({ "target": "esnext", "module": "esnext", "noEmit": true, }), &[], - ); + ) + .await; let ts_config = TsConfig::new(json!({ "target": "esnext", "module": "esnext", "noEmit": true, "lib": ["deno.ns", "deno.worker"] })); - let result = request( - &mut runtime, - state_snapshot, - RequestMethod::Configure(ts_config), - Default::default(), - ); - assert!(result.is_ok()); - let response = result.unwrap(); - assert_eq!(response, json!(true)); + assert!(ts_server.configure(snapshot, ts_config).await.unwrap()); } - #[test] - fn test_get_diagnostics() { + #[tokio::test] + async fn test_get_diagnostics() { let temp_dir = TempDir::new(); - let (mut runtime, state_snapshot, _) = setup( + let (ts_server, snapshot, _) = setup( &temp_dir, - false, json!({ "target": "esnext", "module": "esnext", @@ -4791,18 +4525,15 @@ mod tests { 1, LanguageId::TypeScript, )], - ); + ) + .await; let specifier = resolve_url("file:///a.ts").expect("could not resolve url"); - let result = request( - &mut runtime, - state_snapshot, - RequestMethod::GetDiagnostics(vec![specifier]), - Default::default(), - ); - assert!(result.is_ok()); - let response = result.unwrap(); + let diagnostics = ts_server + .get_diagnostics(snapshot, vec![specifier], Default::default()) + .await + .unwrap(); assert_eq!( - response, + json!(diagnostics), json!({ "file:///a.ts": [ { @@ -4825,12 +4556,11 @@ mod tests { ); } - #[test] - fn test_get_diagnostics_lib() { + #[tokio::test] + async fn test_get_diagnostics_lib() { let temp_dir = TempDir::new(); - let (mut runtime, state_snapshot, _) = setup( + let (ts_server, snapshot, _) = setup( &temp_dir, - false, json!({ "target": "esnext", "module": "esnext", @@ -4844,25 +4574,21 @@ mod tests { 1, LanguageId::TypeScript, )], - ); + ) + .await; let specifier = resolve_url("file:///a.ts").expect("could not resolve url"); - let result = request( - &mut runtime, - state_snapshot, - RequestMethod::GetDiagnostics(vec![specifier]), - Default::default(), - ); - assert!(result.is_ok()); - let response = result.unwrap(); - assert_eq!(response, json!({ "file:///a.ts": [] })); + let diagnostics = ts_server + .get_diagnostics(snapshot, vec![specifier], Default::default()) + .await + .unwrap(); + assert_eq!(json!(diagnostics), json!({ "file:///a.ts": [] })); } - #[test] - fn test_module_resolution() { + #[tokio::test] + async fn test_module_resolution() { let temp_dir = TempDir::new(); - let (mut runtime, state_snapshot, _) = setup( + let (ts_server, snapshot, _) = setup( &temp_dir, - false, json!({ "target": "esnext", "module": "esnext", @@ -4881,25 +4607,21 @@ mod tests { 1, LanguageId::TypeScript, )], - ); + ) + .await; let specifier = resolve_url("file:///a.ts").expect("could not resolve url"); - let result = request( - &mut runtime, - state_snapshot, - RequestMethod::GetDiagnostics(vec![specifier]), - Default::default(), - ); - assert!(result.is_ok()); - let response = result.unwrap(); - assert_eq!(response, json!({ "file:///a.ts": [] })); + let diagnostics = ts_server + .get_diagnostics(snapshot, vec![specifier], Default::default()) + .await + .unwrap(); + assert_eq!(json!(diagnostics), json!({ "file:///a.ts": [] })); } - #[test] - fn test_bad_module_specifiers() { + #[tokio::test] + async fn test_bad_module_specifiers() { let temp_dir = TempDir::new(); - let (mut runtime, state_snapshot, _) = setup( + let (ts_server, snapshot, _) = setup( &temp_dir, - false, json!({ "target": "esnext", "module": "esnext", @@ -4914,18 +4636,15 @@ mod tests { 1, LanguageId::TypeScript, )], - ); + ) + .await; let specifier = resolve_url("file:///a.ts").expect("could not resolve url"); - let result = request( - &mut runtime, - state_snapshot, - RequestMethod::GetDiagnostics(vec![specifier]), - Default::default(), - ); - assert!(result.is_ok()); - let response = result.unwrap(); + let diagnostics = ts_server + .get_diagnostics(snapshot, vec![specifier], Default::default()) + .await + .unwrap(); assert_eq!( - response, + json!(diagnostics), json!({ "file:///a.ts": [{ "start": { @@ -4941,18 +4660,16 @@ mod tests { "sourceLine": " import { A } from \".\";", "category": 2, "code": 6133, - "reportsUnnecessary": true, }] }) ); } - #[test] - fn test_remote_modules() { + #[tokio::test] + async fn test_remote_modules() { let temp_dir = TempDir::new(); - let (mut runtime, state_snapshot, _) = setup( + let (ts_server, snapshot, _) = setup( &temp_dir, - false, json!({ "target": "esnext", "module": "esnext", @@ -4971,25 +4688,21 @@ mod tests { 1, LanguageId::TypeScript, )], - ); + ) + .await; let specifier = resolve_url("file:///a.ts").expect("could not resolve url"); - let result = request( - &mut runtime, - state_snapshot, - RequestMethod::GetDiagnostics(vec![specifier]), - Default::default(), - ); - assert!(result.is_ok()); - let response = result.unwrap(); - assert_eq!(response, json!({ "file:///a.ts": [] })); + let diagnostics = ts_server + .get_diagnostics(snapshot, vec![specifier], Default::default()) + .await + .unwrap(); + assert_eq!(json!(diagnostics), json!({ "file:///a.ts": [] })); } - #[test] - fn test_partial_modules() { + #[tokio::test] + async fn test_partial_modules() { let temp_dir = TempDir::new(); - let (mut runtime, state_snapshot, _) = setup( + let (ts_server, snapshot, _) = setup( &temp_dir, - false, json!({ "target": "esnext", "module": "esnext", @@ -5011,18 +4724,15 @@ mod tests { 1, LanguageId::TypeScript, )], - ); + ) + .await; let specifier = resolve_url("file:///a.ts").expect("could not resolve url"); - let result = request( - &mut runtime, - state_snapshot, - RequestMethod::GetDiagnostics(vec![specifier]), - Default::default(), - ); - assert!(result.is_ok()); - let response = result.unwrap(); + let diagnostics = ts_server + .get_diagnostics(snapshot, vec![specifier], Default::default()) + .await + .unwrap(); assert_eq!( - response, + json!(diagnostics), json!({ "file:///a.ts": [{ "start": { @@ -5038,7 +4748,6 @@ mod tests { "sourceLine": " import {", "category": 2, "code": 6192, - "reportsUnnecessary": true }, { "start": { "line": 8, @@ -5058,12 +4767,11 @@ mod tests { ); } - #[test] - fn test_no_debug_failure() { + #[tokio::test] + async fn test_no_debug_failure() { let temp_dir = TempDir::new(); - let (mut runtime, state_snapshot, _) = setup( + let (ts_server, snapshot, _) = setup( &temp_dir, - false, json!({ "target": "esnext", "module": "esnext", @@ -5076,18 +4784,15 @@ mod tests { 1, LanguageId::TypeScript, )], - ); + ) + .await; let specifier = resolve_url("file:///a.ts").expect("could not resolve url"); - let result = request( - &mut runtime, - state_snapshot, - RequestMethod::GetDiagnostics(vec![specifier]), - Default::default(), - ); - assert!(result.is_ok()); - let response = result.unwrap(); + let diagnostics = ts_server + .get_diagnostics(snapshot, vec![specifier], Default::default()) + .await + .unwrap(); assert_eq!( - response, + json!(diagnostics), json!({ "file:///a.ts": [ { @@ -5110,23 +4815,16 @@ mod tests { ); } - #[test] - fn test_request_assets() { + #[tokio::test] + async fn test_request_assets() { let temp_dir = TempDir::new(); - let (mut runtime, state_snapshot, _) = - setup(&temp_dir, false, json!({}), &[]); - let result = request( - &mut runtime, - state_snapshot, - RequestMethod::GetAssets, - Default::default(), - ) - .unwrap(); - let assets: Vec = serde_json::from_value(result).unwrap(); + let (ts_server, snapshot, _) = setup(&temp_dir, json!({}), &[]).await; + let assets = get_isolate_assets(&ts_server, snapshot).await; let mut asset_names = assets .iter() .map(|a| { - a.specifier + a.specifier() + .to_string() .replace("asset:///lib.", "") .replace(".d.ts", "") }) @@ -5135,29 +4833,25 @@ mod tests { include_str!(concat!(env!("OUT_DIR"), "/lib_file_names.json")), ) .unwrap(); - asset_names.sort(); - expected_asset_names.sort(); - // You might have found this assertion starts failing after upgrading TypeScript. - // Ensure build.rs is updated so these match. + expected_asset_names.sort(); assert_eq!(asset_names, expected_asset_names); // get some notification when the size of the assets grows let mut total_size = 0; for asset in assets { - total_size += asset.text.len(); + total_size += asset.text().len(); } assert!(total_size > 0); assert!(total_size < 2_000_000); // currently as of TS 4.6, it's 0.7MB } - #[test] - fn test_modify_sources() { + #[tokio::test] + async fn test_modify_sources() { let temp_dir = TempDir::new(); - let (mut runtime, state_snapshot, location) = setup( + let (ts_server, snapshot, cache) = setup( &temp_dir, - false, json!({ "target": "esnext", "module": "esnext", @@ -5175,8 +4869,8 @@ mod tests { 1, LanguageId::TypeScript, )], - ); - let cache = Arc::new(GlobalHttpCache::new(location, RealDenoCacheEnv)); + ) + .await; let specifier_dep = resolve_url("https://deno.land/x/example/a.ts").unwrap(); cache @@ -5187,16 +4881,12 @@ mod tests { ) .unwrap(); let specifier = resolve_url("file:///a.ts").unwrap(); - let result = request( - &mut runtime, - state_snapshot.clone(), - RequestMethod::GetDiagnostics(vec![specifier]), - Default::default(), - ); - assert!(result.is_ok()); - let response = result.unwrap(); + let diagnostics = ts_server + .get_diagnostics(snapshot.clone(), vec![specifier], Default::default()) + .await + .unwrap(); assert_eq!( - response, + json!(diagnostics), json!({ "file:///a.ts": [ { @@ -5225,16 +4915,12 @@ mod tests { ) .unwrap(); let specifier = resolve_url("file:///a.ts").unwrap(); - let result = request( - &mut runtime, - state_snapshot, - RequestMethod::GetDiagnostics(vec![specifier]), - Default::default(), - ); - assert!(result.is_ok()); - let response = result.unwrap(); + let diagnostics = ts_server + .get_diagnostics(snapshot.clone(), vec![specifier], Default::default()) + .await + .unwrap(); assert_eq!( - response, + json!(diagnostics), json!({ "file:///a.ts": [] }) @@ -5270,8 +4956,8 @@ mod tests { assert_eq!(actual, Some("abc".to_string())); } - #[test] - fn test_completions() { + #[tokio::test] + async fn test_completions() { let fixture = r#" import { B } from "https://deno.land/x/b/mod.ts"; @@ -5287,9 +4973,8 @@ mod tests { }) .unwrap(); let temp_dir = TempDir::new(); - let (mut runtime, state_snapshot, _) = setup( + let (ts_server, snapshot, _) = setup( &temp_dir, - false, json!({ "target": "esnext", "module": "esnext", @@ -5297,19 +4982,12 @@ mod tests { "noEmit": true, }), &[("file:///a.ts", fixture, 1, LanguageId::TypeScript)], - ); + ) + .await; let specifier = resolve_url("file:///a.ts").expect("could not resolve url"); - let result = request( - &mut runtime, - state_snapshot.clone(), - RequestMethod::GetDiagnostics(vec![specifier.clone()]), - Default::default(), - ); - assert!(result.is_ok()); - let result = request( - &mut runtime, - state_snapshot.clone(), - RequestMethod::GetCompletions(( + let info = ts_server + .get_completions( + snapshot.clone(), specifier.clone(), position, GetCompletionsAtPositionOptions { @@ -5321,31 +4999,28 @@ mod tests { trigger_kind: None, }, Default::default(), - )), - Default::default(), - ); - assert!(result.is_ok()); - let response: CompletionInfo = - serde_json::from_value(result.unwrap()).unwrap(); - assert_eq!(response.entries.len(), 22); - let result = request( - &mut runtime, - state_snapshot, - RequestMethod::GetCompletionDetails(GetCompletionDetailsArgs { - specifier, - position, - name: "log".to_string(), - source: None, - preferences: None, - format_code_settings: None, - data: None, - }), - Default::default(), - ); - assert!(result.is_ok()); - let response = result.unwrap(); + ) + .await + .unwrap(); + assert_eq!(info.entries.len(), 22); + let details = ts_server + .get_completion_details( + snapshot.clone(), + GetCompletionDetailsArgs { + specifier, + position, + name: "log".to_string(), + format_code_settings: None, + source: None, + preferences: None, + data: None, + }, + ) + .await + .unwrap() + .unwrap(); assert_eq!( - response, + json!(details), json!({ "name": "log", "kindModifiers": "declare", @@ -5433,8 +5108,8 @@ mod tests { ); } - #[test] - fn test_completions_fmt() { + #[tokio::test] + async fn test_completions_fmt() { let fixture_a = r#" console.log(someLongVaria) "#; @@ -5449,9 +5124,8 @@ mod tests { }) .unwrap(); let temp_dir = TempDir::new(); - let (mut runtime, state_snapshot, _) = setup( + let (ts_server, snapshot, _) = setup( &temp_dir, - false, json!({ "target": "esnext", "module": "esnext", @@ -5462,24 +5136,17 @@ mod tests { ("file:///a.ts", fixture_a, 1, LanguageId::TypeScript), ("file:///b.ts", fixture_b, 1, LanguageId::TypeScript), ], - ); + ) + .await; let specifier = resolve_url("file:///a.ts").expect("could not resolve url"); - let result = request( - &mut runtime, - state_snapshot.clone(), - RequestMethod::GetDiagnostics(vec![specifier.clone()]), - Default::default(), - ); - assert!(result.is_ok()); let fmt_options_config = FmtOptionsConfig { semi_colons: Some(false), single_quote: Some(true), ..Default::default() }; - let result = request( - &mut runtime, - state_snapshot.clone(), - RequestMethod::GetCompletions(( + let info = ts_server + .get_completions( + snapshot.clone(), specifier.clone(), position, GetCompletionsAtPositionOptions { @@ -5491,37 +5158,36 @@ mod tests { }, ..Default::default() }, - (&fmt_options_config).into(), - )), - Default::default(), - ) - .unwrap(); - let info: CompletionInfo = serde_json::from_value(result).unwrap(); + FormatCodeSettings::from(&fmt_options_config), + ) + .await + .unwrap(); let entry = info .entries .iter() .find(|e| &e.name == "someLongVariable") .unwrap(); - let result = request( - &mut runtime, - state_snapshot, - RequestMethod::GetCompletionDetails(GetCompletionDetailsArgs { - specifier, - position, - name: entry.name.clone(), - source: entry.source.clone(), - preferences: Some(UserPreferences { - quote_preference: Some((&fmt_options_config).into()), - ..Default::default() - }), - format_code_settings: Some((&fmt_options_config).into()), - data: entry.data.clone(), - }), - Default::default(), - ) - .unwrap(); - let details: CompletionEntryDetails = - serde_json::from_value(result).unwrap(); + let details = ts_server + .get_completion_details( + snapshot.clone(), + GetCompletionDetailsArgs { + specifier, + position, + name: entry.name.clone(), + format_code_settings: Some(FormatCodeSettings::from( + &fmt_options_config, + )), + source: entry.source.clone(), + preferences: Some(UserPreferences { + quote_preference: Some((&fmt_options_config).into()), + ..Default::default() + }), + data: entry.data.clone(), + }, + ) + .await + .unwrap() + .unwrap(); let actions = details.code_actions.unwrap(); let action = actions .iter() @@ -5535,12 +5201,11 @@ mod tests { ); } - #[test] - fn test_get_edits_for_file_rename() { + #[tokio::test] + async fn test_get_edits_for_file_rename() { let temp_dir = TempDir::new(); - let (mut runtime, state_snapshot, _) = setup( + let (ts_server, snapshot, _) = setup( &temp_dir, - false, json!({ "target": "esnext", "module": "esnext", @@ -5556,29 +5221,18 @@ mod tests { ), ("file:///b.ts", r#""#, 1, LanguageId::TypeScript), ], - ); - let specifier = resolve_url("file:///a.ts").expect("could not resolve url"); - let result = request( - &mut runtime, - state_snapshot.clone(), - RequestMethod::GetDiagnostics(vec![specifier.clone()]), - Default::default(), - ); - assert!(result.is_ok()); - let changes = request( - &mut runtime, - state_snapshot.clone(), - RequestMethod::GetEditsForFileRename(( + ) + .await; + let changes = ts_server + .get_edits_for_file_rename( + snapshot, resolve_url("file:///b.ts").unwrap(), resolve_url("file:///c.ts").unwrap(), - Default::default(), - Default::default(), - )), - Default::default(), - ) - .unwrap(); - let changes: Vec = - serde_json::from_value(changes).unwrap(); + FormatCodeSettings::default(), + UserPreferences::default(), + ) + .await + .unwrap(); assert_eq!( changes, vec![FileTextChanges { diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js index 8978bf1bef..e246d5d0c3 100644 --- a/cli/tsc/99_main_compiler.js +++ b/cli/tsc/99_main_compiler.js @@ -968,26 +968,23 @@ delete Object.prototype.__proto__; ops.op_respond({ id, data }); } - /** - * @param {LanguageServerRequest} request - */ - function serverRequest({ id, ...request }) { + function serverRequest(id, method, args) { if (logDebug) { - debug(`serverRequest()`, { id, ...request }); + debug(`serverRequest()`, id, method, args); } // reset all memoized source files names scriptFileNamesCache = undefined; // evict all memoized source file versions scriptVersionCache.clear(); - switch (request.method) { - case "restart": { + switch (method) { + case "$restart": { serverRestart(); return respond(id, true); } - case "configure": { + case "$configure": { const { options, errors } = ts - .convertCompilerOptionsFromJson(request.compilerOptions, ""); + .convertCompilerOptionsFromJson(args[0], ""); Object.assign(options, { allowNonTsExtensions: true, allowImportingTsExtensions: true, @@ -998,141 +995,20 @@ delete Object.prototype.__proto__; compilationSettings = options; return respond(id, true); } - case "findRenameLocations": { + case "$getSupportedCodeFixes": { return respond( id, - languageService.findRenameLocations( - request.specifier, - request.position, - request.findInStrings, - request.findInComments, - request.providePrefixAndSuffixTextForRename, - ), + ts.getSupportedCodeFixes(), ); } - case "getAssets": { + case "$getAssets": { return respond(id, getAssets()); } - case "getApplicableRefactors": { - return respond( - id, - languageService.getApplicableRefactors( - request.specifier, - request.range, - { - ...(request.preferences ?? {}), - allowTextChangesInNewFiles: true, - provideRefactorNotApplicableReason: true, - }, - undefined, - request.kind, - ), - ); - } - case "getEditsForRefactor": { - return respond( - id, - languageService.getEditsForRefactor( - request.specifier, - { - ...request.formatCodeSettings, - indentStyle: ts.IndentStyle.Smart, - insertSpaceBeforeAndAfterBinaryOperators: true, - insertSpaceAfterCommaDelimiter: true, - }, - request.range, - request.refactorName, - request.actionName, - request.preferences, - ), - ); - } - case "getEditsForFileRename": { - return respond( - id, - languageService.getEditsForFileRename( - request.oldSpecifier, - request.newSpecifier, - request.formatCodeSettings, - request.preferences, - ), - ); - } - case "getCodeFixes": { - return respond( - id, - languageService.getCodeFixesAtPosition( - request.specifier, - request.startPosition, - request.endPosition, - request.errorCodes.map((v) => Number(v)), - { - ...request.formatCodeSettings, - indentStyle: ts.IndentStyle.Block, - }, - request.preferences, - ), - ); - } - case "getCombinedCodeFix": { - return respond( - id, - languageService.getCombinedCodeFix( - { - type: "file", - fileName: request.specifier, - }, - request.fixId, - { - ...request.formatCodeSettings, - indentStyle: ts.IndentStyle.Block, - }, - request.preferences, - ), - ); - } - case "getCompletionDetails": { - if (logDebug) { - debug("request", request); - } - return respond( - id, - languageService.getCompletionEntryDetails( - request.args.specifier, - request.args.position, - request.args.name, - request.args.formatCodeSettings ?? {}, - request.args.source, - request.args.preferences, - request.args.data, - ), - ); - } - case "getCompletions": { - return respond( - id, - languageService.getCompletionsAtPosition( - request.specifier, - request.position, - request.preferences, - request.formatCodeSettings, - ), - ); - } - case "getDefinition": { - return respond( - id, - languageService.getDefinitionAndBoundSpan( - request.specifier, - request.position, - ), - ); - } - case "getDiagnostics": { + case "$getDiagnostics": { try { /** @type {Record} */ const diagnosticMap = {}; - for (const specifier of request.specifiers) { + for (const specifier of args[0]) { diagnosticMap[specifier] = fromTypeScriptDiagnostics([ ...languageService.getSemanticDiagnostics(specifier), ...languageService.getSuggestionDiagnostics(specifier), @@ -1154,151 +1030,18 @@ delete Object.prototype.__proto__; return respond(id, {}); } } - case "getDocumentHighlights": { - return respond( - id, - languageService.getDocumentHighlights( - request.specifier, - request.position, - request.filesToSearch, - ), - ); - } - case "getEncodedSemanticClassifications": { - return respond( - id, - languageService.getEncodedSemanticClassifications( - request.specifier, - request.span, - ts.SemanticClassificationFormat.TwentyTwenty, - ), - ); - } - case "getImplementation": { - return respond( - id, - languageService.getImplementationAtPosition( - request.specifier, - request.position, - ), - ); - } - case "getNavigateToItems": { - return respond( - id, - languageService.getNavigateToItems( - request.search, - request.maxResultCount, - request.fileName, - ), - ); - } - case "getNavigationTree": { - return respond( - id, - languageService.getNavigationTree(request.specifier), - ); - } - case "getOutliningSpans": { - return respond( - id, - languageService.getOutliningSpans( - request.specifier, - ), - ); - } - case "getQuickInfo": { - return respond( - id, - languageService.getQuickInfoAtPosition( - request.specifier, - request.position, - ), - ); - } - case "findReferences": { - return respond( - id, - languageService.findReferences( - request.specifier, - request.position, - ), - ); - } - case "getSignatureHelpItems": { - return respond( - id, - languageService.getSignatureHelpItems( - request.specifier, - request.position, - request.options, - ), - ); - } - case "getSmartSelectionRange": { - return respond( - id, - languageService.getSmartSelectionRange( - request.specifier, - request.position, - ), - ); - } - case "getSupportedCodeFixes": { - return respond( - id, - ts.getSupportedCodeFixes(), - ); - } - case "getTypeDefinition": { - return respond( - id, - languageService.getTypeDefinitionAtPosition( - request.specifier, - request.position, - ), - ); - } - case "prepareCallHierarchy": { - return respond( - id, - languageService.prepareCallHierarchy( - request.specifier, - request.position, - ), - ); - } - case "provideCallHierarchyIncomingCalls": { - return respond( - id, - languageService.provideCallHierarchyIncomingCalls( - request.specifier, - request.position, - ), - ); - } - case "provideCallHierarchyOutgoingCalls": { - return respond( - id, - languageService.provideCallHierarchyOutgoingCalls( - request.specifier, - request.position, - ), - ); - } - case "provideInlayHints": - return respond( - id, - languageService.provideInlayHints( - request.specifier, - request.span, - request.preferences, - ), - ); default: + if (typeof languageService[method] === "function") { + // The `getCompletionEntryDetails()` method returns null if the + // `source` is `null` for whatever reason. It must be `undefined`. + if (method == "getCompletionEntryDetails") { + args[4] ??= undefined; + } + return respond(id, languageService[method](...args)); + } throw new TypeError( // @ts-ignore exhausted case statement sets type to never - `Invalid request method for request: "${request.method}" (${id})`, + `Invalid request method for request: "${method}" (${id})`, ); } } diff --git a/cli/tsc/compiler.d.ts b/cli/tsc/compiler.d.ts index 30e4334050..73298a44b7 100644 --- a/cli/tsc/compiler.d.ts +++ b/cli/tsc/compiler.d.ts @@ -56,239 +56,4 @@ declare global { ...args: any[] ): void; } - - type LanguageServerRequest = - | Restart - | ConfigureRequest - | FindRenameLocationsRequest - | GetAssets - | GetApplicableRefactors - | GetEditsForRefactor - | GetEditsForFileRename - | GetCodeFixes - | GetCombinedCodeFix - | GetCompletionDetails - | GetCompletionsRequest - | GetDefinitionRequest - | GetDiagnosticsRequest - | GetDocumentHighlightsRequest - | GetEncodedSemanticClassifications - | GetImplementationRequest - | GetNavigateToItems - | GetNavigationTree - | GetOutliningSpans - | GetQuickInfoRequest - | FindReferencesRequest - | GetSignatureHelpItemsRequest - | GetSmartSelectionRange - | GetSupportedCodeFixes - | GetTypeDefinitionRequest - | PrepareCallHierarchy - | ProvideCallHierarchyIncomingCalls - | ProvideCallHierarchyOutgoingCalls - | ProvideInlayHints; - - interface BaseLanguageServerRequest { - id: number; - method: string; - } - - interface ConfigureRequest extends BaseLanguageServerRequest { - method: "configure"; - // deno-lint-ignore no-explicit-any - compilerOptions: Record; - } - - interface FindRenameLocationsRequest extends BaseLanguageServerRequest { - method: "findRenameLocations"; - specifier: string; - position: number; - findInStrings: boolean; - findInComments: boolean; - providePrefixAndSuffixTextForRename: boolean; - } - - interface GetAssets extends BaseLanguageServerRequest { - method: "getAssets"; - } - - interface GetApplicableRefactors extends BaseLanguageServerRequest { - method: "getApplicableRefactors"; - specifier: string; - range: ts.TextRange; - preferences?: ts.UserPreferences; - kind: string; - } - - interface GetEditsForRefactor extends BaseLanguageServerRequest { - method: "getEditsForRefactor"; - specifier: string; - formatCodeSettings: ts.FormatCodeSettings; - range: ts.TextRange; - refactorName: string; - actionName: string; - preferences?: ts.UserPreferences; - } - - interface GetEditsForFileRename extends BaseLanguageServerRequest { - method: "getEditsForFileRename"; - oldSpecifier: string; - newSpecifier: string; - formatCodeSettings: ts.FormatCodeSettings; - preferences?: ts.UserPreferences; - } - - interface GetCodeFixes extends BaseLanguageServerRequest { - method: "getCodeFixes"; - specifier: string; - startPosition: number; - endPosition: number; - errorCodes: string[]; - formatCodeSettings: ts.FormatCodeSettings; - preferences: ts.UserPreferences; - } - - interface GetCombinedCodeFix extends BaseLanguageServerRequest { - method: "getCombinedCodeFix"; - specifier: string; - // deno-lint-ignore ban-types - fixId: {}; - formatCodeSettings: ts.FormatCodeSettings; - preferences: ts.UserPreferences; - } - - interface GetCompletionDetails extends BaseLanguageServerRequest { - method: "getCompletionDetails"; - args: { - specifier: string; - position: number; - name: string; - formatCodeSettings: ts.FormatCodeSettings; - source?: string; - preferences?: ts.UserPreferences; - data?: ts.CompletionEntryData; - }; - } - - interface GetCompletionsRequest extends BaseLanguageServerRequest { - method: "getCompletions"; - specifier: string; - position: number; - preferences: ts.GetCompletionsAtPositionOptions; - formatCodeSettings: ts.FormatCodeSettings; - } - - interface GetDiagnosticsRequest extends BaseLanguageServerRequest { - method: "getDiagnostics"; - specifiers: string[]; - } - - interface GetDefinitionRequest extends BaseLanguageServerRequest { - method: "getDefinition"; - specifier: string; - position: number; - } - - interface GetDocumentHighlightsRequest extends BaseLanguageServerRequest { - method: "getDocumentHighlights"; - specifier: string; - position: number; - filesToSearch: string[]; - } - - interface GetEncodedSemanticClassifications - extends BaseLanguageServerRequest { - method: "getEncodedSemanticClassifications"; - specifier: string; - span: ts.TextSpan; - } - - interface GetImplementationRequest extends BaseLanguageServerRequest { - method: "getImplementation"; - specifier: string; - position: number; - } - - interface GetNavigateToItems extends BaseLanguageServerRequest { - method: "getNavigateToItems"; - search: string; - maxResultCount?: number; - fileName?: string; - } - - interface GetNavigationTree extends BaseLanguageServerRequest { - method: "getNavigationTree"; - specifier: string; - } - - interface GetOutliningSpans extends BaseLanguageServerRequest { - method: "getOutliningSpans"; - specifier: string; - } - - interface GetQuickInfoRequest extends BaseLanguageServerRequest { - method: "getQuickInfo"; - specifier: string; - position: number; - } - - interface FindReferencesRequest extends BaseLanguageServerRequest { - method: "findReferences"; - specifier: string; - position: number; - } - - interface GetSignatureHelpItemsRequest extends BaseLanguageServerRequest { - method: "getSignatureHelpItems"; - specifier: string; - position: number; - options: ts.SignatureHelpItemsOptions; - } - - interface GetSmartSelectionRange extends BaseLanguageServerRequest { - method: "getSmartSelectionRange"; - specifier: string; - position: number; - } - - interface GetSupportedCodeFixes extends BaseLanguageServerRequest { - method: "getSupportedCodeFixes"; - } - - interface GetTypeDefinitionRequest extends BaseLanguageServerRequest { - method: "getTypeDefinition"; - specifier: string; - position: number; - } - - interface PrepareCallHierarchy extends BaseLanguageServerRequest { - method: "prepareCallHierarchy"; - specifier: string; - position: number; - } - - interface ProvideCallHierarchyIncomingCalls - extends BaseLanguageServerRequest { - method: "provideCallHierarchyIncomingCalls"; - specifier: string; - position: number; - } - - interface ProvideCallHierarchyOutgoingCalls - extends BaseLanguageServerRequest { - method: "provideCallHierarchyOutgoingCalls"; - specifier: string; - position: number; - } - - interface ProvideInlayHints extends BaseLanguageServerRequest { - method: "provideInlayHints"; - specifier: string; - span: ts.TextSpan; - preferences?: ts.UserPreferences; - } - - interface Restart extends BaseLanguageServerRequest { - method: "restart"; - } } diff --git a/cli/tsc/diagnostics.rs b/cli/tsc/diagnostics.rs index 08fa3e8dab..2963379747 100644 --- a/cli/tsc/diagnostics.rs +++ b/cli/tsc/diagnostics.rs @@ -113,10 +113,13 @@ pub struct Diagnostic { pub start: Option, pub end: Option, pub message_text: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub message_chain: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub source: Option, pub source_line: Option, pub file_name: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub related_information: Option>, }