UNPKG

typescript-language-server

Version:

Language Server Protocol (LSP) implementation for TypeScript using tsserver

165 lines 5.81 kB
/* * Copyright (C) 2017, 2018 TypeFox and others. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 */ import { platform } from 'node:os'; import * as path from 'node:path'; import * as fs from 'node:fs'; import { fileURLToPath } from 'node:url'; import deepmerge from 'deepmerge'; import * as lsp from 'vscode-languageserver'; import { TextDocument } from 'vscode-languageserver-textdocument'; import { normalizePath, pathToUri } from './protocol-translation.js'; import { LspServer } from './lsp-server.js'; import { ConsoleLogger } from './logger.js'; import { TypeScriptVersionProvider } from './tsServer/versionProvider.js'; const CONSOLE_LOG_LEVEL = ConsoleLogger.toMessageTypeLevel(process.env.CONSOLE_LOG_LEVEL); export const PACKAGE_ROOT = fileURLToPath(new URL('..', import.meta.url)); const DEFAULT_TEST_CLIENT_CAPABILITIES = { textDocument: { completion: { completionItem: { insertReplaceSupport: true, snippetSupport: true, labelDetailsSupport: true, }, }, documentSymbol: { hierarchicalDocumentSymbolSupport: true, }, publishDiagnostics: { tagSupport: { valueSet: [ lsp.DiagnosticTag.Unnecessary, lsp.DiagnosticTag.Deprecated, ], }, }, moniker: {}, }, }; const DEFAULT_TEST_CLIENT_INITIALIZATION_OPTIONS = { plugins: [], preferences: { allowIncompleteCompletions: true, allowRenameOfImportPath: true, allowTextChangesInNewFiles: true, displayPartsForJSDoc: true, generateReturnInDocTemplate: true, includeAutomaticOptionalChainCompletions: true, includeCompletionsForImportStatements: true, includeCompletionsForModuleExports: true, includeCompletionsWithClassMemberSnippets: true, includeCompletionsWithInsertText: true, includeCompletionsWithSnippetText: true, jsxAttributeCompletionStyle: 'auto', providePrefixAndSuffixTextForRename: true, }, }; export function uri(...components) { const resolved = filePath(...components); return pathToUri(resolved, undefined); } export function filePath(...components) { return normalizePath(path.resolve(PACKAGE_ROOT, 'test-data', ...components)); } export function readContents(path) { return fs.readFileSync(path, 'utf-8').toString(); } export function positionAt(document, idx) { const doc = TextDocument.create(document.uri, document.languageId, document.version, document.text); const pos = doc.positionAt(idx); return { line: pos.line, character: pos.character, }; } export function position(document, match) { return positionAt(document, document.text.indexOf(match)); } export function positionAfter(document, match) { return positionAt(document, document.text.indexOf(match) + match.length); } export function lastPosition(document, match) { return positionAt(document, document.text.lastIndexOf(match)); } export function toPlatformEOL(text) { if (platform() === 'win32') { return text.replace(/(?!\r)\n/g, '\r\n'); } return text; } export class TestLspClient { constructor(options, logger) { this.options = options; this.logger = logger; this.workspaceEditsListener = null; } async createProgressReporter(_token, _workDoneProgress) { const reporter = new class { begin(_title, _percentage, _message, _cancellable) { } report(_message) { } done() { } }; return reporter; } async withProgress(_options, task) { const progress = await this.createProgressReporter(); return await task(progress); } publishDiagnostics(args) { return this.options.publishDiagnostics(args); } showErrorMessage(message) { this.logger.error(`[showErrorMessage] ${message}`); } logMessage(args) { this.logger.log('logMessage', JSON.stringify(args)); } addApplyWorkspaceEditListener(listener) { this.workspaceEditsListener = listener; } async applyWorkspaceEdit(args) { if (this.workspaceEditsListener) { this.workspaceEditsListener(args); } return { applied: true }; } rename() { throw new Error('unsupported'); } } export class TestLspServer extends LspServer { constructor() { super(...arguments); this.workspaceEdits = []; } } export async function createServer(options) { const typescriptVersionProvider = new TypeScriptVersionProvider(); const bundled = typescriptVersionProvider.bundledVersion(); const logger = new ConsoleLogger(CONSOLE_LOG_LEVEL); const lspClient = new TestLspClient(options, logger); const server = new TestLspServer({ logger, tsserverPath: bundled.tsServerPath, tsserverLogVerbosity: options.tsserverLogVerbosity, tsserverLogFile: path.resolve(PACKAGE_ROOT, 'tsserver.log'), lspClient, }); lspClient.addApplyWorkspaceEditListener(args => { server.workspaceEdits.push(args); }); await server.initialize({ rootPath: undefined, rootUri: options.rootUri, processId: 42, capabilities: deepmerge(DEFAULT_TEST_CLIENT_CAPABILITIES, options.clientCapabilitiesOverride || {}), initializationOptions: DEFAULT_TEST_CLIENT_INITIALIZATION_OPTIONS, workspaceFolders: null, }); return server; } //# sourceMappingURL=test-utils.js.map