namespace ts . server { export interface SessionClientHost extends LanguageServiceHost { writeMessage ( message ) : void ; } interface RenameEntry { readonly renameInfo : RenameInfo ; readonly inputs : { readonly fileName : string ; readonly position : number ; readonly findInStrings : boolean ; readonly findInComments : boolean ; } ; readonly locations : RenameLocation [ ] ; } export function extractMessage ( message ) { const contentLengthPrefix = "Content-Length: " ; const lines = message . split ( /\r?\n/ ) ; Debug . assert ( lines . length >= 2 , "Malformed response: Expected 3 lines in the response." ) ; const contentLengthText = lines [ 0 ] ; Debug . assert ( contentLengthText . indexOf ( contentLengthPrefix ) === 0 , "Malformed response: Response text did not contain content-length header." ) ; const contentLength = parseInt ( contentLengthText . substring ( contentLengthPrefix . length ) ) ; const responseBody = lines [ 2 ] ; Debug . assert ( responseBody . length + 1 === contentLength , "Malformed response: Content length did not match the response's body length." ) ; return responseBody ; } export class SessionClient implements LanguageService { private sequence = 0 ; private lineMaps = new Map < string , number [ ] > ( ) ; private messages : string [ ] = [ ] ; private lastRenameEntry : RenameEntry | undefined ; constructor ( private host ) { } public onMessage ( message ) { this . messages . push ( message ) ; } private writeMessage ( message ) { this . host . writeMessage ( message ) ; } private getLineMap ( fileName ) { let lineMap = this . lineMaps . get ( fileName ) ; if ( ! lineMap ) { lineMap = computeLineStarts ( getSnapshotText ( this . host . getScriptSnapshot ( fileName ) ! ) ) ; this . lineMaps . set ( fileName , lineMap ) ; } return lineMap ; } private lineOffsetToPosition ( fileName , lineOffset , lineMap ? ) { lineMap = lineMap || this . getLineMap ( fileName ) ; return computePositionOfLineAndCharacter ( lineMap , lineOffset . line - 1 , lineOffset . offset - 1 ) ; } private positionToOneBasedLineOffset ( fileName , position ) { const lineOffset = computeLineAndCharacterOfPosition ( this . getLineMap ( fileName ) , position ) ; return { line : lineOffset . line + 1 , offset : lineOffset . character + 1 } ; } private convertCodeEditsToTextChange ( fileName , codeEdit ) { return { span : this . decodeSpan ( codeEdit , fileName ) , newText : codeEdit . newText } ; } private processRequest < T extends protocol . Request > ( command , args ) { const request = { seq : this . sequence , type : "request" , arguments : args , command } ; this . sequence ++ ; this . writeMessage ( JSON . stringify ( request ) ) ; return request as T ; } private processResponse < T extends protocol . Response > ( request , expectEmptyBody = false ) { let foundResponseMessage = false ; let response ! ; while ( ! foundResponseMessage ) { const lastMessage = this . messages . shift ( ) ! ; Debug . assert ( ! ! lastMessage , "Did not receive any responses." ) ; const responseBody = extractMessage ( lastMessage ) ; try { response = JSON . parse ( responseBody ) ; if ( response . type === "response" ) { foundResponseMessage = true ; } } catch ( e ) { throw new Error ( "Malformed response: Failed to parse server response: " + lastMessage + ". \r\n  Error details: " + e . message ) ; } } Debug . assert ( response . request_seq === request . seq , "Malformed response: response sequence number did not match request sequence number." ) ; if ( ! response . success ) { throw new Error ( "Error " + response . message ) ; } Debug . assert ( expectEmptyBody || ! ! response . body , "Malformed response: Unexpected empty response body." ) ; Debug . assert ( ! expectEmptyBody || ! response . body , "Malformed response: Unexpected non-empty response body." ) ; return response ; } configure ( preferences ) { const args = { preferences } ; const request = this . processRequest ( CommandNames . Configure , args ) ; this . processResponse ( request , true ) ; } setFormattingOptions ( formatOptions ) { const args = { formatOptions } ; const request = this . processRequest ( CommandNames . Configure , args ) ; this . processResponse ( request , true ) ; } setCompilerOptionsForInferredProjects ( options ) { const args = { options } ; const request = this . processRequest ( CommandNames . CompilerOptionsForInferredProjects , args ) ; this . processResponse ( request , false ) ; } openFile ( file , fileContent ? , scriptKindName ? ) { const args = { file , fileContent , scriptKindName } ; this . processRequest ( CommandNames . Open , args ) ; } closeFile ( file ) { const args = { file } ; this . processRequest ( CommandNames . Close , args ) ; } createChangeFileRequestArgs ( fileName , start , end , insertString ) { return { ... this . createFileLocationRequestArgsWithEndLineAndOffset ( fileName , start , end ) , insertString } ; } changeFile ( fileName , args ) { this . lineMaps . set ( fileName , undefined ! ) ; this . processRequest ( CommandNames . Change , args ) ; } toLineColumnOffset ( fileName , position ) { const { line , offset } = this . positionToOneBasedLineOffset ( fileName , position ) ; return { line , character : offset } ; } getQuickInfoAtPosition ( fileName , position ) { const args = this . createFileLocationRequestArgs ( fileName , position ) ; const request = this . processRequest < protocol . QuickInfoRequest > ( CommandNames . Quickinfo , args ) ; const response = this . processResponse < protocol . QuickInfoResponse > ( request ) ; const body = response . body ! ; return { kind : body . kind , kindModifiers : body . kindModifiers , textSpan : this . decodeSpan ( body , fileName ) , displayParts : [ { kind : "text" , text : body . displayString } ] , documentation : typeof body . documentation === "string" ? [ { kind : "text" , text : body . documentation } ] : body . documentation , tags : this . decodeLinkDisplayParts ( body . tags ) } ; } getProjectInfo ( file , needFileNameList ) { const args = { file , needFileNameList } ; const request = this . processRequest < protocol . ProjectInfoRequest > ( CommandNames . ProjectInfo , args ) ; const response = this . processResponse < protocol . ProjectInfoResponse > ( request ) ; return { configFileName : response . body ! . configFileName , fileNames : response . body ! . fileNames } ; } getCompletionsAtPosition ( fileName , position , _preferences ) { const args = this . createFileLocationRequestArgs ( fileName , position ) ; const request = this . processRequest < protocol . CompletionsRequest > ( CommandNames . CompletionInfo , args ) ; const response = this . processResponse < protocol . CompletionInfoResponse > ( request ) ; return { isGlobalCompletion : response . body ! . isGlobalCompletion , isMemberCompletion : response . body ! . isMemberCompletion , isNewIdentifierLocation : response . body ! . isNewIdentifierLocation , entries : response . body ! . entries . map < CompletionEntry > ( entry => { if ( entry . replacementSpan !== undefined ) { const res = { ... entry , data : entry . data as any , replacementSpan : this . decodeSpan ( entry . replacementSpan , fileName ) } ; return res ; } return entry as { name : string ; kind : ScriptElementKind ; kindModifiers : string ; sortText : string ; } ; } ) } ; } getCompletionEntryDetails ( fileName , position , entryName , _options , source , _preferences , data ) { const args = { ... this . createFileLocationRequestArgs ( fileName , position ) , entryNames : [ { name : entryName , source , data } ] } ; const request = this . processRequest < protocol . CompletionDetailsRequest > ( CommandNames . CompletionDetailsFull , args ) ; const response = this . processResponse < protocol . Response > ( request ) ; Debug . assert ( response . body . length === 1 , "Unexpected length of completion details response body." ) ; return response . body [ 0 ] ; } getCompletionEntrySymbol ( _fileName , _position , _entryName ) { return notImplemented ( ) ; } getNavigateToItems ( searchValue ) { const args = { searchValue , file : this . host . getScriptFileNames ( ) [ 0 ] } ; const request = this . processRequest < protocol . NavtoRequest > ( CommandNames . Navto , args ) ; const response = this . processResponse < protocol . NavtoResponse > ( request ) ; return response . body ! . map ( entry => ( { name : entry . name , containerName : entry . containerName || "" , containerKind : entry . containerKind || ScriptElementKind . unknown , kind : entry . kind , kindModifiers : entry . kindModifiers || "" , matchKind : entry . matchKind as keyof typeof PatternMatchKind , isCaseSensitive : entry . isCaseSensitive , fileName : entry . file , textSpan : this . decodeSpan ( entry ) , } ) ) ; } getFormattingEditsForRange ( file , start , end , _options ) { const args = this . createFileLocationRequestArgsWithEndLineAndOffset ( file , start , end ) ; const request = this . processRequest < protocol . FormatRequest > ( CommandNames . Format , args ) ; const response = this . processResponse < protocol . FormatResponse > ( request ) ; return response . body ! . map ( entry => this . convertCodeEditsToTextChange ( file , entry ) ) ; } getFormattingEditsForDocument ( fileName , options ) { return this . getFormattingEditsForRange ( fileName , 0 , this . host . getScriptSnapshot ( fileName ) ! . getLength ( ) , options ) ; } getFormattingEditsAfterKeystroke ( fileName , position , key , _options ) { const args = { ... this . createFileLocationRequestArgs ( fileName , position ) , key } ; const request = this . processRequest < protocol . FormatOnKeyRequest > ( CommandNames . Formatonkey , args ) ; const response = this . processResponse < protocol . FormatResponse > ( request ) ; return response . body ! . map ( entry => this . convertCodeEditsToTextChange ( fileName , entry ) ) ; } getDefinitionAtPosition ( fileName , position ) { const args = this . createFileLocationRequestArgs ( fileName , position ) ; const request = this . processRequest < protocol . DefinitionRequest > ( CommandNames . Definition , args ) ; const response = this . processResponse < protocol . DefinitionResponse > ( request ) ; return response . body ! . map ( entry => ( { containerKind : ScriptElementKind . unknown , containerName : "" , fileName : entry . file , textSpan : this . decodeSpan ( entry ) , kind : ScriptElementKind . unknown , name : "" } ) ) ; } getDefinitionAndBoundSpan ( fileName , position ) { const args = this . createFileLocationRequestArgs ( fileName , position ) ; const request = this . processRequest < protocol . DefinitionRequest > ( CommandNames . DefinitionAndBoundSpan , args ) ; const response = this . processResponse < protocol . DefinitionInfoAndBoundSpanResponse > ( request ) ; const body = Debug . checkDefined ( response . body ) ; return { definitions : body . definitions . map ( entry => ( { containerKind : ScriptElementKind . unknown , containerName : "" , fileName : entry . file , textSpan : this . decodeSpan ( entry ) , kind : ScriptElementKind . unknown , name : "" , unverified : entry . unverified , } ) ) , textSpan : this . decodeSpan ( body . textSpan , request . arguments . file ) } ; } getTypeDefinitionAtPosition ( fileName , position ) { const args = this . createFileLocationRequestArgs ( fileName , position ) ; const request = this . processRequest < protocol . TypeDefinitionRequest > ( CommandNames . TypeDefinition , args ) ; const response = this . processResponse < protocol . TypeDefinitionResponse > ( request ) ; return response . body ! . map ( entry => ( { containerKind : ScriptElementKind . unknown , containerName : "" , fileName : entry . file , textSpan : this . decodeSpan ( entry ) , kind : ScriptElementKind . unknown , name : "" } ) ) ; } getImplementationAtPosition ( fileName , position ) { const args = this . createFileLocationRequestArgs ( fileName , position ) ; const request = this . processRequest < protocol . ImplementationRequest > ( CommandNames . Implementation , args ) ; const response = this . processResponse < protocol . ImplementationResponse > ( request ) ; return response . body ! . map ( entry => ( { fileName : entry . file , textSpan : this . decodeSpan ( entry ) , kind : ScriptElementKind . unknown , displayParts : [ ] } ) ) ; } findReferences ( fileName , position ) { const args = this . createFileLocationRequestArgs ( fileName , position ) ; const request = this . processRequest < protocol . ReferencesRequest > ( CommandNames . ReferencesFull , args ) ; const response = this . processResponse ( request ) ; return response . body ; } getReferencesAtPosition ( fileName , position ) { const args = this . createFileLocationRequestArgs ( fileName , position ) ; const request = this . processRequest < protocol . ReferencesRequest > ( CommandNames . References , args ) ; const response = this . processResponse < protocol . ReferencesResponse > ( request ) ; return response . body ! . refs . map ( entry => ( { fileName : entry . file , textSpan : this . decodeSpan ( entry ) , isWriteAccess : entry . isWriteAccess , isDefinition : entry . isDefinition , } ) ) ; } getFileReferences ( fileName ) { const request = this . processRequest < protocol . FileReferencesRequest > ( CommandNames . FileReferences , { file : fileName } ) ; const response = this . processResponse < protocol . FileReferencesResponse > ( request ) ; return response . body ! . refs . map ( entry => ( { fileName : entry . file , textSpan : this . decodeSpan ( entry ) , isWriteAccess : entry . isWriteAccess , isDefinition : entry . isDefinition , } ) ) ; } getEmitOutput ( file ) { const request = this . processRequest < protocol . EmitOutputRequest > ( protocol . CommandTypes . EmitOutput , { file } ) ; const response = this . processResponse < protocol . EmitOutputResponse > ( request ) ; return response . body as EmitOutput ; } getSyntacticDiagnostics ( file ) { return this . getDiagnostics ( file , CommandNames . SyntacticDiagnosticsSync ) ; } getSemanticDiagnostics ( file ) { return this . getDiagnostics ( file , CommandNames . SemanticDiagnosticsSync ) ; } getSuggestionDiagnostics ( file ) { return this . getDiagnostics ( file , CommandNames . SuggestionDiagnosticsSync ) ; } private getDiagnostics ( file , command ) { const request = this . processRequest < protocol . SyntacticDiagnosticsSyncRequest | protocol . SemanticDiagnosticsSyncRequest | protocol . SuggestionDiagnosticsSyncRequest > ( command , { file , includeLinePosition : true } ) ; const response = this . processResponse < protocol . SyntacticDiagnosticsSyncResponse | protocol . SemanticDiagnosticsSyncResponse | protocol . SuggestionDiagnosticsSyncResponse > ( request ) ; const sourceText = getSnapshotText ( this . host . getScriptSnapshot ( file ) ! ) ; const fakeSourceFile = { fileName : file , text : sourceText } as SourceFile ; return ( response . body as protocol . DiagnosticWithLinePosition [ ] ) . map ( ( entry ) : DiagnosticWithLocation => { const category = firstDefined ( Object . keys ( DiagnosticCategory ) , id => isString ( id ) && entry . category === id . toLowerCase ( ) ? ( DiagnosticCategory as any ) [ id ] : undefined ) ; return { file : fakeSourceFile , start : entry . start , length : entry . length , messageText : entry . message , category : Debug . checkDefined ( category , "convertDiagnostic: category should not be undefined" ) , code : entry . code , reportsUnnecessary : entry . reportsUnnecessary , reportsDeprecated : entry . reportsDeprecated , } ; } ) ; } getCompilerOptionsDiagnostics ( ) { return notImplemented ( ) ; } getRenameInfo ( fileName , position , _options ? , findInStrings ? , findInComments ? ) { const args = { ... this . createFileLocationRequestArgs ( fileName , position ) , findInStrings , findInComments } ; const request = this . processRequest < protocol . RenameRequest > ( CommandNames . Rename , args ) ; const response = this . processResponse < protocol . RenameResponse > ( request ) ; const body = response . body ! ; const locations = [ ] ; for ( const entry of body . locs ) { const fileName = entry . file ; for ( const { start , end , contextStart , contextEnd , ... prefixSuffixText } of entry . locs ) { locations . push ( { textSpan : this . decodeSpan ( { start , end } , fileName ) , fileName , ... ( contextStart !== undefined ? { contextSpan : this . decodeSpan ( { start : contextStart , end : contextEnd ! } , fileName ) } : undefined ) , ... prefixSuffixText } ) ; } } const renameInfo = body . info . canRename ? identity < RenameInfoSuccess > ( { canRename : body . info . canRename , fileToRename : body . info . fileToRename , displayName : body . info . displayName , fullDisplayName : body . info . fullDisplayName , kind : body . info . kind , kindModifiers : body . info . kindModifiers , triggerSpan : createTextSpanFromBounds ( position , position ) , } ) : identity < RenameInfoFailure > ( { canRename : false , localizedErrorMessage : body . info . localizedErrorMessage } ) ; this . lastRenameEntry = { renameInfo , inputs : { fileName , position , findInStrings : ! ! findInStrings , findInComments : ! ! findInComments , } , locations , } ; return renameInfo ; } getSmartSelectionRange ( ) { return notImplemented ( ) ; } findRenameLocations ( fileName , position , findInStrings , findInComments ) { if ( ! this . lastRenameEntry || this . lastRenameEntry . inputs . fileName !== fileName || this . lastRenameEntry . inputs . position !== position || this . lastRenameEntry . inputs . findInStrings !== findInStrings || this . lastRenameEntry . inputs . findInComments !== findInComments ) { this . getRenameInfo ( fileName , position , { allowRenameOfImportPath : true } , findInStrings , findInComments ) ; } return this . lastRenameEntry ! . locations ; } private decodeNavigationBarItems ( items , fileName , lineMap ) { if ( ! items ) { return [ ] ; } return items . map ( item => ( { text : item . text , kind : item . kind , kindModifiers : item . kindModifiers || "" , spans : item . spans . map ( span => this . decodeSpan ( span , fileName , lineMap ) ) , childItems : this . decodeNavigationBarItems ( item . childItems , fileName , lineMap ) , indent : item . indent , bolded : false , grayed : false } ) ) ; } getNavigationBarItems ( file ) { const request = this . processRequest < protocol . NavBarRequest > ( CommandNames . NavBar , { file } ) ; const response = this . processResponse < protocol . NavBarResponse > ( request ) ; const lineMap = this . getLineMap ( file ) ; return this . decodeNavigationBarItems ( response . body , file , lineMap ) ; } private decodeNavigationTree ( tree , fileName , lineMap ) { return { text : tree . text , kind : tree . kind , kindModifiers : tree . kindModifiers , spans : tree . spans . map ( span => this . decodeSpan ( span , fileName , lineMap ) ) , nameSpan : tree . nameSpan && this . decodeSpan ( tree . nameSpan , fileName , lineMap ) , childItems : map ( tree . childItems , item => this . decodeNavigationTree ( item , fileName , lineMap ) ) } ; } getNavigationTree ( file ) { const request = this . processRequest < protocol . NavTreeRequest > ( CommandNames . NavTree , { file } ) ; const response = this . processResponse < protocol . NavTreeResponse > ( request ) ; const lineMap = this . getLineMap ( file ) ; return this . decodeNavigationTree ( response . body ! , file , lineMap ) ; } private decodeSpan ( span ) ; private decodeSpan ( span , fileName , lineMap ? ) ; private decodeSpan ( span , fileName ? , lineMap ? ) { if ( span . start . line === 1 && span . start . offset === 1 && span . end . line === 1 && span . end . offset === 1 ) { return { start : 0 , length : 0 } ; } fileName = fileName || span . file ; lineMap = lineMap || this . getLineMap ( fileName ) ; return createTextSpanFromBounds ( this . lineOffsetToPosition ( fileName , span . start , lineMap ) , this . lineOffsetToPosition ( fileName , span . end , lineMap ) ) ; } private decodeLinkDisplayParts ( tags ) { return tags . map ( tag => typeof tag . text === "string" ? { ... tag , text : [ textPart ( tag . text ) ] } : ( tag as JSDocTagInfo ) ) ; } getNameOrDottedNameSpan ( _fileName , _startPos , _endPos ) { return notImplemented ( ) ; } getBreakpointStatementAtPosition ( _fileName , _position ) { return notImplemented ( ) ; } getSignatureHelpItems ( fileName , position ) { const args = this . createFileLocationRequestArgs ( fileName , position ) ; const request = this . processRequest < protocol . SignatureHelpRequest > ( CommandNames . SignatureHelp , args ) ; const response = this . processResponse < protocol . SignatureHelpResponse > ( request ) ; if ( ! response . body ) { return undefined ; } const { items : encodedItems , applicableSpan : encodedApplicableSpan , selectedItemIndex , argumentIndex , argumentCount } = response . body ; const applicableSpan = encodedApplicableSpan as unknown as TextSpan ; const items = ( encodedItems as ( SignatureHelpItem | protocol . SignatureHelpItem ) [ ] ) . map ( item => ( { ... item , tags : this . decodeLinkDisplayParts ( item . tags ) } ) ) ; return { items , applicableSpan , selectedItemIndex , argumentIndex , argumentCount } ; } getOccurrencesAtPosition ( fileName , position ) { const args = this . createFileLocationRequestArgs ( fileName , position ) ; const request = this . processRequest < protocol . OccurrencesRequest > ( CommandNames . Occurrences , args ) ; const response = this . processResponse < protocol . OccurrencesResponse > ( request ) ; return response . body ! . map ( entry => ( { fileName : entry . file , textSpan : this . decodeSpan ( entry ) , isWriteAccess : entry . isWriteAccess , isDefinition : false } ) ) ; } getDocumentHighlights ( fileName , position , filesToSearch ) { const args = { ... this . createFileLocationRequestArgs ( fileName , position ) , filesToSearch } ; const request = this . processRequest < protocol . DocumentHighlightsRequest > ( CommandNames . DocumentHighlights , args ) ; const response = this . processResponse < protocol . DocumentHighlightsResponse > ( request ) ; return response . body ! . map ( item => ( { fileName : item . file , highlightSpans : item . highlightSpans . map ( span => ( { textSpan : this . decodeSpan ( span , item . file ) , kind : span . kind } ) ) , } ) ) ; } getOutliningSpans ( file ) { const request = this . processRequest < protocol . OutliningSpansRequest > ( CommandNames . GetOutliningSpans , { file } ) ; const response = this . processResponse < protocol . OutliningSpansResponse > ( request ) ; return response . body ! . map < OutliningSpan > ( item => ( { textSpan : this . decodeSpan ( item . textSpan , file ) , hintSpan : this . decodeSpan ( item . hintSpan , file ) , bannerText : item . bannerText , autoCollapse : item . autoCollapse , kind : item . kind } ) ) ; } getTodoComments ( _fileName , _descriptors ) { return notImplemented ( ) ; } getDocCommentTemplateAtPosition ( _fileName , _position , _options ? ) { return notImplemented ( ) ; } isValidBraceCompletionAtPosition ( _fileName , _position , _openingBrace ) { return notImplemented ( ) ; } getJsxClosingTagAtPosition ( _fileName , _position ) { return notImplemented ( ) ; } getSpanOfEnclosingComment ( _fileName , _position , _onlyMultiLine ) { return notImplemented ( ) ; } getCodeFixesAtPosition ( file , start , end , errorCodes ) { const args = { ... this . createFileRangeRequestArgs ( file , start , end ) , errorCodes } ; const request = this . processRequest < protocol . CodeFixRequest > ( CommandNames . GetCodeFixes , args ) ; const response = this . processResponse < protocol . CodeFixResponse > ( request ) ; return response . body ! . map < CodeFixAction > ( ( { fixName , description , changes , commands , fixId , fixAllDescription } ) => ( { fixName , description , changes : this . convertChanges ( changes , file ) , commands : commands as CodeActionCommand [ ] , fixId , fixAllDescription } ) ) ; } getCombinedCodeFix = notImplemented ; applyCodeActionCommand = notImplemented ; provideInlayHints ( file , span ) { const { start , length } = span ; const args = { file , start , length } ; const request = this . processRequest < protocol . InlayHintsRequest > ( CommandNames . ProvideInlayHints , args ) ; const response = this . processResponse < protocol . InlayHintsResponse > ( request ) ; return response . body ! . map ( item => ( { ... item , kind : item . kind as InlayHintKind , position : this . lineOffsetToPosition ( file , item . position ) , } ) ) ; } private createFileLocationOrRangeRequestArgs ( positionOrRange , fileName ) { return typeof positionOrRange === "number" ? this . createFileLocationRequestArgs ( fileName , positionOrRange ) : this . createFileRangeRequestArgs ( fileName , positionOrRange . pos , positionOrRange . end ) ; } private createFileLocationRequestArgs ( file , position ) { const { line , offset } = this . positionToOneBasedLineOffset ( file , position ) ; return { file , line , offset } ; } private createFileRangeRequestArgs ( file , start , end ) { const { line : startLine , offset : startOffset } = this . positionToOneBasedLineOffset ( file , start ) ; const { line : endLine , offset : endOffset } = this . positionToOneBasedLineOffset ( file , end ) ; return { file , startLine , startOffset , endLine , endOffset } ; } private createFileLocationRequestArgsWithEndLineAndOffset ( file , start , end ) { const { line , offset } = this . positionToOneBasedLineOffset ( file , start ) ; const { line : endLine , offset : endOffset } = this . positionToOneBasedLineOffset ( file , end ) ; return { file , line , offset , endLine , endOffset } ; } getApplicableRefactors ( fileName , positionOrRange ) { const args = this . createFileLocationOrRangeRequestArgs ( positionOrRange , fileName ) ; const request = this . processRequest < protocol . GetApplicableRefactorsRequest > ( CommandNames . GetApplicableRefactors , args ) ; const response = this . processResponse < protocol . GetApplicableRefactorsResponse > ( request ) ; return response . body ! ; } getEditsForRefactor ( fileName , _formatOptions , positionOrRange , refactorName , actionName ) { const args = this . createFileLocationOrRangeRequestArgs ( positionOrRange , fileName ) as protocol . GetEditsForRefactorRequestArgs ; args . refactor = refactorName ; args . action = actionName ; const request = this . processRequest < protocol . GetEditsForRefactorRequest > ( CommandNames . GetEditsForRefactor , args ) ; const response = this . processResponse < protocol . GetEditsForRefactorResponse > ( request ) ; if ( ! response . body ) { return { edits : [ ] , renameFilename : undefined , renameLocation : undefined } ; } const edits = this . convertCodeEditsToTextChanges ( response . body . edits ) ; const renameFilename = response . body . renameFilename ; let renameLocation ; if ( renameFilename !== undefined ) { renameLocation = this . lineOffsetToPosition ( renameFilename , response . body . renameLocation ! ) ; } return { edits , renameFilename , renameLocation } ; } organizeImports ( _args , _formatOptions ) { return notImplemented ( ) ; } getEditsForFileRename ( ) { return notImplemented ( ) ; } private convertCodeEditsToTextChanges ( edits ) { return edits . map ( edit => { const fileName = edit . fileName ; return { fileName , textChanges : edit . textChanges . map ( t => this . convertTextChangeToCodeEdit ( t , fileName ) ) } ; } ) ; } private convertChanges ( changes , fileName ) { return changes . map ( change => ( { fileName : change . fileName , textChanges : change . textChanges . map ( textChange => this . convertTextChangeToCodeEdit ( textChange , fileName ) ) } ) ) ; } convertTextChangeToCodeEdit ( change , fileName ) { return { span : this . decodeSpan ( change , fileName ) , newText : change . newText ? change . newText : "" } ; } getBraceMatchingAtPosition ( fileName , position ) { const args = this . createFileLocationRequestArgs ( fileName , position ) ; const request = this . processRequest < protocol . BraceRequest > ( CommandNames . Brace , args ) ; const response = this . processResponse < protocol . BraceResponse > ( request ) ; return response . body ! . map ( entry => this . decodeSpan ( entry , fileName ) ) ; } configurePlugin ( pluginName , configuration ) { const request = this . processRequest < protocol . ConfigurePluginRequest > ( "configurePlugin" , { pluginName , configuration } ) ; this . processResponse < protocol . ConfigurePluginResponse > ( request , true ) ; } getIndentationAtPosition ( _fileName , _position , _options ) { return notImplemented ( ) ; } getSyntacticClassifications ( _fileName , _span ) { return notImplemented ( ) ; } getSemanticClassifications ( _fileName , _span ) { return notImplemented ( ) ; } getEncodedSyntacticClassifications ( _fileName , _span ) { return notImplemented ( ) ; } getEncodedSemanticClassifications ( file , span , format ? ) { const request = this . processRequest < protocol . EncodedSemanticClassificationsRequest > ( protocol . CommandTypes . EncodedSemanticClassificationsFull , { file , start : span . start , length : span . length , format } ) ; const r = this . processResponse < protocol . EncodedSemanticClassificationsResponse > ( request ) ; return r . body ! ; } private convertCallHierarchyItem ( item ) { return { file : item . file , name : item . name , kind : item . kind , kindModifiers : item . kindModifiers , containerName : item . containerName , span : this . decodeSpan ( item . span , item . file ) , selectionSpan : this . decodeSpan ( item . selectionSpan , item . file ) } ; } prepareCallHierarchy ( fileName , position ) { const args = this . createFileLocationRequestArgs ( fileName , position ) ; const request = this . processRequest < protocol . PrepareCallHierarchyRequest > ( CommandNames . PrepareCallHierarchy , args ) ; const response = this . processResponse < protocol . PrepareCallHierarchyResponse > ( request ) ; return response . body && mapOneOrMany ( response . body , item => this . convertCallHierarchyItem ( item ) ) ; } private convertCallHierarchyIncomingCall ( item ) { return { from : this . convertCallHierarchyItem ( item . from ) , fromSpans : item . fromSpans . map ( span => this . decodeSpan ( span , item . from . file ) ) } ; } provideCallHierarchyIncomingCalls ( fileName , position ) { const args = this . createFileLocationRequestArgs ( fileName , position ) ; const request = this . processRequest < protocol . ProvideCallHierarchyIncomingCallsRequest > ( CommandNames . ProvideCallHierarchyIncomingCalls , args ) ; const response = this . processResponse < protocol . ProvideCallHierarchyIncomingCallsResponse > ( request ) ; return response . body . map ( item => this . convertCallHierarchyIncomingCall ( item ) ) ; } private convertCallHierarchyOutgoingCall ( file , item ) { return { to : this . convertCallHierarchyItem ( item . to ) , fromSpans : item . fromSpans . map ( span => this . decodeSpan ( span , file ) ) } ; } provideCallHierarchyOutgoingCalls ( fileName , position ) { const args = this . createFileLocationRequestArgs ( fileName , position ) ; const request = this . processRequest < protocol . ProvideCallHierarchyOutgoingCallsRequest > ( CommandNames . ProvideCallHierarchyOutgoingCalls , args ) ; const response = this . processResponse < protocol . ProvideCallHierarchyOutgoingCallsResponse > ( request ) ; return response . body . map ( item => this . convertCallHierarchyOutgoingCall ( fileName , item ) ) ; } getProgram ( ) { throw new Error ( "Program objects are not serializable through the server protocol." ) ; } getAutoImportProvider ( ) { throw new Error ( "Program objects are not serializable through the server protocol." ) ; } getNonBoundSourceFile ( _fileName ) { throw new Error ( "SourceFile objects are not serializable through the server protocol." ) ; } getSourceFile ( _fileName ) { throw new Error ( "SourceFile objects are not serializable through the server protocol." ) ; } cleanupSemanticCache ( ) { throw new Error ( "cleanupSemanticCache is not available through the server layer." ) ; } getSourceMapper ( ) { return notImplemented ( ) ; } clearSourceMapperCache ( ) { return notImplemented ( ) ; } toggleLineComment ( ) { return notImplemented ( ) ; } toggleMultilineComment ( ) { return notImplemented ( ) ; } commentSelection ( ) { return notImplemented ( ) ; } uncommentSelection ( ) { return notImplemented ( ) ; } dispose ( ) { throw new Error ( "dispose is not available through the server layer." ) ; } } }