"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.osqueryTableNames = exports.keywords = exports.initializeOsqueryEditor = exports.getEditorAutoCompleteSuggestion = exports.dataTypes = exports.builtinFunctions = exports.builtinConstants = void 0; var _monaco = require("@kbn/monaco"); var _lodash = require("lodash"); var _osquery_tables = require("./osquery_tables"); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ const osqueryTableNames = (0, _osquery_tables.getOsqueryTableNames)(); exports.osqueryTableNames = osqueryTableNames; const keywords = ['select', 'insert', 'update', 'delete', 'from', 'where', 'and', 'or', 'group', 'by', 'order', 'limit', 'offset', 'having', 'as', 'case', 'when', 'else', 'end', 'type', 'left', 'right', 'join', 'on', 'outer', 'desc', 'asc', 'union', 'create', 'table', 'primary', 'key', 'if', 'foreign', 'not', 'references', 'default', 'null', 'inner', 'cross', 'natural', 'database', 'drop', 'grant']; exports.keywords = keywords; const builtinConstants = ['true', 'false']; exports.builtinConstants = builtinConstants; const builtinFunctions = ['avg', 'count', 'first', 'last', 'max', 'min', 'sum', 'ucase', 'lcase', 'mid', 'len', 'round', 'rank', 'now', 'format', 'coalesce', 'ifnull', 'isnull', 'nvl']; exports.builtinFunctions = builtinFunctions; const dataTypes = ['int', 'numeric', 'decimal', 'date', 'varchar', 'char', 'bigint', 'float', 'double', 'bit', 'binary', 'text', 'set', 'timestamp', 'money', 'real', 'number', 'integer']; exports.dataTypes = dataTypes; const theme = { base: 'vs', inherit: false, rules: [{ token: 'osquery' }, { token: 'support.function', foreground: '4271AE' }, { token: 'keyword', foreground: '8959A8' }, { token: 'storage.type', foreground: '8959A8' }, { token: 'constant.language', foreground: 'F5871F' }, { token: 'comment', foreground: '8E908C' }, { token: 'string', foreground: '718C00' }, { token: 'constant.numeric', foreground: 'F5871F' }, { token: 'keyword.operator', foreground: '3E999F' }], colors: { 'editorGutter.background': '#F6F6F6' } }; const initializeOsqueryEditor = () => { let disposable = null; if (_monaco.monaco) { disposable = _monaco.monaco.languages.onLanguage('sql', () => { _monaco.monaco.languages.setMonarchTokensProvider('sql', { ignoreCase: true, osqueryTableNames, builtinFunctions, keywords, builtinConstants, dataTypes, brackets: [{ open: '[', close: ']', token: 'delimiter.square' }, { open: '(', close: ')', token: 'delimiter.parenthesis' }], tokenizer: { root: [['[a-zA-Z_$][a-zA-Z0-9_$]*\\b', { cases: { '@osqueryTableNames': 'osquery', '@builtinFunctions': 'support.function', '@keywords': 'keyword', '@builtinConstants': 'constant.language', '@dataTypes': 'storage.type' } }], ['--.*$', 'comment'], ['/\\*.*\\*/', 'comment'], ['".*?"', 'string'], ["'.*?'", 'string'], [/[ \t\r\n]+/, { token: 'whitespace' }], ['[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b', 'constant.numeric'], ['\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=', 'keyword.operator'], ['[\\(]', 'paren.lparen'], ['[\\)]', 'paren.rparen'], ['\\s+', 'text']] } }); _monaco.monaco === null || _monaco.monaco === void 0 ? void 0 : _monaco.monaco.editor.defineTheme('osquery', theme); _monaco.monaco === null || _monaco.monaco === void 0 ? void 0 : _monaco.monaco.languages.registerCompletionItemProvider('sql', { triggerCharacters: ['.'], provideCompletionItems: (model, position) => { const value = model.getValue(); const tokens = _monaco.monaco.editor.tokenize(value, 'sql'); const findOsqueryToken = (0, _lodash.findLast)(tokens[position.lineNumber - 1], token => token.type === 'osquery.sql'); const osqueryTable = model.getWordAtPosition({ lineNumber: position.lineNumber, column: ((findOsqueryToken === null || findOsqueryToken === void 0 ? void 0 : findOsqueryToken.offset) || 0) + 1 }); const lineContent = model.getLineContent(position.lineNumber); const word = model.getWordUntilPosition(position); const isDot = lineContent.charAt(lineContent.length - 1) === '.' || lineContent.charAt(lineContent.length - 2) === '.'; const range = { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: word.startColumn, endColumn: word.endColumn }; return getEditorAutoCompleteSuggestion(range, value, isDot, osqueryTable === null || osqueryTable === void 0 ? void 0 : osqueryTable.word); } }); }); return disposable; } }; exports.initializeOsqueryEditor = initializeOsqueryEditor; const regex = /\s*[\s,]\s*/; const getEditorAutoCompleteSuggestion = (range, value, isDot, name) => { var _osqueryTablesRecord$; // we do not want to suggest the last word (currently being typed) const localValue = value.split(regex).slice(0, -1); const localKeywords = localValue.map(kw => ({ label: kw, kind: _monaco.monaco.languages.CompletionItemKind.Snippet, detail: 'Local', insertText: kw, range })); const suggestionsFromDefaultKeywords = keywords.map(kw => ({ label: `${kw.toUpperCase()}`, kind: _monaco.monaco.languages.CompletionItemKind.Keyword, detail: 'Keyword', insertText: `${kw.toUpperCase()} `, range })); const osqueryColumns = name ? (0, _lodash.map)((_osqueryTablesRecord$ = _osquery_tables.osqueryTablesRecord[name]) === null || _osqueryTablesRecord$ === void 0 ? void 0 : _osqueryTablesRecord$.columns, ({ name: columnName }) => ({ label: columnName, kind: _monaco.monaco.languages.CompletionItemKind.Folder, detail: `${name} column`, insertText: columnName, range })) : []; const tableNameKeywords = osqueryTableNames.map(tableName => ({ label: tableName, kind: _monaco.monaco.languages.CompletionItemKind.Folder, detail: 'Osquery', insertText: tableName, range })); const builtinConstantsKeywords = builtinConstants.map(constant => ({ label: constant, kind: _monaco.monaco.languages.CompletionItemKind.Constant, detail: 'Constant', insertText: constant, range })); const builtinFunctionsKeywords = builtinFunctions.map(builtinFunction => ({ label: builtinFunction, kind: _monaco.monaco.languages.CompletionItemKind.Function, detail: 'Function', insertText: builtinFunction, range })); const dataTypesKeywords = dataTypes.map(dataType => ({ label: dataType, kind: _monaco.monaco.languages.CompletionItemKind.TypeParameter, detail: 'Type', insertText: dataType, range })); return { suggestions: // first word has to be an SQL keyword range.startColumn === 1 ? suggestionsFromDefaultKeywords : // if last char is === '.' it means we are joining so we want to present just specific osquery table suggestions isDot ? osqueryColumns : (0, _lodash.uniqBy)([...suggestionsFromDefaultKeywords, ...tableNameKeywords, ...builtinConstantsKeywords, ...builtinFunctionsKeywords, ...dataTypesKeywords, ...localKeywords], word => word.label.toLowerCase()) }; }; exports.getEditorAutoCompleteSuggestion = getEditorAutoCompleteSuggestion;