UNPKG

@microsoft/compose-language-service

Version:
208 lines 10.2 kB
"use strict"; /*!-------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See LICENSE in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); exports.ComposeLanguageService = void 0; const vscode_languageserver_1 = require("vscode-languageserver"); const DocumentSettings_1 = require("../client/DocumentSettings"); const TelemetryEvent_1 = require("../client/TelemetryEvent"); const ComposeDocument_1 = require("./ComposeDocument"); const MultiCompletionProvider_1 = require("./providers/completion/MultiCompletionProvider"); const DiagnosticProvider_1 = require("./providers/DiagnosticProvider"); const DocumentFormattingProvider_1 = require("./providers/DocumentFormattingProvider"); const ImageLinkProvider_1 = require("./providers/ImageLinkProvider"); const KeyHoverProvider_1 = require("./providers/KeyHoverProvider"); const ServiceStartupCodeLensProvider_1 = require("./providers/ServiceStartupCodeLensProvider"); const ActionContext_1 = require("./utils/ActionContext"); const TelemetryAggregator_1 = require("./utils/telemetry/TelemetryAggregator"); const DefaultCapabilities = { // Text document synchronization textDocumentSync: { openClose: true, change: vscode_languageserver_1.TextDocumentSyncKind.Incremental, willSave: false, willSaveWaitUntil: false, save: false, }, // Both basic and advanced completions completionProvider: { triggerCharacters: ['-', ':', ' ', '"'], resolveProvider: false, }, // Code lenses for starting services codeLensProvider: { resolveProvider: false, }, // Hover over YAML keys hoverProvider: true, // Links to Docker Hub on image names documentLinkProvider: { resolveProvider: false, }, // YAML formatting documentFormattingProvider: true, // Workspace features workspace: { workspaceFolders: { supported: true, }, }, }; // Default settings for a client with no alternate YAML language service const DefaultAlternateYamlLanguageServiceClientCapabilities = { syntaxValidation: false, schemaValidation: false, basicCompletions: false, advancedCompletions: false, serviceStartupCodeLens: false, hover: false, imageLinks: false, formatting: false, }; class ComposeLanguageService { constructor(connection, clientParams) { var _a, _b, _c; this.connection = connection; this.clientParams = clientParams; this.documentManager = new vscode_languageserver_1.TextDocuments(ComposeDocument_1.ComposeDocument.DocumentManagerConfig); this.subscriptions = []; this._capabilities = DefaultCapabilities; let altYamlCapabilities = (_a = clientParams.capabilities.experimental) === null || _a === void 0 ? void 0 : _a.alternateYamlLanguageService; if (altYamlCapabilities) { connection.console.info('An alternate YAML language service is present. The Compose language service will not enable features already provided by the alternate.'); } else { altYamlCapabilities = DefaultAlternateYamlLanguageServiceClientCapabilities; } // Hook up the document listeners, which create a Disposable which will be added to this.subscriptions if (altYamlCapabilities.syntaxValidation && altYamlCapabilities.schemaValidation) { // Noop. No server-side capability needs to be set for diagnostics because it is based on pushing from server to client. } else { this.createDocumentManagerHandler(this.documentManager.onDidChangeContent, new DiagnosticProvider_1.DiagnosticProvider((_b = clientParams.initializationOptions) === null || _b === void 0 ? void 0 : _b.diagnosticDelay, !altYamlCapabilities.syntaxValidation, !altYamlCapabilities.schemaValidation)); } // End of document listeners // Hook up all the applicable LSP listeners, which do not create Disposables for some reason if (altYamlCapabilities.basicCompletions && altYamlCapabilities.advancedCompletions) { this._capabilities.completionProvider = undefined; } else { this.createLspHandler(this.connection.onCompletion, new MultiCompletionProvider_1.MultiCompletionProvider(!altYamlCapabilities.basicCompletions, !altYamlCapabilities.advancedCompletions)); } if (altYamlCapabilities.serviceStartupCodeLens) { this._capabilities.codeLensProvider = undefined; } else { this.createLspHandler(this.connection.onCodeLens, new ServiceStartupCodeLensProvider_1.ServiceStartupCodeLensProvider()); } if (altYamlCapabilities.hover) { this._capabilities.hoverProvider = undefined; } else { this.createLspHandler(this.connection.onHover, new KeyHoverProvider_1.KeyHoverProvider()); } if (altYamlCapabilities.imageLinks) { this._capabilities.documentLinkProvider = undefined; } else { this.createLspHandler(this.connection.onDocumentLinks, new ImageLinkProvider_1.ImageLinkProvider()); } if (altYamlCapabilities.formatting) { this._capabilities.documentFormattingProvider = undefined; } else { this.createLspHandler(this.connection.onDocumentFormatting, new DocumentFormattingProvider_1.DocumentFormattingProvider()); } // End of LSP listeners // Hook up one additional notification handler this.connection.onNotification(DocumentSettings_1.DocumentSettingsNotification.method, (params) => this.onDidChangeDocumentSettings(params)); // Start the document listener this.documentManager.listen(this.connection); // Start the telemetry aggregator this.subscriptions.push(this.telemetryAggregator = new TelemetryAggregator_1.TelemetryAggregator(this.connection, (_c = clientParams.initializationOptions) === null || _c === void 0 ? void 0 : _c.telemetryAggregationInterval)); } dispose() { for (const subscription of this.subscriptions) { subscription.dispose(); } } get capabilities() { return this._capabilities; } onDidChangeDocumentSettings(params) { // TODO: Telemetrize this? const composeDoc = this.documentManager.get(params.textDocument.uri); if (composeDoc) { composeDoc.updateSettings(params); } } createLspHandler(event, handler) { event(async (params, token, workDoneProgress, resultProgress) => { return await this.callWithTelemetryAndErrorHandling(handler.constructor.name, async () => { const doc = this.documentManager.get(params.textDocument.uri); if (!doc) { throw new vscode_languageserver_1.ResponseError(vscode_languageserver_1.ErrorCodes.InvalidParams, 'Document not found in cache.'); } const extendedParams = { ...params, document: doc, }; return await Promise.resolve(handler.on(extendedParams, token, workDoneProgress, resultProgress)); }); }); } createDocumentManagerHandler(event, handler) { event(async (params) => { return await this.callWithTelemetryAndErrorHandling(handler.constructor.name, async () => { const extendedParams = { ...params, textDocument: params.document.id, }; return await Promise.resolve(handler.on(extendedParams, vscode_languageserver_1.CancellationToken.None)); }); }, this, this.subscriptions); } async callWithTelemetryAndErrorHandling(callbackId, callback) { const actionContext = { clientCapabilities: this.clientParams.capabilities, connection: this.connection, telemetry: (0, TelemetryEvent_1.initEvent)(callbackId), }; const startTime = process.hrtime.bigint(); try { return await (0, ActionContext_1.runWithContext)(actionContext, callback); } catch (error) { let responseError; let stack; if (error instanceof vscode_languageserver_1.ResponseError) { responseError = error; stack = error.stack; } else if (error instanceof Error) { responseError = new vscode_languageserver_1.ResponseError(vscode_languageserver_1.ErrorCodes.UnknownErrorCode, error.message, error); stack = error.stack; } else { // eslint-disable-next-line @typescript-eslint/no-explicit-any responseError = new vscode_languageserver_1.ResponseError(vscode_languageserver_1.ErrorCodes.InternalError, error.toString ? error.toString() : 'Unknown error'); } actionContext.telemetry.properties.result = 'Failed'; actionContext.telemetry.properties.error = responseError.code.toString(); actionContext.telemetry.properties.errorMessage = responseError.message; actionContext.telemetry.properties.stack = stack; return responseError; } finally { const endTime = process.hrtime.bigint(); const elapsedMicroseconds = Number((endTime - startTime) / BigInt(1000)); actionContext.telemetry.measurements.duration = elapsedMicroseconds; // The aggregator will internally handle suppressing / etc. this.telemetryAggregator.logEvent(actionContext.telemetry); } } } exports.ComposeLanguageService = ComposeLanguageService; //# sourceMappingURL=ComposeLanguageService.js.map