"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getTypeSuggestions = exports.getStaticSuggestions = exports.getKeywords = exports.getFieldSuggestions = exports.getConstructorSuggestions = exports.getClassMemberSuggestions = exports.getAutocompleteSuggestions = void 0; var _i18n = require("@kbn/i18n"); var _autocomplete_definitions = require("../../autocomplete_definitions"); var _lexer_rules = require("../../lexer_rules"); var _autocomplete_utils = require("./autocomplete_utils"); /* * 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 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ const getKeywords = () => { const lexerKeywords = _lexer_rules.lexerRules.keywords.map(keyword => { return { label: keyword, kind: 'keyword', documentation: `Keyword: ${keyword}`, insertText: keyword }; }); const allKeywords = [...lexerKeywords, { label: 'params', kind: 'keyword', documentation: _i18n.i18n.translate('monaco.painlessLanguage.autocomplete.paramsKeywordDescription', { defaultMessage: 'Access variables passed into the script.' }), insertText: 'params' }]; return allKeywords; }; exports.getKeywords = getKeywords; const getTypeSuggestions = () => { return _lexer_rules.lexerRules.primitives.map(primitive => { return { label: primitive, kind: 'type', documentation: `Type: ${primitive}`, insertText: primitive }; }); }; exports.getTypeSuggestions = getTypeSuggestions; const runtimeContexts = ['boolean_script_field_script_field', 'date_script_field', 'double_script_field_script_field', 'ip_script_field_script_field', 'long_script_field_script_field', 'string_script_field_script_field']; const mapContextToData = { painless_test: _autocomplete_definitions.commonContext, score: _autocomplete_definitions.scoreContext, filter: _autocomplete_definitions.filterContext, boolean_script_field_script_field: _autocomplete_definitions.booleanScriptFieldScriptFieldContext, date_script_field: _autocomplete_definitions.dateScriptFieldContext, double_script_field_script_field: _autocomplete_definitions.doubleScriptFieldScriptFieldContext, ip_script_field_script_field: _autocomplete_definitions.ipScriptFieldScriptFieldContext, long_script_field_script_field: _autocomplete_definitions.longScriptFieldScriptFieldContext, processor_conditional: _autocomplete_definitions.processorConditionalContext, string_script_field_script_field: _autocomplete_definitions.stringScriptFieldScriptFieldContext }; const getStaticSuggestions = ({ suggestions, hasFields, isRuntimeContext }) => { const classSuggestions = suggestions.map(suggestion => { const { properties, constructorDefinition, ...rootSuggestion } = suggestion; return rootSuggestion; }); const keywords = getKeywords(); const typeSuggestions = getTypeSuggestions(); let keywordSuggestions = hasFields ? [...keywords, { label: 'doc', kind: 'keyword', documentation: _i18n.i18n.translate('monaco.painlessLanguage.autocomplete.docKeywordDescription', { defaultMessage: `Access a field value from a script using the doc['field_name'] syntax` }), insertText: "doc[${1:'my_field'}]", insertTextAsSnippet: true }] : keywords; keywordSuggestions = isRuntimeContext ? [...keywordSuggestions, { label: 'emit', kind: 'keyword', documentation: _i18n.i18n.translate('monaco.painlessLanguage.autocomplete.emitKeywordDescription', { defaultMessage: 'Emit value without returning.' }), insertText: 'emit' }] : keywordSuggestions; return { isIncomplete: false, suggestions: [...classSuggestions, ...keywordSuggestions, ...typeSuggestions] }; }; exports.getStaticSuggestions = getStaticSuggestions; const getClassMemberSuggestions = (suggestions, className) => { const painlessClass = suggestions.find(suggestion => suggestion.label === className); return { isIncomplete: false, suggestions: (painlessClass === null || painlessClass === void 0 ? void 0 : painlessClass.properties) || [] }; }; exports.getClassMemberSuggestions = getClassMemberSuggestions; const getFieldSuggestions = fields => { const suggestions = fields.map(({ name }) => { return { label: name, kind: 'field', documentation: _i18n.i18n.translate('monaco.painlessLanguage.autocomplete.fieldValueDescription', { defaultMessage: `Retrieve the value for field '{fieldName}'`, values: { fieldName: name } }), // A trailing quotation mark is added to format the field for the user insertText: `${name}'` }; }); return { isIncomplete: false, suggestions }; }; exports.getFieldSuggestions = getFieldSuggestions; const getConstructorSuggestions = suggestions => { let constructorSuggestions = []; const suggestionsWithConstructors = suggestions.filter(suggestion => suggestion.constructorDefinition); if (suggestionsWithConstructors) { constructorSuggestions = suggestionsWithConstructors.map(filteredSuggestion => filteredSuggestion.constructorDefinition); } return { isIncomplete: false, suggestions: constructorSuggestions }; }; exports.getConstructorSuggestions = getConstructorSuggestions; const getAutocompleteSuggestions = (painlessContext, words, fields) => { // Unique suggestions based on context const contextSuggestions = mapContextToData[painlessContext].suggestions; // Enhance suggestions with common classes that exist in all contexts // "painless_test" is the exception since it equals the common suggestions const suggestions = painlessContext === 'painless_test' ? contextSuggestions : contextSuggestions.concat(_autocomplete_definitions.commonContext.suggestions); // What the user is currently typing const activeTyping = words[words.length - 1]; // This logic may end up needing to be more robust as we integrate autocomplete into more editors // For now, we're assuming there is a list of painless contexts that are only applicable in runtime fields const isRuntimeContext = runtimeContexts.includes(painlessContext); // "text" field types are not available in doc values and should be removed for autocompletion const filteredFields = fields === null || fields === void 0 ? void 0 : fields.filter(field => field.type !== 'text'); const hasFields = Boolean(filteredFields === null || filteredFields === void 0 ? void 0 : filteredFields.length); let autocompleteSuggestions = { isIncomplete: false, suggestions: [] }; if ((0, _autocomplete_utils.isConstructorInstance)(words)) { autocompleteSuggestions = getConstructorSuggestions(suggestions); } else if (filteredFields && (0, _autocomplete_utils.isDeclaringField)(activeTyping)) { autocompleteSuggestions = getFieldSuggestions(filteredFields); } else if ((0, _autocomplete_utils.isAccessingProperty)(activeTyping)) { const className = activeTyping.substring(0, activeTyping.length - 1).split('.')[0]; autocompleteSuggestions = getClassMemberSuggestions(suggestions, className); } else if ((0, _autocomplete_utils.showStaticSuggestions)(activeTyping, words, _lexer_rules.lexerRules.primitives)) { autocompleteSuggestions = getStaticSuggestions({ suggestions, hasFields, isRuntimeContext }); } return autocompleteSuggestions; }; exports.getAutocompleteSuggestions = getAutocompleteSuggestions;