license import { UrlResolver } from 'polymer-analyzer' ; import { ProjectConfig } from 'polymer-project-config' ; import * as util from 'util' ; import { ClientCapabilities , IConnection , InitializeResult , ServerCapabilities , TextDocuments , TextDocumentSyncKind } from 'vscode-languageserver' ; import Uri from 'vscode-uri' ; import AnalyzerSynchronizer from './analyzer-synchronizer' ; import AutoCompleter from './auto-completer' ; import CommandExecutor , { allSupportedCommands } from './commands' ; import AnalyzerLSPConverter from './converter' ; import DefinitionFinder from './definition-finder' ; import DiagnosticGenerator from './diagnostics' ; import FeatureFinder from './feature-finder' ; import FileSynchronizer from './file-synchronizer' ; import HoverDocumenter from './hover-documenter' ; import { Logger } from './logger' ; import Settings from './settings' ; import { Handler } from './util' ; export interface LoggingOptions { interceptConsole : boolean ; logToFile ? : string ; } export default class LanguageServer extends Handler { protected readonly connection : IConnection ; readonly fileSynchronizer : FileSynchronizer ; private readonly syncKind : TextDocumentSyncKind ; /** Get an initialized and ready language server. */ static async initializeWithConnection ( connection , loggingOptions ) { function getWorkspaceUri ( rootUri , rootPath ) { if ( rootUri ) { return Uri . parse ( rootUri ) ; } if ( rootPath ) { return Uri . file ( rootPath ) ; } return null ; } const server = await new Promise < LanguageServer > ( ( resolve , reject ) => { connection . onInitialize ( async ( params ) : Promise < InitializeResult > => { const workspaceUri = getWorkspaceUri ( params . rootUri , params . rootPath ) ; if ( ! workspaceUri || workspaceUri . scheme !== 'file' ) { const error = new Error ( `Got invalid workspaceUri from client: ` + `${ util . inspect ( workspaceUri ) }` ) ; reject ( error ) ; throw error ; } const { urlResolver } = await ProjectConfig . initializeAnalyzerFromDirectory ( workspaceUri . fsPath ) ; const newServer = new LanguageServer ( connection , workspaceUri , params . capabilities , urlResolver , loggingOptions . logToFile ) ; resolve ( newServer ) ; return { capabilities : newServer . capabilities ( params . capabilities ) } ; } ) ; } ) ; if ( loggingOptions . interceptConsole ) { const { hookUpRemoteConsole } = await import ( '../intercept-logs' ) ; hookUpRemoteConsole ( connection . console ) ; } return server ; } /**
     * Called once we've got an initialized connection, a working polymer
     * editor service, and a workspace.
     */ constructor ( connection , workspaceUri , clientCapabilities , urlResolver , logToFile ) { super ( ) ; this . disposables . push ( connection ) ; this . connection = connection ; const logger = new Logger ( { connection , logToFileFlag : logToFile } ) ; this . disposables . push ( logger ) ; const workspacePath = workspaceUri . fsPath ; const documents = new TextDocuments ( ) ; documents . listen ( connection ) ; this . syncKind = documents . syncKind ; const converter = new AnalyzerLSPConverter ( workspaceUri , urlResolver ) ; this . fileSynchronizer = new FileSynchronizer ( connection , documents , workspacePath , converter , logger ) ; logger . log ( `\n\n\n\n\nInitialized with workspace path: ${ workspacePath }` ) ; logger . log ( `Client's capabilities:` ) ; logger . log ( JSON . stringify ( clientCapabilities , null , 2 ) ) ; logger . log ( `\n\nServer's capabilities:` ) ; logger . log ( JSON . stringify ( this . capabilities ( clientCapabilities ) , null , 2 ) ) ; const analyzerSynchronizer = new AnalyzerSynchronizer ( documents , this . fileSynchronizer , logger , urlResolver , converter ) ; const settings = new Settings ( connection , this . fileSynchronizer , analyzerSynchronizer . analyzer ) ; this . disposables . push ( settings ) ; logger . hookupSettings ( settings ) ; const diagnosticGenerator = new DiagnosticGenerator ( analyzerSynchronizer . analyzer , converter , connection , settings , analyzerSynchronizer , documents ) ; this . disposables . push ( diagnosticGenerator ) ; const commandExecutor = new CommandExecutor ( this . connection , diagnosticGenerator ) ; this . disposables . push ( commandExecutor ) ; const featureFinder = new FeatureFinder ( analyzerSynchronizer . analyzer ) ; const hoverDocumenter = new HoverDocumenter ( this . connection , converter , featureFinder , logger ) ; this . disposables . push ( hoverDocumenter ) ; const autoCompleter = new AutoCompleter ( this . connection , converter , featureFinder , analyzerSynchronizer . analyzer , clientCapabilities ) ; this . disposables . push ( autoCompleter ) ; const definitionFinder = new DefinitionFinder ( this . connection , converter , featureFinder , analyzerSynchronizer . analyzer , settings ) ; this . disposables . push ( definitionFinder ) ; } private capabilities ( clientCapabilities ) { const ourCapabilities = { textDocumentSync : { change : this . syncKind , openClose : true , willSaveWaitUntil : true } , completionProvider : { resolveProvider : false } , hoverProvider : true , definitionProvider : true , codeActionProvider : true , referencesProvider : true , documentSymbolProvider : true , workspaceSymbolProvider : true , codeLensProvider : { } , } ; if ( clientCapabilities . workspace && clientCapabilities . workspace . applyEdit ) { ourCapabilities . executeCommandProvider = { commands : allSupportedCommands } ; } return ourCapabilities ; } }