flink-sql-language-server
Version:
A LSP-based language server for Apache Flink SQL
213 lines (212 loc) • 8.36 kB
JavaScript
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();
;