"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.compileBodyDescription = compileBodyDescription; exports.globalsOnlyAutocompleteComponents = globalsOnlyAutocompleteComponents; var _lodash = _interopRequireDefault(require("lodash")); var _engine = require("./engine"); var _components = require("./components"); /* * 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. */ function CompilingContext(endpointId, parametrizedComponentFactories) { this.parametrizedComponentFactories = parametrizedComponentFactories; this.endpointId = endpointId; } /** * An object to resolve scope links (syntax endpoint.path1.path2) * @param link the link either string (endpoint.path1.path2, or .path1.path2) or a function (context,editor) * which returns a description to be compiled * @constructor * @param compilingContext * * * For this to work we expect the context to include a method context.endpointComponentResolver(endpoint) * which should return the top level components for the given endpoint */ function resolvePathToComponents(tokenPath, context, editor, components) { const walkStates = (0, _engine.walkTokenPath)(tokenPath, [new _engine.WalkingState('ROOT', components, [])], context, editor); const result = [].concat.apply([], _lodash.default.map(walkStates, 'components')); return result; } class ScopeResolver extends _components.SharedComponent { constructor(link, compilingContext) { super('__scope_link'); if (_lodash.default.isString(link) && link[0] === '.') { // relative link, inject current endpoint if (link === '.') { link = compilingContext.endpointId; } else { link = compilingContext.endpointId + link; } } this.link = link; this.compilingContext = compilingContext; } resolveLinkToComponents(context, editor) { if (_lodash.default.isFunction(this.link)) { const desc = this.link(context, editor); return compileDescription(desc, this.compilingContext); } if (!_lodash.default.isString(this.link)) { throw new Error('unsupported link format', this.link); } let path = this.link.replace(/\./g, '{').split(/(\{)/); const endpoint = path[0]; let components; try { if (endpoint === 'GLOBAL') { // global rules need an extra indirection if (path.length < 3) { throw new Error('missing term in global link: ' + this.link); } const term = path[2]; components = context.globalComponentResolver(term); path = path.slice(3); } else { path = path.slice(1); components = context.endpointComponentResolver(endpoint); } } catch (e) { throw new Error('failed to resolve link [' + this.link + ']: ' + e); } return resolvePathToComponents(path, context, editor, components); } getTerms(context, editor) { const options = []; const components = this.resolveLinkToComponents(context, editor); _lodash.default.each(components, function (component) { options.push.apply(options, component.getTerms(context, editor)); }); return options; } match(token, context, editor) { const result = { next: [] }; const components = this.resolveLinkToComponents(context, editor); _lodash.default.each(components, function (component) { const componentResult = component.match(token, context, editor); if (componentResult && componentResult.next) { result.next.push.apply(result.next, componentResult.next); } }); return result; } } function getTemplate(description) { if (description.__template) { if (description.__raw && _lodash.default.isString(description.__template)) { return { // This is a special secret attribute that gets passed through to indicate that // the raw value should be passed through to the console without JSON.stringifying it // first. // // Primary use case is to allow __templates to contain extended JSON special values like // triple quotes. __raw: true, value: description.__template }; } return description.__template; } else if (description.__one_of) { return getTemplate(description.__one_of[0]); } else if (description.__any_of) { return []; } else if (description.__scope_link) { // assume an object for now. return {}; } else if (Array.isArray(description)) { if (description.length === 1) { if (_lodash.default.isObject(description[0])) { // shortcut to save typing const innerTemplate = getTemplate(description[0]); return innerTemplate != null ? [innerTemplate] : []; } } return []; } else if (_lodash.default.isObject(description)) { return {}; } else if (_lodash.default.isString(description) && !/^\{.*\}$/.test(description)) { return description; } else { return description; } } function getOptions(description) { const options = {}; const template = getTemplate(description); if (!_lodash.default.isUndefined(template)) { options.template = template; } return options; } /** * @param description a json dict describing the endpoint * @param compilingContext */ function compileDescription(description, compilingContext) { if (Array.isArray(description)) { return [compileList(description, compilingContext)]; } else if (_lodash.default.isObject(description)) { // test for objects list as arrays are also objects if (description.__scope_link) { return [new ScopeResolver(description.__scope_link, compilingContext)]; } if (description.__any_of) { return [compileList(description.__any_of, compilingContext)]; } if (description.__one_of) { return _lodash.default.flatten(_lodash.default.map(description.__one_of, function (d) { return compileDescription(d, compilingContext); })); } const obj = compileObject(description, compilingContext); if (description.__condition) { return [compileCondition(description.__condition, obj, compilingContext)]; } else { return [obj]; } } else if (_lodash.default.isString(description) && /^\{.*\}$/.test(description)) { return [compileParametrizedValue(description, compilingContext)]; } else { return [new _components.ConstantComponent(description)]; } } function compileParametrizedValue(value, compilingContext, template) { value = value.substr(1, value.length - 2).toLowerCase(); let component = compilingContext.parametrizedComponentFactories.getComponent(value, true); if (!component) { console.warn("[Console] no factory found for '" + value + "'"); // using upper case as an indication that this value is a parameter return new _components.ConstantComponent(value.toUpperCase()); } component = component(value, null, template); if (!_lodash.default.isUndefined(template)) { component = (0, _engine.wrapComponentWithDefaults)(component, { template: template }); } return component; } function compileObject(objDescription, compilingContext) { const objectC = new _components.ConstantComponent('{'); const constants = []; const patterns = []; _lodash.default.each(objDescription, function (desc, key) { if (key.indexOf('__') === 0) { // meta key return; } const options = getOptions(desc); let component; if (/^\{.*\}$/.test(key)) { component = compileParametrizedValue(key, compilingContext, options.template); patterns.push(component); } else if (key === '*') { component = new _components.SharedComponent(key); patterns.push(component); } else { options.name = key; component = new _components.ConstantComponent(key, null, [options]); constants.push(component); } _lodash.default.map(compileDescription(desc, compilingContext), function (subComponent) { component.addComponent(subComponent); }); }); objectC.addComponent(new _components.ObjectComponent('inner', constants, patterns)); return objectC; } function compileList(listRule, compilingContext) { const listC = new _components.ConstantComponent('['); _lodash.default.each(listRule, function (desc) { _lodash.default.each(compileDescription(desc, compilingContext), function (component) { listC.addComponent(component); }); }); return listC; } /** takes a compiled object and wraps in a {@link ConditionalProxy }*/ function compileCondition(description, compiledObject) { if (description.lines_regex) { return new _components.ConditionalProxy(function (context, editor) { const lines = editor.getLines(context.requestStartRow, editor.getCurrentPosition().lineNumber).join('\n'); return new RegExp(description.lines_regex, 'm').test(lines); }, compiledObject); } else { throw 'unknown condition type - got: ' + JSON.stringify(description); } } // a list of component that match anything but give auto complete suggestions based on global API entries. function globalsOnlyAutocompleteComponents() { return [new _components.GlobalOnlyComponent('__global__')]; } /** * @param endpointId id of the endpoint being compiled. * @param description a json dict describing the endpoint * @param endpointComponentResolver a function (endpoint,context,editor) which should resolve an endpoint * to it's list of compiled components. * @param parametrizedComponentFactories a dict of the following structure * that will be used as a fall back for pattern keys (i.e.: {index}, resolved without the {}) * { * TYPE: function (part, parent, endpoint) { * return new SharedComponent(part, parent) * } * } */ function compileBodyDescription(endpointId, description, parametrizedComponentFactories) { return compileDescription(description, new CompilingContext(endpointId, parametrizedComponentFactories)); }