UNPKG

@microsoft/compose-language-service

Version:
252 lines 12.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. *--------------------------------------------------------------------------------------------*/ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.ComposeLanguageService = void 0; const util = __importStar(require("util")); const vscode_languageserver_1 = require("vscode-languageserver"); const DocumentSettingsClientCapabilities_1 = require("../common/DocumentSettingsClientCapabilities"); const TelemetryEvent_1 = require("../common/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 { connection; clientParams; documentManager = new vscode_languageserver_1.TextDocuments(ComposeDocument_1.ComposeDocument.DocumentManagerConfig); subscriptions = []; telemetryAggregator; _capabilities = DefaultCapabilities; constructor(connection, clientParams) { this.connection = connection; this.clientParams = clientParams; let altYamlCapabilities = clientParams.capabilities.experimental?.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 { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access this.createDocumentManagerHandler(this.documentManager.onDidChangeContent, new DiagnosticProvider_1.DiagnosticProvider(clientParams.initializationOptions?.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.bind(this), new MultiCompletionProvider_1.MultiCompletionProvider(!altYamlCapabilities.basicCompletions, !altYamlCapabilities.advancedCompletions)); } if (altYamlCapabilities.serviceStartupCodeLens) { this._capabilities.codeLensProvider = undefined; } else { this.createLspHandler(this.connection.onCodeLens.bind(this), new ServiceStartupCodeLensProvider_1.ServiceStartupCodeLensProvider()); } if (altYamlCapabilities.hover) { this._capabilities.hoverProvider = undefined; } else { this.createLspHandler(this.connection.onHover.bind(this), new KeyHoverProvider_1.KeyHoverProvider()); } if (altYamlCapabilities.imageLinks) { this._capabilities.documentLinkProvider = undefined; } else { this.createLspHandler(this.connection.onDocumentLinks.bind(this), new ImageLinkProvider_1.ImageLinkProvider()); } if (altYamlCapabilities.formatting) { this._capabilities.documentFormattingProvider = undefined; } else { this.createLspHandler(this.connection.onDocumentFormatting.bind(this), new DocumentFormattingProvider_1.DocumentFormattingProvider()); } // End of LSP listeners // Hook up one additional notification handler this.connection.onNotification(DocumentSettingsClientCapabilities_1.DocumentSettingsNotification.type, (params) => this.onDidChangeDocumentSettings(params)); // Start the document listener this.documentManager.listen(this.connection); // Start the telemetry aggregator // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access this.subscriptions.push(this.telemetryAggregator = new TelemetryAggregator_1.TelemetryAggregator(this.connection, clientParams.initializationOptions?.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, // The result (`R`) and error (`E`) types are inferred from the connection's // handler signature (via `NoInfer`) and the provider is validated against them. // The partial-result type (`PR`) is not cross-checked: the LSP connection types it // as the item type while providers use `never`, and those are contravariantly // incompatible even though the wrapper simply forwards the reporter unchanged. // eslint-disable-next-line @typescript-eslint/no-explicit-any 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 { responseError = new vscode_languageserver_1.ResponseError(vscode_languageserver_1.ErrorCodes.InternalError, util.inspect(error) || '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