Actualizacion maquina principal
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-eslint / server / index.ts
diff --git a/.config/coc/extensions/node_modules/coc-eslint/server/index.ts b/.config/coc/extensions/node_modules/coc-eslint/server/index.ts
new file mode 100644 (file)
index 0000000..a249038
--- /dev/null
@@ -0,0 +1,1294 @@
+/* --------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ * ------------------------------------------------------------------------------------------ */
+'use strict'
+
+import * as os from 'os'
+import * as path from 'path'
+import { Position, CancellationToken, CodeAction, CodeActionKind, CodeActionRequest, Command, createConnection, Diagnostic, DiagnosticSeverity, DidChangeConfigurationNotification, DidChangeWatchedFilesNotification, ErrorCodes, ExecuteCommandRequest, Files, IConnection, NotificationHandler, NotificationType, Range, RequestHandler, RequestType, ResponseError, TextDocumentIdentifier, TextDocuments, TextDocumentSaveReason, TextDocumentSyncKind, TextEdit, VersionedTextDocumentIdentifier, WorkspaceChange } from 'vscode-languageserver'
+import { URI } from 'vscode-uri'
+import { CLIOptions, ESLintAutoFixEdit, ESLintError, ESLintModule, ESLintProblem, ESLintReport, Is, TextDocumentSettings } from './types'
+import { getAllFixEdits, executeInWorkspaceDirectory, getFilePath, isUNC, resolveModule } from './util'
+import { TextDocument } from 'vscode-languageserver-textdocument'
+declare var __webpack_require__: any
+declare var __non_webpack_require__: any
+const requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require
+
+namespace CommandIds {
+  export const applySingleFix = 'eslint.applySingleFix'
+  export const applySameFixes = 'eslint.applySameFixes'
+  export const applyAllFixes = 'eslint.applyAllFixes'
+  export const applyAutoFix = 'eslint.applyAutoFix'
+  export const applyDisableLine = 'eslint.applyDisableLine'
+  export const applyDisableFile = 'eslint.applyDisableFile'
+  export const openRuleDoc = 'eslint.openRuleDoc'
+}
+
+namespace OpenESLintDocRequest {
+  export const type = new RequestType<OpenESLintDocParams, OpenESLintDocResult, void, void>('eslint/openDoc')
+}
+
+interface OpenESLintDocParams {
+  url: string
+}
+
+interface OpenESLintDocResult {
+}
+
+enum Status {
+  ok = 1,
+  warn = 2,
+  error = 3
+}
+
+interface StatusParams {
+  state: Status
+}
+
+namespace StatusNotification {
+  export const type = new NotificationType<StatusParams, void>('eslint/status')
+}
+
+interface NoConfigParams {
+  message: string
+  document: TextDocumentIdentifier
+}
+
+interface NoConfigResult { }
+
+namespace NoConfigRequest {
+  export const type = new RequestType<
+    NoConfigParams,
+    NoConfigResult,
+    void,
+    void
+  >('eslint/noConfig')
+}
+
+interface NoESLintLibraryParams {
+  source: TextDocumentIdentifier
+}
+
+interface NoESLintLibraryResult { }
+
+namespace NoESLintLibraryRequest {
+  export const type = new RequestType<
+    NoESLintLibraryParams,
+    NoESLintLibraryResult,
+    void,
+    void
+  >('eslint/noLibrary')
+}
+
+interface RuleCodeActions {
+  fixes: CodeAction[]
+  disable?: CodeAction
+  fixAll?: CodeAction
+  disableFile?: CodeAction
+  showDocumentation?: CodeAction
+}
+
+class CodeActionResult {
+  private _actions: Map<string, RuleCodeActions>
+  private _fixAll: CodeAction | undefined
+
+  public constructor() {
+    this._actions = new Map()
+  }
+
+  public get(ruleId: string): RuleCodeActions {
+    let result: RuleCodeActions = this._actions.get(ruleId)
+    if (result === undefined) {
+      result = { fixes: [] }
+      this._actions.set(ruleId, result)
+    }
+    return result
+  }
+
+  public set fixAll(action: CodeAction) {
+    this._fixAll = action
+  }
+
+  public all(): CodeAction[] {
+    let result: CodeAction[] = []
+    for (let actions of this._actions.values()) {
+      result.push(...actions.fixes)
+      if (actions.disable) {
+        result.push(actions.disable)
+      }
+      if (actions.fixAll) {
+        result.push(actions.fixAll)
+      }
+      if (actions.disableFile) {
+        result.push(actions.disableFile)
+      }
+      if (actions.showDocumentation) {
+        result.push(actions.showDocumentation)
+      }
+    }
+    if (this._fixAll !== undefined) {
+      result.push(this._fixAll)
+    }
+    return result
+  }
+
+  public get length(): number {
+    let result = 0
+    for (let actions of this._actions.values()) {
+      result += actions.fixes.length
+    }
+    return result
+  }
+}
+
+function makeDiagnostic(problem: ESLintProblem): Diagnostic {
+  let message =
+    problem.ruleId != null
+      ? `${problem.message} (${problem.ruleId})`
+      : `${problem.message}`
+  let startLine = Math.max(0, problem.line - 1)
+  let startChar = Math.max(0, problem.column - 1)
+  let endLine =
+    problem.endLine != null ? Math.max(0, problem.endLine - 1) : startLine
+  let endChar =
+    problem.endColumn != null ? Math.max(0, problem.endColumn - 1) : startChar
+  return {
+    message,
+    severity: convertSeverity(problem.severity),
+    source: 'eslint',
+    range: {
+      start: { line: startLine, character: startChar },
+      end: { line: endLine, character: endChar }
+    },
+    code: problem.ruleId
+  }
+}
+
+interface FixableProblem {
+  label: string
+  documentVersion: number
+  ruleId: string
+  line: number
+  edit?: ESLintAutoFixEdit
+}
+
+function computeKey(diagnostic: Diagnostic): string {
+  let range = diagnostic.range
+  return `[${range.start.line},${range.start.character},${range.end.line},${
+    range.end.character
+    }]-${diagnostic.code}`
+}
+
+let codeActions: Map<string, Map<string, FixableProblem>> = new Map<
+  string,
+  Map<string, FixableProblem>
+>()
+function recordCodeAction(
+  document: TextDocument,
+  diagnostic: Diagnostic,
+  problem: ESLintProblem
+): void {
+  if (!problem.ruleId) {
+    return
+  }
+  let uri = document.uri
+  let edits: Map<string, FixableProblem> = codeActions.get(uri)
+  if (!edits) {
+    edits = new Map<string, FixableProblem>()
+    codeActions.set(uri, edits)
+  }
+  edits.set(computeKey(diagnostic), { label: `Fix this ${problem.ruleId} problem`, documentVersion: document.version, ruleId: problem.ruleId, edit: problem.fix, line: problem.line })
+}
+
+function convertSeverity(severity: number): DiagnosticSeverity {
+  switch (severity) {
+    // Eslint 1 is warning
+    case 1:
+      return DiagnosticSeverity.Warning
+    case 2:
+      return DiagnosticSeverity.Error
+    default:
+      return DiagnosticSeverity.Error
+  }
+}
+
+const exitCalled = new NotificationType<[number, string], void>(
+  'eslint/exitCalled'
+)
+
+const nodeExit = process.exit
+process.exit = ((code?: number): void => {
+  let stack = new Error('stack')
+  connection.sendNotification(exitCalled, [code ? code : 0, stack.stack])
+  setTimeout(() => {
+    nodeExit(code)
+  }, 1000)
+}) as any
+process.on('uncaughtException', (error: any) => {
+  let message: string
+  if (error) {
+    if (typeof error.stack === 'string') {
+      message = error.stack
+    } else if (typeof error.message === 'string') {
+      message = error.message
+    } else if (typeof error === 'string') {
+      message = error
+    }
+    if (!message) {
+      try {
+        message = JSON.stringify(error, undefined, 4)
+      } catch (e) {
+        // Should not happen.
+      }
+    }
+  }
+  connection.console.error(`Uncaught exception recevied.
+  ${message || ''}`)
+})
+
+let connection = createConnection()
+connection.console.info(`ESLint server running in node ${process.version}`)
+let documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument)
+
+let _globalNpmPath: string | null | undefined
+function globalNpmPath(): string {
+  if (_globalNpmPath === void 0) {
+    _globalNpmPath = Files.resolveGlobalNodePath(trace)
+    if (_globalNpmPath === void 0) {
+      _globalNpmPath = null
+    }
+  }
+  if (_globalNpmPath === null) {
+    return undefined
+  }
+  return _globalNpmPath
+}
+let _globalYarnPath: string | undefined
+function globalYarnPath(): string {
+  if (_globalYarnPath === void 0) {
+    _globalYarnPath = Files.resolveGlobalYarnPath(trace)
+    if (_globalYarnPath === void 0) {
+      _globalYarnPath = null
+    }
+  }
+  if (_globalYarnPath === null) {
+    return undefined
+  }
+  return _globalYarnPath
+}
+let path2Library: Map<string, ESLintModule> = new Map<string, ESLintModule>()
+let document2Settings: Map<string, Thenable<TextDocumentSettings>> = new Map<
+  string,
+  Thenable<TextDocumentSettings>
+>()
+
+let ruleDocData: {
+  handled: Set<string>
+  urls: Map<string, string>
+} = {
+  handled: new Set<string>(),
+  urls: new Map<string, string>()
+}
+
+function resolveSettings(
+  document: TextDocument
+): Thenable<TextDocumentSettings> {
+  let uri = document.uri
+  let resultPromise = document2Settings.get(uri)
+  if (resultPromise) {
+    return resultPromise
+  }
+  resultPromise = connection.workspace
+    .getConfiguration({ scopeUri: uri, section: '' })
+    .then((settings: TextDocumentSettings) => {
+      let nodePath: string
+      if (settings.nodePath) {
+        nodePath = settings.nodePath
+        if (nodePath.startsWith('~')) {
+          nodePath = nodePath.replace(/^~/, os.homedir())
+        }
+        if (!path.isAbsolute(nodePath)) {
+          nodePath = path.join(URI.parse(settings.workspaceFolder.uri).fsPath, nodePath)
+        }
+      } else if (settings.packageManager === 'npm') {
+        nodePath = globalNpmPath()
+      } else if (settings.packageManager === 'yarn') {
+        nodePath = globalYarnPath()
+      }
+      let uri = URI.parse(document.uri)
+      let promise: Thenable<string>
+      let directory: string
+      if (uri.scheme === 'file') {
+        directory = path.dirname(uri.fsPath)
+      } else {
+        directory = settings.workspaceFolder ? URI.parse(settings.workspaceFolder.uri).fsPath : undefined
+      }
+      promise = resolveModule('./eslint', directory, nodePath).catch(() => {
+        return resolveModule('eslint', directory, nodePath)
+      })
+      return promise.then(path => {
+        let library = path2Library.get(path)
+        if (!library) {
+          library = requireFunc(path)
+          if (!library.CLIEngine) {
+            settings.validate = false
+            connection.console.error(
+              `The eslint library loaded from ${path} doesn\'t export a CLIEngine. You need at least eslint@1.0.0`
+            )
+          } else {
+            connection.console.info(`ESLint library loaded from: ${path}`)
+            settings.library = library
+          }
+          path2Library.set(path, library)
+        } else {
+          settings.library = library
+        }
+        return settings
+      }, () => {
+        settings.validate = false
+        connection.sendRequest(NoESLintLibraryRequest.type, {
+          source: { uri: document.uri }
+        })
+        return settings
+      }
+      )
+    })
+  document2Settings.set(uri, resultPromise)
+  return resultPromise
+}
+
+interface Request<P, R> {
+  method: string
+  params: P
+  documentVersion: number | undefined
+  resolve: (value: R | Thenable<R>) => void | undefined
+  reject: (error: any) => void | undefined
+  token: CancellationToken | undefined
+}
+
+namespace Request {
+  export function is(value: any): value is Request<any, any> {
+    let candidate: Request<any, any> = value
+    return (
+      candidate &&
+      !!candidate.token &&
+      !!candidate.resolve &&
+      !!candidate.reject
+    )
+  }
+}
+
+interface Notifcation<P> {
+  method: string
+  params: P
+  documentVersion: number
+}
+
+type Message<P, R> = Notifcation<P> | Request<P, R>
+
+type VersionProvider<P> = (params: P) => number
+
+namespace Thenable {
+  export function is<T>(value: any): value is Thenable<T> {
+    let candidate: Thenable<T> = value
+    return candidate && typeof candidate.then === 'function'
+  }
+}
+
+class BufferedMessageQueue {
+  private queue: Message<any, any>[]
+  private requestHandlers: Map<
+    string,
+    {
+      handler: RequestHandler<any, any, any>
+      versionProvider?: VersionProvider<any>
+    }
+  >
+  private notificationHandlers: Map<
+    string,
+    { handler: NotificationHandler<any>; versionProvider?: VersionProvider<any> }
+  >
+  private timer: NodeJS.Immediate | undefined
+
+  constructor(private connection: IConnection) {
+    this.queue = []
+    this.requestHandlers = new Map()
+    this.notificationHandlers = new Map()
+  }
+
+  public registerRequest<P, R, E, RO>(
+    type: RequestType<P, R, E, RO>,
+    handler: RequestHandler<P, R, E>,
+    versionProvider?: VersionProvider<P>
+  ): void {
+    this.connection.onRequest(type, (params, token) => {
+      return new Promise<R>((resolve, reject) => {
+        this.queue.push({
+          method: type.method,
+          params,
+          documentVersion: versionProvider
+            ? versionProvider(params)
+            : undefined,
+          resolve,
+          reject,
+          token
+        })
+        this.trigger()
+      })
+    })
+    this.requestHandlers.set(type.method, { handler, versionProvider })
+  }
+
+  public registerNotification<P, RO>(
+    type: NotificationType<P, RO>,
+    handler: NotificationHandler<P>,
+    versionProvider?: (params: P) => number
+  ): void {
+    connection.onNotification(type, params => {
+      this.queue.push({
+        method: type.method,
+        params,
+        documentVersion: versionProvider ? versionProvider(params) : undefined
+      })
+      this.trigger()
+    })
+    this.notificationHandlers.set(type.method, { handler, versionProvider })
+  }
+
+  public addNotificationMessage<P, RO>(
+    type: NotificationType<P, RO>,
+    params: P,
+    version: number
+  ): void {
+    this.queue.push({
+      method: type.method,
+      params,
+      documentVersion: version
+    })
+    this.trigger()
+  }
+
+  public onNotification<P, RO>(
+    type: NotificationType<P, RO>,
+    handler: NotificationHandler<P>,
+    versionProvider?: (params: P) => number
+  ): void {
+    this.notificationHandlers.set(type.method, { handler, versionProvider })
+  }
+
+  private trigger(): void {
+    if (this.timer || this.queue.length === 0) {
+      return
+    }
+    this.timer = setImmediate(() => {
+      this.timer = undefined
+      this.processQueue()
+    })
+  }
+
+  private processQueue(): void {
+    let message = this.queue.shift()
+    if (!message) {
+      return
+    }
+    if (Request.is(message)) {
+      let requestMessage = message
+      if (requestMessage.token.isCancellationRequested) {
+        requestMessage.reject(
+          // tslint:disable-next-line: no-inferred-empty-object-type
+          new ResponseError(
+            ErrorCodes.RequestCancelled,
+            'Request got cancelled'
+          )
+        )
+        return
+      }
+      let elem = this.requestHandlers.get(requestMessage.method)
+      if (
+        elem.versionProvider &&
+        requestMessage.documentVersion !== void 0 &&
+        requestMessage.documentVersion !==
+        elem.versionProvider(requestMessage.params)
+      ) {
+        requestMessage.reject(
+          // tslint:disable-next-line: no-inferred-empty-object-type
+          new ResponseError(
+            ErrorCodes.RequestCancelled,
+            'Request got cancelled'
+          )
+        )
+        return
+      }
+      let result = elem.handler(requestMessage.params, requestMessage.token)
+      if (Thenable.is(result)) {
+        result.then(
+          value => {
+            requestMessage.resolve(value)
+          },
+          error => {
+            requestMessage.reject(error)
+          }
+        )
+      } else {
+        requestMessage.resolve(result)
+      }
+    } else {
+      let notificationMessage = message
+      let elem = this.notificationHandlers.get(notificationMessage.method)
+      if (
+        elem.versionProvider &&
+        notificationMessage.documentVersion !== void 0 &&
+        notificationMessage.documentVersion !==
+        elem.versionProvider(notificationMessage.params)
+      ) {
+        return
+      }
+      elem.handler(notificationMessage.params)
+    }
+    this.trigger()
+  }
+}
+
+let messageQueue: BufferedMessageQueue = new BufferedMessageQueue(connection)
+
+namespace ValidateNotification {
+  export const type: NotificationType<
+    TextDocument,
+    void
+  > = new NotificationType<TextDocument, void>('eslint/validate')
+}
+
+messageQueue.onNotification(
+  ValidateNotification.type,
+  document => {
+    validateSingle(document, true)
+  },
+  (document): number => {
+    return document.version
+  }
+)
+
+// The documents manager listen for text document create, change
+// and close on the connection
+documents.listen(connection)
+documents.onDidOpen(event => {
+  resolveSettings(event.document).then(settings => {
+    if (!settings.validate) {
+      return
+    }
+    if (settings.run === 'onSave') {
+      messageQueue.addNotificationMessage(
+        ValidateNotification.type,
+        event.document,
+        event.document.version
+      )
+    }
+  })
+})
+
+// A text document has changed. Validate the document according the run setting.
+documents.onDidChangeContent(event => {
+  resolveSettings(event.document).then(settings => {
+    if (!settings.validate || settings.run !== 'onType') {
+      return
+    }
+    messageQueue.addNotificationMessage(
+      ValidateNotification.type,
+      event.document,
+      event.document.version
+    )
+  })
+})
+
+documents.onWillSaveWaitUntil(event => {
+  if (event.reason === TextDocumentSaveReason.AfterDelay) {
+    return []
+  }
+
+  let document = event.document
+  return resolveSettings(document).then(settings => {
+    if (!settings.autoFixOnSave) {
+      return []
+    }
+    // If we validate on save and want to apply fixes on will save
+    // we need to validate the file.
+    if (settings.run === 'onSave') {
+      // Do not queue this since we want to get the fixes as fast as possible.
+      return validateSingle(document, false).then(() => getAllFixEdits(document, settings))
+    } else {
+      return getAllFixEdits(document, settings)
+    }
+  })
+})
+
+// A text document has been saved. Validate the document according the run setting.
+documents.onDidSave(event => {
+  resolveSettings(event.document).then(settings => {
+    if (!settings.validate || settings.run !== 'onSave') {
+      return
+    }
+    messageQueue.addNotificationMessage(
+      ValidateNotification.type,
+      event.document,
+      event.document.version
+    )
+  })
+})
+
+documents.onDidClose(event => {
+  resolveSettings(event.document).then(settings => {
+    let uri = event.document.uri
+    document2Settings.delete(uri)
+    codeActions.delete(uri)
+    if (settings.validate) {
+      connection.sendDiagnostics({ uri, diagnostics: [] })
+    }
+  })
+})
+
+function environmentChanged(): void {
+  document2Settings.clear()
+  for (let document of documents.all()) {
+    messageQueue.addNotificationMessage(
+      ValidateNotification.type,
+      document,
+      document.version
+    )
+  }
+}
+
+function trace(message: string, verbose?: string): void {
+  connection.tracer.log(message, verbose)
+}
+
+connection.onInitialize(_params => {
+  return {
+    capabilities: {
+      textDocumentSync: {
+        openClose: true,
+        change: TextDocumentSyncKind.Full,
+        willSaveWaitUntil: true,
+        save: {
+          includeText: false
+        }
+      },
+      codeActionProvider: true,
+      executeCommandProvider: {
+        commands: [
+          CommandIds.applySingleFix,
+          CommandIds.applySameFixes,
+          CommandIds.applyAllFixes,
+          CommandIds.applyAutoFix,
+          CommandIds.applyDisableLine,
+          CommandIds.applyDisableFile,
+          CommandIds.openRuleDoc,
+        ]
+      }
+    }
+  }
+})
+
+connection.onInitialized(() => {
+  connection.client.register(DidChangeConfigurationNotification.type, undefined)
+})
+
+messageQueue.registerNotification(
+  DidChangeConfigurationNotification.type,
+  _params => {
+    environmentChanged()
+  }
+)
+
+// messageQueue.registerNotification(
+//   DidChangeWorkspaceFoldersNotification.type,
+//   _params => {
+//     environmentChanged()
+//   }
+// )
+
+const singleErrorHandlers: ((
+  error: any,
+  document: TextDocument,
+  library: ESLintModule
+) => Status)[] = [
+    tryHandleNoConfig,
+    tryHandleConfigError,
+    tryHandleMissingModule,
+    showErrorMessage
+  ]
+
+function validateSingle(
+  document: TextDocument,
+  publishDiagnostics = true
+): Thenable<void> {
+  // We validate document in a queue but open / close documents directly. So we need to deal with the
+  // fact that a document might be gone from the server.
+  if (!documents.get(document.uri)) {
+    return Promise.resolve(undefined)
+  }
+  return resolveSettings(document).then(settings => {
+    if (!settings.validate) {
+      return
+    }
+    try {
+      validate(document, settings, publishDiagnostics)
+      connection.sendNotification(StatusNotification.type, { state: Status.ok })
+    } catch (err) {
+      let status
+      for (let handler of singleErrorHandlers) {
+        status = handler(err, document, settings.library)
+        if (status) {
+          break
+        }
+      }
+      status = status || Status.error
+      connection.sendNotification(StatusNotification.type, { state: status })
+    }
+  })
+}
+
+function validateMany(documents: TextDocument[]): void {
+  documents.forEach(document => {
+    messageQueue.addNotificationMessage(
+      ValidateNotification.type,
+      document,
+      document.version
+    )
+  })
+}
+
+function getMessage(err: any, document: TextDocument): string {
+  let result: string = null
+  if (typeof err.message === 'string' || err.message instanceof String) {
+    result = err.message as string
+    result = result.replace(/\r?\n/g, ' ')
+    if (/^CLI: /.test(result)) {
+      result = result.substr(5)
+    }
+  } else {
+    result = `An unknown error occured while validating document: ${
+      document.uri
+      }`
+  }
+  return result
+}
+
+function validate(document: TextDocument, settings: TextDocumentSettings, publishDiagnostics = true): void {
+  const uri = document.uri
+  const content = document.getText()
+  const newOptions: CLIOptions = Object.assign(Object.create(null), settings.options)
+  executeInWorkspaceDirectory(document, settings, newOptions, (file: string, options: CLIOptions) => {
+    const cli = new settings.library.CLIEngine(options)
+    // Clean previously computed code actions.
+    codeActions.delete(uri)
+    const report: ESLintReport = cli.executeOnText(content, file)
+    const diagnostics: Diagnostic[] = []
+    if (report && report.results && Array.isArray(report.results) && report.results.length > 0) {
+      const docReport = report.results[0]
+      if (docReport.messages && Array.isArray(docReport.messages)) {
+        docReport.messages.forEach(problem => {
+          if (problem) {
+            const isWarning = convertSeverity(problem.severity) === DiagnosticSeverity.Warning
+            if (settings.quiet && isWarning) {
+              // Filter out warnings when quiet mode is enabled
+              return
+            }
+            const diagnostic = makeDiagnostic(problem)
+            diagnostics.push(diagnostic)
+            if (settings.autoFix) {
+              if (typeof cli.getRules === 'function' && problem.ruleId !== undefined && problem.fix !== undefined) {
+                const rule = cli.getRules().get(problem.ruleId)
+                if (rule !== undefined && rule.meta && typeof rule.meta.fixable == 'string') {
+                  recordCodeAction(document, diagnostic, problem)
+                }
+              } else {
+                recordCodeAction(document, diagnostic, problem)
+              }
+            }
+          }
+        })
+      }
+    }
+    if (publishDiagnostics) {
+      connection.sendDiagnostics({ uri, diagnostics })
+    }
+
+    // cache documentation urls for all rules
+    if (typeof cli.getRules === 'function' && !ruleDocData.handled.has(uri)) {
+      ruleDocData.handled.add(uri)
+      cli.getRules().forEach((rule, key) => {
+        if (rule.meta && rule.meta.docs && Is.string(rule.meta.docs.url)) {
+          ruleDocData.urls.set(key, rule.meta.docs.url)
+        }
+      })
+    }
+  })
+}
+
+let noConfigReported: Map<string, ESLintModule> = new Map<
+  string,
+  ESLintModule
+>()
+
+function isNoConfigFoundError(error: any): boolean {
+  let candidate = error as ESLintError
+  return (
+    candidate.messageTemplate === 'no-config-found' ||
+    candidate.message === 'No ESLint configuration found.'
+  )
+}
+
+function tryHandleNoConfig(
+  error: any,
+  document: TextDocument,
+  library: ESLintModule
+): Status {
+  if (!isNoConfigFoundError(error)) {
+    return undefined
+  }
+  if (!noConfigReported.has(document.uri)) {
+    connection
+      .sendRequest(NoConfigRequest.type, {
+        message: getMessage(error, document),
+        document: {
+          uri: document.uri
+        }
+      })
+      .then(undefined, () => {
+        // noop
+      })
+    noConfigReported.set(document.uri, library)
+  }
+  return Status.warn
+}
+
+let configErrorReported: Map<string, ESLintModule> = new Map<
+  string,
+  ESLintModule
+>()
+
+function tryHandleConfigError(
+  error: any,
+  document: TextDocument,
+  library: ESLintModule
+): Status {
+  if (!error.message) {
+    return undefined
+  }
+
+  function handleFileName(filename: string): Status {
+    if (!configErrorReported.has(filename)) {
+      connection.console.error(getMessage(error, document))
+      if (!documents.get(URI.file(filename).toString())) {
+        connection.window.showInformationMessage(getMessage(error, document))
+      }
+      configErrorReported.set(filename, library)
+    }
+    return Status.warn
+  }
+
+  let matches = /Cannot read config file:\s+(.*)\nError:\s+(.*)/.exec(
+    error.message
+  )
+  if (matches && matches.length === 3) {
+    return handleFileName(matches[1])
+  }
+
+  matches = /(.*):\n\s*Configuration for rule \"(.*)\" is /.exec(error.message)
+  if (matches && matches.length === 3) {
+    return handleFileName(matches[1])
+  }
+
+  matches = /Cannot find module '([^']*)'\nReferenced from:\s+(.*)/.exec(
+    error.message
+  )
+  if (matches && matches.length === 3) {
+    return handleFileName(matches[2])
+  }
+
+  return undefined
+}
+
+let missingModuleReported: Map<string, ESLintModule> = new Map<
+  string,
+  ESLintModule
+>()
+
+function tryHandleMissingModule(
+  error: any,
+  document: TextDocument,
+  library: ESLintModule
+): Status {
+  if (!error.message) {
+    return undefined
+  }
+
+  function handleMissingModule(
+    plugin: string,
+    module: string,
+    error: ESLintError
+  ): Status {
+    if (!missingModuleReported.has(plugin)) {
+      let fsPath = getFilePath(document)
+      missingModuleReported.set(plugin, library)
+      if (error.messageTemplate === 'plugin-missing') {
+        connection.console.error(
+          [
+            '',
+            `${error.message.toString()}`,
+            `Happened while validating ${fsPath ? fsPath : document.uri}`,
+            `This can happen for a couple of reasons:`,
+            `1. The plugin name is spelled incorrectly in an ESLint configuration file (e.g. .eslintrc).`,
+            `2. If ESLint is installed globally, then make sure ${module} is installed globally as well.`,
+            `3. If ESLint is installed locally, then ${module} isn't installed correctly.`,
+            '',
+            `Consider running eslint --debug ${
+            fsPath ? fsPath : document.uri
+            } from a terminal to obtain a trace about the configuration files used.`
+          ].join('\n')
+        )
+      } else {
+        connection.console.error(
+          [
+            `${error.message.toString()}`,
+            `Happend while validating ${fsPath ? fsPath : document.uri}`
+          ].join('\n')
+        )
+      }
+    }
+    return Status.warn
+  }
+
+  let matches = /Failed to load plugin (.*): Cannot find module (.*)/.exec(
+    error.message
+  )
+  if (matches && matches.length === 3) {
+    return handleMissingModule(matches[1], matches[2], error)
+  }
+
+  return undefined
+}
+
+function showErrorMessage(error: any, document: TextDocument): Status {
+  connection.window.showErrorMessage(
+    `ESLint: ${getMessage(
+      error,
+      document
+    )}. Please see the 'ESLint' output channel for details.`
+  )
+  if (Is.string(error.stack)) {
+    connection.console.error('ESLint stack trace:')
+    connection.console.error(error.stack)
+  }
+  return Status.error
+}
+
+messageQueue.registerNotification(
+  DidChangeWatchedFilesNotification.type,
+  params => {
+    // A .eslintrc has change. No smartness here.
+    // Simply revalidate all file.
+    noConfigReported = new Map<string, ESLintModule>()
+    missingModuleReported = new Map<string, ESLintModule>()
+    params.changes.forEach(change => {
+      let fsPath = getFilePath(change.uri)
+      if (!fsPath || isUNC(fsPath)) {
+        return
+      }
+      let dirname = path.dirname(fsPath)
+      if (dirname) {
+        let library = configErrorReported.get(fsPath)
+        if (library) {
+          let cli = new library.CLIEngine({})
+          try {
+            cli.executeOnText('', path.join(dirname, '___test___.js'))
+            configErrorReported.delete(fsPath)
+          } catch (error) {
+            // noop
+          }
+        }
+      }
+    })
+    validateMany(documents.all())
+  }
+)
+
+class Fixes {
+  constructor(private edits: Map<string, FixableProblem>) { }
+
+  public static overlaps(lastEdit: FixableProblem, newEdit: FixableProblem): boolean {
+    return !!lastEdit && lastEdit.edit.range[1] > newEdit.edit.range[0]
+  }
+
+  public isEmpty(): boolean {
+    return this.edits.size === 0
+  }
+
+  public getDocumentVersion(): number {
+    if (this.isEmpty()) {
+      throw new Error('No edits recorded.')
+    }
+    return this.edits.values().next().value.documentVersion
+  }
+
+  public getScoped(diagnostics: Diagnostic[]): FixableProblem[] {
+    let result: FixableProblem[] = []
+    for (let diagnostic of diagnostics) {
+      let key = computeKey(diagnostic)
+      let editInfo = this.edits.get(key)
+      if (editInfo) {
+        result.push(editInfo)
+      }
+    }
+    return result
+  }
+
+  public getAllSorted(): FixableProblem[] {
+    let result: FixableProblem[] = []
+    this.edits.forEach(value => result.push(value))
+    return result.sort((a, b) => {
+      let d = a.edit.range[0] - b.edit.range[0]
+      if (d !== 0) {
+        return d
+      }
+      if (a.edit.range[1] === 0) {
+        return -1
+      }
+      if (b.edit.range[1] === 0) {
+        return 1
+      }
+      return a.edit.range[1] - b.edit.range[1]
+    })
+  }
+
+  public getOverlapFree(): FixableProblem[] {
+    let sorted = this.getAllSorted()
+    if (sorted.length <= 1) {
+      return sorted
+    }
+    let result: FixableProblem[] = []
+    let last: FixableProblem = sorted[0]
+    result.push(last)
+    for (let i = 1; i < sorted.length; i++) {
+      let current = sorted[i]
+      if (!Fixes.overlaps(last, current)) {
+        result.push(current)
+        last = current
+      }
+    }
+    return result
+  }
+}
+
+let commands: Map<string, WorkspaceChange>
+messageQueue.registerRequest(
+  CodeActionRequest.type,
+  params => {
+    commands = new Map<string, WorkspaceChange>()
+    let result: CodeActionResult = new CodeActionResult()
+    let uri = params.textDocument.uri
+    let edits = codeActions.get(uri)
+    if (!edits) return []
+    let fixes = new Fixes(edits)
+    if (fixes.isEmpty()) return []
+
+    let textDocument = documents.get(uri)
+    let documentVersion = -1
+    let allFixableRuleIds: string[] = []
+
+    function createTextEdit(editInfo: FixableProblem): TextEdit {
+      return TextEdit.replace(Range.create(textDocument.positionAt(editInfo.edit.range[0]), textDocument.positionAt(editInfo.edit.range[1])), editInfo.edit.text || '')
+    }
+
+    function createDisableLineTextEdit(editInfo: FixableProblem, indentationText: string): TextEdit {
+      return TextEdit.insert(Position.create(editInfo.line - 1, 0), `${indentationText}// eslint-disable-next-line ${editInfo.ruleId}\n`)
+    }
+
+    function createDisableSameLineTextEdit(editInfo: FixableProblem): TextEdit {
+      return TextEdit.insert(Position.create(editInfo.line - 1, Number.MAX_VALUE), ` // eslint-disable-line ${editInfo.ruleId}`)
+    }
+
+    function createDisableFileTextEdit(editInfo: FixableProblem): TextEdit {
+      return TextEdit.insert(Position.create(0, 0), `/* eslint-disable ${editInfo.ruleId} */\n`)
+    }
+
+    function getLastEdit(array: FixableProblem[]): FixableProblem {
+      let length = array.length
+      if (length === 0) {
+        return undefined
+      }
+      return array[length - 1]
+    }
+
+    return resolveSettings(textDocument).then(settings => {
+      for (let editInfo of fixes.getScoped(params.context.diagnostics)) {
+        documentVersion = editInfo.documentVersion
+        let ruleId = editInfo.ruleId
+        allFixableRuleIds.push(ruleId)
+
+        if (!!editInfo.edit) {
+          let workspaceChange = new WorkspaceChange()
+          workspaceChange.getTextEditChange({ uri, version: documentVersion }).add(createTextEdit(editInfo))
+          commands.set(`${CommandIds.applySingleFix}:${ruleId}`, workspaceChange)
+          result.get(ruleId).fixes.push(CodeAction.create(
+            editInfo.label,
+            Command.create(editInfo.label, CommandIds.applySingleFix, ruleId),
+            CodeActionKind.QuickFix
+          ))
+        }
+
+        if (settings.codeAction.disableRuleComment.enable) {
+          let workspaceChange = new WorkspaceChange()
+          if (settings.codeAction.disableRuleComment.location === 'sameLine') {
+            workspaceChange.getTextEditChange({ uri, version: documentVersion }).add(createDisableSameLineTextEdit(editInfo))
+          } else {
+            let lineText = textDocument.getText(Range.create(Position.create(editInfo.line - 1, 0), Position.create(editInfo.line - 1, Number.MAX_VALUE)))
+            let indentationText = /^([ \t]*)/.exec(lineText)[1]
+            workspaceChange.getTextEditChange({ uri, version: documentVersion }).add(createDisableLineTextEdit(editInfo, indentationText))
+          }
+          commands.set(`${CommandIds.applyDisableLine}:${ruleId}`, workspaceChange)
+          let title = `Disable ${ruleId} for this line`
+          result.get(ruleId).disable = CodeAction.create(
+            title,
+            Command.create(title, CommandIds.applyDisableLine, ruleId),
+            CodeActionKind.QuickFix
+          )
+
+          if (result.get(ruleId).disableFile === undefined) {
+            workspaceChange = new WorkspaceChange()
+            workspaceChange.getTextEditChange({ uri, version: documentVersion }).add(createDisableFileTextEdit(editInfo))
+            commands.set(`${CommandIds.applyDisableFile}:${ruleId}`, workspaceChange)
+            title = `Disable ${ruleId} for the entire file`
+            result.get(ruleId).disableFile = CodeAction.create(
+              title,
+              Command.create(title, CommandIds.applyDisableFile, ruleId),
+              CodeActionKind.QuickFix
+            )
+          }
+        }
+
+        if (settings.codeAction.showDocumentation.enable && result.get(ruleId).showDocumentation === undefined) {
+          if (ruleDocData.urls.has(ruleId)) {
+            let title = `Show documentation for ${ruleId}`
+            result.get(ruleId).showDocumentation = CodeAction.create(
+              title,
+              Command.create(title, CommandIds.openRuleDoc, ruleId),
+              CodeActionKind.QuickFix
+            )
+          }
+        }
+      }
+
+      if (result.length > 0) {
+        let sameProblems: Map<string, FixableProblem[]> = new Map<string, FixableProblem[]>(allFixableRuleIds.map<[string, FixableProblem[]]>(s => [s, []]))
+        let all: FixableProblem[] = []
+
+        for (let editInfo of fixes.getAllSorted()) {
+          if (documentVersion === -1) {
+            documentVersion = editInfo.documentVersion
+          }
+          if (sameProblems.has(editInfo.ruleId)) {
+            let same = sameProblems.get(editInfo.ruleId)
+            if (!Fixes.overlaps(getLastEdit(same), editInfo)) {
+              same.push(editInfo)
+            }
+          }
+          if (!Fixes.overlaps(getLastEdit(all), editInfo)) {
+            all.push(editInfo)
+          }
+        }
+        sameProblems.forEach((same, ruleId) => {
+          if (same.length > 1) {
+            let sameFixes: WorkspaceChange = new WorkspaceChange()
+            let sameTextChange = sameFixes.getTextEditChange({ uri, version: documentVersion })
+            same.map(createTextEdit).forEach(edit => sameTextChange.add(edit))
+            commands.set(CommandIds.applySameFixes, sameFixes)
+            let title = `Fix all ${ruleId} problems`
+            let command = Command.create(title, CommandIds.applySameFixes)
+            result.get(ruleId).fixAll = CodeAction.create(
+              title,
+              command,
+              CodeActionKind.QuickFix
+            )
+          }
+        })
+        if (all.length > 1) {
+          let allFixes: WorkspaceChange = new WorkspaceChange()
+          let allTextChange = allFixes.getTextEditChange({ uri, version: documentVersion })
+          all.map(createTextEdit).forEach(edit => allTextChange.add(edit))
+          commands.set(CommandIds.applyAllFixes, allFixes)
+          let title = `Fix all auto-fixable problems`
+          let command = Command.create(title, CommandIds.applyAllFixes)
+          result.fixAll = CodeAction.create(
+            title,
+            command,
+            CodeActionKind.SourceFixAll
+          )
+        }
+      }
+      return result.all()
+    })
+  },
+  (params): number => {
+    let document = documents.get(params.textDocument.uri)
+    return document ? document.version : undefined
+  }
+)
+
+messageQueue.registerRequest(
+  ExecuteCommandRequest.type,
+  async params => {
+    let workspaceChange: WorkspaceChange
+    if (params.command === CommandIds.applyAutoFix) {
+      let identifier: VersionedTextDocumentIdentifier = params.arguments[0]
+      if (!identifier.uri.startsWith('file:')) {
+        return {}
+      }
+      let textDocument = documents.get(identifier.uri)
+      let settings = await Promise.resolve(resolveSettings(textDocument))
+      let edits = getAllFixEdits(textDocument, settings)
+      if (edits && edits.length) {
+        workspaceChange = new WorkspaceChange()
+        let textChange = workspaceChange.getTextEditChange(identifier)
+        edits.forEach(edit => textChange.add(edit))
+      }
+    } else {
+      if ([CommandIds.applySingleFix, CommandIds.applyDisableLine, CommandIds.applyDisableFile].indexOf(params.command) !== -1) {
+        let ruleId = params.arguments[0]
+        workspaceChange = commands.get(`${params.command}:${ruleId}`)
+      } else if (params.command === CommandIds.openRuleDoc) {
+        let ruleId = params.arguments[0]
+        let url = ruleDocData.urls.get(ruleId)
+        if (url) {
+          await connection.sendRequest(OpenESLintDocRequest.type, { url })
+        }
+      } else {
+        workspaceChange = commands.get(params.command)
+      }
+    }
+
+    if (!workspaceChange) {
+      return {}
+    }
+    try {
+      let response = await Promise.resolve(connection.workspace.applyEdit(workspaceChange.edit))
+      if (!response.applied) {
+        connection.console.error(`Failed to apply command: ${params.command}`)
+      }
+    } catch (e) {
+      connection.console.error(`Failed to apply command: ${params.command}`)
+    }
+    return {}
+  },
+  (params): number => {
+    if (params.command === CommandIds.applyAutoFix) {
+      let identifier: VersionedTextDocumentIdentifier = params.arguments[0]
+      return identifier.version
+    } else {
+      return undefined
+    }
+  }
+)
+
+connection.tracer.connection.listen()