UNPKG

flink-sql-language-server

Version:

A LSP-based language server for Apache Flink SQL

213 lines (212 loc) 8.36 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const vscode_languageserver_1 = require("vscode-languageserver"); const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument"); const browser_1 = require("vscode-languageserver/browser"); const flinkdb_schema_json_1 = __importDefault(require("./assets/flinkdb.schema.json")); const constants_1 = require("./constants"); const execute_command_1 = require("./execute-command"); const lsp_server_1 = require("./lsp-server"); const protocol_translation_1 = require("./protocol-translation"); const messageReader = new browser_1.BrowserMessageReader(self); const messageWriter = new browser_1.BrowserMessageWriter(self); const connection = (0, browser_1.createConnection)(messageReader, messageWriter); connection.onInitialize(() => { const capabilities = { textDocumentSync: vscode_languageserver_1.TextDocumentSyncKind.Incremental, executeCommandProvider: { commands: [ constants_1.EXTRACT_SQL_STRUCTURE_COMMAND, constants_1.REGISTER_SCHEMAS_COMMAND, constants_1.PREVIEW_SCRIPT_COMMAND, constants_1.EXTRACT_SCHEMA_CONTEXTS_COMMAND, constants_1.COLLECT_TOKENS_COMMAND, constants_1.COLUMN_LEVEL_LINEAGE_COMMAND ] }, documentFormattingProvider: true, referencesProvider: true, hoverProvider: true, foldingRangeProvider: true, renameProvider: true, codeActionProvider: true, completionProvider: { triggerCharacters: '.1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''), resolveProvider: true } }; return { capabilities }; }); const documents = new vscode_languageserver_1.TextDocuments(vscode_languageserver_textdocument_1.TextDocument); const lspServer = new lsp_server_1.LSPServer(); documents.listen(connection); documents.onDidClose(e => { lspServer.warehouse.removeParsingValue(e.document.uri); }); documents.onDidChangeContent(change => { if (!lspServer.warehouse.hasParsingValue(change.document)) { lspServer.warehouse.setParsingValue(change.document); } else { const parseValueCache = lspServer.warehouse.getParsingValue(change.document); if (change.document.getText() === parseValueCache.origin) { return; } lspServer.warehouse.setParsingValue(change.document); } }); connection.onDidChangeWatchedFiles(() => { }); connection.onRequest(vscode_languageserver_1.DocumentDiagnosticRequest.type, params => { const textDocument = documents.get(params.textDocument.uri); if (!textDocument) { console.error('Language Server: TextDocument not found.'); return { kind: 'full', items: [] }; } const items = lspServer.doValidation(textDocument); return { kind: 'full', items }; }); connection.onCompletion((params) => { const { textDocument, position } = params; const document = documents.get(textDocument.uri); if (!document) { console.error('Language Server: TextDocument not found.'); return []; } return lspServer.doCompletion(document, position).completionItems; }); connection.onCompletionResolve((item) => { if (!item.detail) { item.detail = 'reserved keyword'; } return item; }); connection.onCodeAction((params) => { const actions = []; const diagnostics = params.context.diagnostics; if (!diagnostics.length) { return []; } const document = documents.get(params.textDocument.uri); if (!document) { console.error('Language Server: TextDocument not found.'); return []; } const kinds = params.context.only; if (kinds?.includes(vscode_languageserver_1.CodeActionKind.QuickFix)) { diagnostics.forEach(diagnostic => { const quickFixes = diagnostic.data?.suggestions .filter((s) => s !== 'EOF') .map((newText) => ({ title: `Cannot find name '${document.getText(diagnostic.range)}'. Do you mean '${newText}'?`, kind: vscode_languageserver_1.CodeActionKind.QuickFix, diagnostics: [diagnostic], edit: { changes: { [params.textDocument.uri]: [ { newText, range: diagnostic.range } ] } } })) || []; actions.push(...quickFixes); }); } return actions; }); connection.onDocumentFormatting((params) => { const document = documents.get(params.textDocument.uri); if (!document) { console.error('Language Server: TextDocument not found.'); return []; } return lspServer.doFormatting(document, params.options); }); connection.onReferences((params) => { const document = documents.get(params.textDocument.uri); if (!document) { console.error('Language Server: TextDocument not found.'); return []; } const semanticToken = lspServer .collectTokens(document) .semanticTokens.find(t => (0, protocol_translation_1.positionInRange)(document, params.position, t.range)); if (!semanticToken) { return []; } let references = lspServer.doReferences(document, params.position).map(reference => { return { uri: document.uri, range: reference }; }); documents .all() .filter(doc => doc.uri !== params.textDocument.uri) .forEach(doc => { const semanticTokens = lspServer.collectTokens(doc).semanticTokens; references = references.concat(semanticTokens .filter(t => (0, lsp_server_1.isSemanticTokenReference)(t, semanticToken)) .map(t => ({ uri: doc.uri, range: t.range }))); }); return references; }); connection.onHover((params) => { const document = documents.get(params.textDocument.uri); const contents = []; if (!document) { console.error('Language Server: TextDocument not found.'); return { contents }; } const token = lspServer.getTokenByPosition(document, params.position); if (token?.text === undefined) { return { contents }; } const functionItem = flinkdb_schema_json_1.default.functions.find(f => token.text.localeCompare(f.name, undefined, { sensitivity: 'accent' }) === 0); if (functionItem) { contents.push(`**System (Built-in) Function**`); contents.push(functionItem.description); contents.push(`For more information, please refer to [Flink Document](https://nightlies.apache.org/flink/flink-docs-release-1.20/docs/dev/table/functions/systemfunctions/).`); } return { contents }; }); connection.onFoldingRanges((params) => { const document = documents.get(params.textDocument.uri); if (!document) { console.error('Language Server: TextDocument not found.'); return []; } return lspServer.doFoldingRanges(document); }); connection.onRenameRequest((params) => { const document = documents.get(params.textDocument.uri); if (!document) { console.error('Language Server: TextDocument not found.'); return; } const semanticToken = lspServer .collectTokens(document) .semanticTokens.find(t => (0, protocol_translation_1.positionInRange)(document, params.position, t.range)); if (!semanticToken) { return; } const workspaceEdit = { changes: {} }; documents.all().forEach(doc => { const tokens = lspServer.collectTokens(doc).semanticTokens.filter(t => (0, lsp_server_1.isSemanticTokenReference)(t, semanticToken)); workspaceEdit.changes[doc.uri] = tokens.map(t => ({ newText: params.newName, range: t.range })); }); return workspaceEdit; }); connection.onExecuteCommand(params => (0, execute_command_1.handleExecuteCommand)(documents, lspServer, params)); connection.listen();