diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2f03c408663ba5..d26bd9b8dcb068 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,6 +3,7 @@ # For more info, see https://help.github.com/articles/about-codeowners/ # App Architecture +/src/plugins/data/ @elastic/kibana-app-arch /src/plugins/kibana_utils/ @elastic/kibana-app-arch # APM diff --git a/docs/development/core/public/kibana-plugin-public.plugin.md b/docs/development/core/public/kibana-plugin-public.plugin.md index 77e7fa65f3f85f..879897ec18d847 100644 --- a/docs/development/core/public/kibana-plugin-public.plugin.md +++ b/docs/development/core/public/kibana-plugin-public.plugin.md @@ -9,14 +9,14 @@ The interface that should be returned by a `PluginInitializer`. Signature: ```typescript -export interface Plugin = {}, TPluginsStart extends Record = {}> +export interface Plugin ``` -## Properties +## Methods -| Property | Type | Description | -| --- | --- | --- | -| [setup](./kibana-plugin-public.plugin.setup.md) | (core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise<TSetup> | | -| [start](./kibana-plugin-public.plugin.start.md) | (core: CoreStart, plugins: TPluginsStart) => TStart | Promise<TStart> | | -| [stop](./kibana-plugin-public.plugin.stop.md) | () => void | | +| Method | Description | +| --- | --- | +| [setup(core, plugins)](./kibana-plugin-public.plugin.setup.md) | | +| [start(core, plugins)](./kibana-plugin-public.plugin.start.md) | | +| [stop()](./kibana-plugin-public.plugin.stop.md) | | diff --git a/docs/development/core/public/kibana-plugin-public.plugin.setup.md b/docs/development/core/public/kibana-plugin-public.plugin.setup.md index 01223e3f9f24d9..56855b02cfbad4 100644 --- a/docs/development/core/public/kibana-plugin-public.plugin.setup.md +++ b/docs/development/core/public/kibana-plugin-public.plugin.setup.md @@ -2,10 +2,22 @@ [Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [Plugin](./kibana-plugin-public.plugin.md) > [setup](./kibana-plugin-public.plugin.setup.md) -## Plugin.setup property +## Plugin.setup() method Signature: ```typescript -setup: (core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise; +setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; ``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| core | CoreSetup | | +| plugins | TPluginsSetup | | + +Returns: + +`TSetup | Promise` + diff --git a/docs/development/core/public/kibana-plugin-public.plugin.start.md b/docs/development/core/public/kibana-plugin-public.plugin.start.md index 7e381b4379daaa..b132706f4b7c02 100644 --- a/docs/development/core/public/kibana-plugin-public.plugin.start.md +++ b/docs/development/core/public/kibana-plugin-public.plugin.start.md @@ -2,10 +2,22 @@ [Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [Plugin](./kibana-plugin-public.plugin.md) > [start](./kibana-plugin-public.plugin.start.md) -## Plugin.start property +## Plugin.start() method Signature: ```typescript -start: (core: CoreStart, plugins: TPluginsStart) => TStart | Promise; +start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; ``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| core | CoreStart | | +| plugins | TPluginsStart | | + +Returns: + +`TStart | Promise` + diff --git a/docs/development/core/public/kibana-plugin-public.plugin.stop.md b/docs/development/core/public/kibana-plugin-public.plugin.stop.md index 1af971d80c1ba1..2ccb9f5f3655b7 100644 --- a/docs/development/core/public/kibana-plugin-public.plugin.stop.md +++ b/docs/development/core/public/kibana-plugin-public.plugin.stop.md @@ -2,10 +2,14 @@ [Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [Plugin](./kibana-plugin-public.plugin.md) > [stop](./kibana-plugin-public.plugin.stop.md) -## Plugin.stop property +## Plugin.stop() method Signature: ```typescript -stop?: () => void; +stop?(): void; ``` +Returns: + +`void` + diff --git a/docs/development/core/server/kibana-plugin-server.plugin.md b/docs/development/core/server/kibana-plugin-server.plugin.md index 035aa160149427..5cef833ecc30e4 100644 --- a/docs/development/core/server/kibana-plugin-server.plugin.md +++ b/docs/development/core/server/kibana-plugin-server.plugin.md @@ -9,14 +9,14 @@ The interface that should be returned by a `PluginInitializer`. Signature: ```typescript -export interface Plugin = {}, TPluginsStart extends Record = {}> +export interface Plugin ``` -## Properties +## Methods -| Property | Type | Description | -| --- | --- | --- | -| [setup](./kibana-plugin-server.plugin.setup.md) | (core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise<TSetup> | | -| [start](./kibana-plugin-server.plugin.start.md) | (core: CoreStart, plugins: TPluginsStart) => TStart | Promise<TStart> | | -| [stop](./kibana-plugin-server.plugin.stop.md) | () => void | | +| Method | Description | +| --- | --- | +| [setup(core, plugins)](./kibana-plugin-server.plugin.setup.md) | | +| [start(core, plugins)](./kibana-plugin-server.plugin.start.md) | | +| [stop()](./kibana-plugin-server.plugin.stop.md) | | diff --git a/docs/development/core/server/kibana-plugin-server.plugin.setup.md b/docs/development/core/server/kibana-plugin-server.plugin.setup.md index e11c1f331b9566..5ceb504f796f18 100644 --- a/docs/development/core/server/kibana-plugin-server.plugin.setup.md +++ b/docs/development/core/server/kibana-plugin-server.plugin.setup.md @@ -2,10 +2,22 @@ [Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [Plugin](./kibana-plugin-server.plugin.md) > [setup](./kibana-plugin-server.plugin.setup.md) -## Plugin.setup property +## Plugin.setup() method Signature: ```typescript -setup: (core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise; +setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; ``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| core | CoreSetup | | +| plugins | TPluginsSetup | | + +Returns: + +`TSetup | Promise` + diff --git a/docs/development/core/server/kibana-plugin-server.plugin.start.md b/docs/development/core/server/kibana-plugin-server.plugin.start.md index ff5d81b5513a4b..6ce9f05de77311 100644 --- a/docs/development/core/server/kibana-plugin-server.plugin.start.md +++ b/docs/development/core/server/kibana-plugin-server.plugin.start.md @@ -2,10 +2,22 @@ [Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [Plugin](./kibana-plugin-server.plugin.md) > [start](./kibana-plugin-server.plugin.start.md) -## Plugin.start property +## Plugin.start() method Signature: ```typescript -start: (core: CoreStart, plugins: TPluginsStart) => TStart | Promise; +start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; ``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| core | CoreStart | | +| plugins | TPluginsStart | | + +Returns: + +`TStart | Promise` + diff --git a/docs/development/core/server/kibana-plugin-server.plugin.stop.md b/docs/development/core/server/kibana-plugin-server.plugin.stop.md index 00dbc824627bf2..1c51727c1d1660 100644 --- a/docs/development/core/server/kibana-plugin-server.plugin.stop.md +++ b/docs/development/core/server/kibana-plugin-server.plugin.stop.md @@ -2,10 +2,14 @@ [Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [Plugin](./kibana-plugin-server.plugin.md) > [stop](./kibana-plugin-server.plugin.stop.md) -## Plugin.stop property +## Plugin.stop() method Signature: ```typescript -stop?: () => void; +stop?(): void; ``` +Returns: + +`void` + diff --git a/src/core/public/plugins/plugin.ts b/src/core/public/plugins/plugin.ts index 5beba9dbafd2c5..4ac7c46e6ebca4 100644 --- a/src/core/public/plugins/plugin.ts +++ b/src/core/public/plugins/plugin.ts @@ -28,14 +28,14 @@ import { CoreStart, CoreSetup } from '..'; * @public */ export interface Plugin< - TSetup, - TStart, - TPluginsSetup extends Record = {}, - TPluginsStart extends Record = {} + TSetup = void, + TStart = void, + TPluginsSetup extends {} = {}, + TPluginsStart extends {} = {} > { - setup: (core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise; - start: (core: CoreStart, plugins: TPluginsStart) => TStart | Promise; - stop?: () => void; + setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; + start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; + stop?(): void; } /** diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index d6354d5c09c611..aa8f1c9ccf375f 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -475,13 +475,13 @@ export interface OverlayStart { } // @public -export interface Plugin = {}, TPluginsStart extends Record = {}> { +export interface Plugin { // (undocumented) - setup: (core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise; + setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; // (undocumented) - start: (core: CoreStart, plugins: TPluginsStart) => TStart | Promise; + start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; // (undocumented) - stop?: () => void; + stop?(): void; } // @public diff --git a/src/core/server/plugins/plugin.ts b/src/core/server/plugins/plugin.ts index c703c6f1d94406..6f3d6c68b4fd3e 100644 --- a/src/core/server/plugins/plugin.ts +++ b/src/core/server/plugins/plugin.ts @@ -136,14 +136,14 @@ export interface DiscoveredPluginInternal extends DiscoveredPlugin { * @public */ export interface Plugin< - TSetup, - TStart, - TPluginsSetup extends Record = {}, - TPluginsStart extends Record = {} + TSetup = void, + TStart = void, + TPluginsSetup extends {} = {}, + TPluginsStart extends {} = {} > { - setup: (core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise; - start: (core: CoreStart, plugins: TPluginsStart) => TStart | Promise; - stop?: () => void; + setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; + start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; + stop?(): void; } /** diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 7aa793764cabcd..f2b8aa894f042a 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -313,13 +313,13 @@ export interface OnPreAuthToolkit { } // @public -export interface Plugin = {}, TPluginsStart extends Record = {}> { +export interface Plugin { // (undocumented) - setup: (core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise; + setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; // (undocumented) - start: (core: CoreStart, plugins: TPluginsStart) => TStart | Promise; + start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; // (undocumented) - stop?: () => void; + stop?(): void; } // @public diff --git a/src/legacy/core_plugins/data/public/query/query_bar/index.ts b/src/legacy/core_plugins/data/public/query/query_bar/index.ts index 38865e50e8897d..c761681847c8e8 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/index.ts +++ b/src/legacy/core_plugins/data/public/query/query_bar/index.ts @@ -25,7 +25,4 @@ export { getQueryLog } from './lib/get_query_log'; // @ts-ignore export { setupDirective } from './directive'; -export interface Query { - query: string | { [key: string]: any }; - language: string; -} +export { Query } from '../../../../../../plugins/data/common/query/types'; diff --git a/src/legacy/core_plugins/input_control_vis/public/input_control_fn.test.js b/src/legacy/core_plugins/input_control_vis/public/input_control_fn.test.js index 60d9956ec1261f..54dd94a8d14b60 100644 --- a/src/legacy/core_plugins/input_control_vis/public/input_control_fn.test.js +++ b/src/legacy/core_plugins/input_control_vis/public/input_control_fn.test.js @@ -20,6 +20,8 @@ import { functionWrapper } from '../../interpreter/test_helpers'; import { inputControlVis } from './input_control_fn'; +jest.mock('ui/new_platform', () => require('../../../ui/public/new_platform/index.test.mocks').mockNewPlatformBackdoor()); + describe('interpreter/functions#input_control_vis', () => { const fn = functionWrapper(inputControlVis); const visConfig = { diff --git a/src/legacy/core_plugins/interpreter/common/index.ts b/src/legacy/core_plugins/interpreter/common/index.ts index 13ee31e920f1d1..740f75ddd7798a 100644 --- a/src/legacy/core_plugins/interpreter/common/index.ts +++ b/src/legacy/core_plugins/interpreter/common/index.ts @@ -34,4 +34,10 @@ export { PointSeriesColumnName, Render, Style, -} from './types'; +} from '../../../../plugins/data/common/expressions/expression_types'; +export const API_ROUTE = '/api/interpreter'; +export * from '../../../../plugins/data/common/expressions/serialize_provider'; +export { Type } from '../../../../plugins/data/common/expressions/interpreter'; +export { + interpreterProvider, +} from '../../../../plugins/data/common/expressions/interpreter_provider'; diff --git a/src/legacy/core_plugins/interpreter/init.ts b/src/legacy/core_plugins/interpreter/init.ts index 74f003774cb28a..37eecd3b10db42 100644 --- a/src/legacy/core_plugins/interpreter/init.ts +++ b/src/legacy/core_plugins/interpreter/init.ts @@ -17,20 +17,31 @@ * under the License. */ +/* eslint-disable max-classes-per-file */ + // @ts-ignore -import { register, registryFactory } from '@kbn/interpreter/common'; +import { register, registryFactory, Registry, Fn } from '@kbn/interpreter/common'; // @ts-ignore import { routes } from './server/routes'; +// @ts-ignore +import { typeSpecs as types } from '../../../plugins/data/common/expressions/expression_types'; + +import { Type } from './common'; import { Legacy } from '../../../../kibana'; -// @ts-ignore -import { FunctionsRegistry } from './common/functions_registry'; -// @ts-ignore -import { typeSpecs as types } from './common/types'; -// @ts-ignore -import { TypesRegistry } from './common/types_registry'; +export class TypesRegistry extends Registry { + wrapper(obj: any) { + return new (Type as any)(obj); + } +} + +export class FunctionsRegistry extends Registry { + wrapper(obj: any) { + return new Fn(obj); + } +} export const registries = { types: new TypesRegistry(), diff --git a/src/legacy/core_plugins/interpreter/public/functions/esaggs.ts b/src/legacy/core_plugins/interpreter/public/functions/esaggs.ts index c64464030f02b6..3bf414cf022115 100644 --- a/src/legacy/core_plugins/interpreter/public/functions/esaggs.ts +++ b/src/legacy/core_plugins/interpreter/public/functions/esaggs.ts @@ -37,7 +37,7 @@ const courierRequestHandlerProvider = CourierRequestHandlerProvider; const courierRequestHandler = courierRequestHandlerProvider().handler; import { ExpressionFunction } from '../../types'; -import { KibanaContext, KibanaDatatable } from '../../common/types'; +import { KibanaContext, KibanaDatatable } from '../../common'; const name = 'esaggs'; diff --git a/src/legacy/core_plugins/interpreter/public/functions/range.ts b/src/legacy/core_plugins/interpreter/public/functions/range.ts index 622785dce4f940..8ae07dd82a22c0 100644 --- a/src/legacy/core_plugins/interpreter/public/functions/range.ts +++ b/src/legacy/core_plugins/interpreter/public/functions/range.ts @@ -18,7 +18,7 @@ */ import { i18n } from '@kbn/i18n'; -import { KibanaDatatable, Range } from '../../common/types'; +import { KibanaDatatable, Range } from '../../types'; import { ExpressionFunction } from '../../types'; const name = 'range'; diff --git a/src/legacy/core_plugins/interpreter/public/interpreter.js b/src/legacy/core_plugins/interpreter/public/interpreter.js index e7a1f45e6f6db3..f401487099c58a 100644 --- a/src/legacy/core_plugins/interpreter/public/interpreter.js +++ b/src/legacy/core_plugins/interpreter/public/interpreter.js @@ -25,7 +25,7 @@ import { kfetch } from 'ui/kfetch'; import { ajaxStream } from 'ui/ajax_stream'; import { functions } from './functions'; import { visualization } from './renderers/visualization'; -import { typeSpecs } from '../common/types'; +import { typeSpecs } from '../../../../plugins/data/common/expressions/expression_types'; // Expose kbnInterpreter.register(specs) and kbnInterpreter.registries() globally so that plugins // can register without a transpile step. diff --git a/src/legacy/core_plugins/interpreter/public/lib/interpreter.js b/src/legacy/core_plugins/interpreter/public/lib/interpreter.js index 7b2dc757b4b400..de3c21cc742059 100644 --- a/src/legacy/core_plugins/interpreter/public/lib/interpreter.js +++ b/src/legacy/core_plugins/interpreter/public/lib/interpreter.js @@ -17,8 +17,7 @@ * under the License. */ -import { interpreterProvider } from '../../common/interpreter/interpret'; -import { serializeProvider } from '../../common/serialize'; +import { interpreterProvider, serializeProvider } from '../../common'; import { createHandlers } from './create_handlers'; import { batchedFetch } from './batched_fetch'; import { FUNCTIONS_URL } from './consts'; diff --git a/src/legacy/core_plugins/interpreter/public/lib/interpreter.test.js b/src/legacy/core_plugins/interpreter/public/lib/interpreter.test.js index 24fcd81abef0e1..2c2ebd52f53d16 100644 --- a/src/legacy/core_plugins/interpreter/public/lib/interpreter.test.js +++ b/src/legacy/core_plugins/interpreter/public/lib/interpreter.test.js @@ -20,11 +20,7 @@ import { FUNCTIONS_URL } from './consts'; import { initializeInterpreter } from './interpreter'; -jest.mock('../../common/interpreter/interpret', () => ({ - interpreterProvider: () => () => ({}), -})); - -jest.mock('../../common/serialize', () => ({ +jest.mock('../../common', () => ({ serializeProvider: () => ({ serialize: () => ({}) }), })); diff --git a/src/legacy/core_plugins/interpreter/public/registries.karma_mock.ts b/src/legacy/core_plugins/interpreter/public/registries.karma_mock.ts new file mode 100644 index 00000000000000..66c51167c7b59f --- /dev/null +++ b/src/legacy/core_plugins/interpreter/public/registries.karma_mock.ts @@ -0,0 +1,43 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import sinon from 'sinon'; + +export const functionsRegistry = {}; +export const renderersRegistry = {}; +export const typesRegistry = {}; +export const registries = { + browserFunctions: functionsRegistry, + renderers: renderersRegistry, + types: typesRegistry, +}; + +const resetRegistry = (registry: any) => { + registry.wrapper = sinon.stub(); + registry.register = sinon.stub(); + registry.toJS = sinon.stub(); + registry.toArray = sinon.stub(); + registry.get = sinon.stub(); + registry.getProp = sinon.stub(); + registry.reset = sinon.stub(); +}; +const resetAll = () => Object.values(registries).forEach(resetRegistry); + +resetAll(); +afterEach(resetAll); diff --git a/src/legacy/core_plugins/interpreter/public/registries/index.js b/src/legacy/core_plugins/interpreter/public/registries.ts similarity index 66% rename from src/legacy/core_plugins/interpreter/public/registries/index.js rename to src/legacy/core_plugins/interpreter/public/registries.ts index 5c869867d6f6b4..492b154fd9a50f 100644 --- a/src/legacy/core_plugins/interpreter/public/registries/index.js +++ b/src/legacy/core_plugins/interpreter/public/registries.ts @@ -17,14 +17,16 @@ * under the License. */ -import { typesRegistry } from './type_registry'; -import { functionsRegistry } from './functions_registry'; -import { renderersRegistry } from './renderer_registry'; +import { npSetup } from 'ui/new_platform'; -const registries = { +export const functionsRegistry = + npSetup.plugins.data.expressions.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.functions; +export const renderersRegistry = + npSetup.plugins.data.expressions.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.renderers; +export const typesRegistry = + npSetup.plugins.data.expressions.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.types; +export const registries = { browserFunctions: functionsRegistry, renderers: renderersRegistry, types: typesRegistry, }; - -export { registries, typesRegistry, functionsRegistry, renderersRegistry }; diff --git a/src/legacy/core_plugins/interpreter/server/routes/server_functions.js b/src/legacy/core_plugins/interpreter/server/routes/server_functions.js index 539f9544d9ab69..b64a9af006e412 100644 --- a/src/legacy/core_plugins/interpreter/server/routes/server_functions.js +++ b/src/legacy/core_plugins/interpreter/server/routes/server_functions.js @@ -18,8 +18,7 @@ */ import Boom from 'boom'; -import { serializeProvider } from '../../common/serialize'; -import { API_ROUTE } from '../../common/constants'; +import { serializeProvider, API_ROUTE } from '../../common'; import { createHandlers } from '../lib/create_handlers'; import Joi from 'joi'; diff --git a/src/legacy/core_plugins/interpreter/types/arguments.ts b/src/legacy/core_plugins/interpreter/types/arguments.ts index 20bec9359a5937..a750d1d0364275 100644 --- a/src/legacy/core_plugins/interpreter/types/arguments.ts +++ b/src/legacy/core_plugins/interpreter/types/arguments.ts @@ -17,126 +17,4 @@ * under the License. */ -import { KnownTypeToString, TypeString, UnmappedTypeStrings } from './common'; - -/** - * This type represents all of the possible combinations of properties of an - * Argument in an Expression Function. The presence or absence of certain fields - * influence the shape and presence of others within each `arg` in the specification. - */ -export type ArgumentType = - | SingleArgumentType - | MultipleArgumentType - | UnresolvedSingleArgumentType - | UnresolvedMultipleArgumentType; - -/** - * Map the type within the the generic array to a string-based - * representation of the type. - */ -// prettier-ignore -type ArrayTypeToArgumentString = - T extends Array ? TypeString : - T extends null ? 'null' : - never; - -/** - * Map the return type of the function within the generic to a - * string-based representation of the return type. - */ -// prettier-ignore -type UnresolvedTypeToArgumentString = - T extends (...args: any) => infer ElementType ? TypeString : - T extends null ? 'null' : - never; - -/** - * Map the array-based return type of the function within the generic to a - * string-based representation of the return type. - */ -// prettier-ignore -type UnresolvedArrayTypeToArgumentString = - T extends Array<(...args: any) => infer ElementType> ? TypeString : - T extends (...args: any) => infer ElementType ? ArrayTypeToArgumentString : - T extends null ? 'null' : - never; - -/** A type containing properties common to all Function Arguments. */ -interface BaseArgumentType { - /** Alternate names for the Function valid for use in the Expression Editor */ - aliases?: string[]; - /** Help text for the Argument to be displayed in the Expression Editor */ - help: string; - /** Default options for the Argument */ - options?: T[]; - /** - * Is this Argument required? - * @default false - */ - required?: boolean; - /** - * If false, the Argument is supplied as a function to be invoked in the - * implementation, rather than a value. - * @default true - */ - resolve?: boolean; - /** Names of types that are valid values of the Argument. */ - types?: string[]; - /** The optional default value of the Argument. */ - default?: T | string; - /** - * If true, multiple values may be supplied to the Argument. - * @default false - */ - multi?: boolean; -} - -/** - * The `types` array in a `FunctionSpec` should contain string - * representations of the `ArgumentsSpec` types: - * - * `someArgument: boolean | string` results in `types: ['boolean', 'string']` - */ -type SingleArgumentType = BaseArgumentType & { - multi?: false; - resolve?: true; - types?: Array | UnmappedTypeStrings>; -}; - -/** - * If the `multi` property on the argument is true, the `types` array should - * contain string representations of the `ArgumentsSpec` array types: - * - * `someArgument: boolean[] | string[]` results in: `types: ['boolean', 'string']` - */ -type MultipleArgumentType = BaseArgumentType & { - multi: true; - resolve?: true; - types?: Array | UnmappedTypeStrings>; -}; - -/** - * If the `resolve` property on the arugument is false, the `types` array, if - * present, should contain string representations of the result of the argument - * function: - * - * `someArgument: () => string` results in `types: ['string']` - */ -type UnresolvedSingleArgumentType = BaseArgumentType & { - multi?: false; - resolve: false; - types?: Array | UnmappedTypeStrings>; -}; - -/** - * If the `resolve` property on the arugument is false, the `types` array, if - * present, should contain string representations of the result of the argument - * function: - * - * `someArgument: () => string[]` results in `types: ['string']` - */ -type UnresolvedMultipleArgumentType = BaseArgumentType & { - multi: true; - resolve: false; - types?: Array | UnmappedTypeStrings>; -}; +export * from '../../../../plugins/data/common/expressions/types/arguments'; diff --git a/src/legacy/core_plugins/interpreter/types/common.ts b/src/legacy/core_plugins/interpreter/types/common.ts index 55a3ed579c6869..02093c80f8f56a 100644 --- a/src/legacy/core_plugins/interpreter/types/common.ts +++ b/src/legacy/core_plugins/interpreter/types/common.ts @@ -17,44 +17,4 @@ * under the License. */ -/** - * This can convert a type into a known Expression string representation of - * that type. For example, `TypeToString` will resolve to `'datatable'`. - * This allows Expression Functions to continue to specify their type in a - * simple string format. - */ -export type TypeToString = KnownTypeToString | UnmappedTypeStrings; - -/** - * Map the type of the generic to a string-based representation of the type. - * - * If the provided generic is its own type interface, we use the value of - * the `type` key as a string literal type for it. - */ -// prettier-ignore -export type KnownTypeToString = - T extends string ? 'string' : - T extends boolean ? 'boolean' : - T extends number ? 'number' : - T extends null ? 'null' : - T extends { type: string } ? T['type'] : - never; - -/** - * If the type extends a Promise, we still need to return the string representation: - * - * `someArgument: Promise` results in `types: ['boolean', 'string']` - */ -export type TypeString = KnownTypeToString>; - -/** - * Types used in Expressions that don't map to a primitive cleanly: - * - * `date` is typed as a number or string, and represents a date - */ -export type UnmappedTypeStrings = 'date' | 'filter'; - -/** - * Utility type: extracts returned type from a Promise. - */ -export type UnwrapPromise = T extends Promise ? P : T; +export * from '../../../../plugins/data/common/expressions/types/common'; diff --git a/src/legacy/core_plugins/interpreter/types/functions.ts b/src/legacy/core_plugins/interpreter/types/functions.ts index d640e351c5640d..5d7f67292d89ee 100644 --- a/src/legacy/core_plugins/interpreter/types/functions.ts +++ b/src/legacy/core_plugins/interpreter/types/functions.ts @@ -17,31 +17,4 @@ * under the License. */ -import { ArgumentType } from './arguments'; -import { TypeToString, UnwrapPromise } from './common'; - -/** - * A generic type which represents an Expression Function definition. - */ -export interface ExpressionFunction { - /** Arguments for the Function */ - args: { [key in keyof Arguments]: ArgumentType }; - aliases?: string[]; - context?: { - types: Array>; - }; - /** Help text displayed in the Expression editor */ - help: string; - /** The name of the Function */ - name: Name; - /** The type of the Function */ - type?: TypeToString>; - /** The implementation of the Function */ - fn(context: Context, args: Arguments, handlers: FunctionHandlers): Return; -} - -// TODO: Handlers can be passed to the `fn` property of the Function. At the moment, these Functions -// are not strongly defined. -interface FunctionHandlers { - [key: string]: (...args: any) => any; -} +export * from '../../../../plugins/data/common/expressions/types/functions'; diff --git a/src/legacy/core_plugins/interpreter/types/index.ts b/src/legacy/core_plugins/interpreter/types/index.ts index 6383214a0c42c8..19b66c8407ba1b 100644 --- a/src/legacy/core_plugins/interpreter/types/index.ts +++ b/src/legacy/core_plugins/interpreter/types/index.ts @@ -17,14 +17,4 @@ * under the License. */ -export { ArgumentType } from './arguments'; -export { - TypeToString, - KnownTypeToString, - TypeString, - UnmappedTypeStrings, - UnwrapPromise, -} from './common'; -export { ExpressionFunction } from './functions'; -export { ExpressionType } from './types'; -export * from '../common/types'; +export * from '../../../../plugins/data/common'; diff --git a/src/legacy/core_plugins/interpreter/types/types.ts b/src/legacy/core_plugins/interpreter/types/types.ts index a6c8a564a4484a..97f9a501eeeda0 100644 --- a/src/legacy/core_plugins/interpreter/types/types.ts +++ b/src/legacy/core_plugins/interpreter/types/types.ts @@ -17,17 +17,4 @@ * under the License. */ -/** - * A generic type which represents a custom Expression Type Definition that's - * registered to the Interpreter. - */ -export interface ExpressionType { - name: Name; - validate?: (type: any) => void | Error; - serialize?: (type: Type) => SerializedType; - deserialize?: (type: SerializedType) => Type; - // TODO: Update typings for the `availableTypes` parameter once interfaces for this - // have been added elsewhere in the interpreter. - from?: Record) => Type>; - to?: Record) => unknown>; -} +export * from '../../../../plugins/data/common/expressions/types/types'; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/pie_fn.test.js b/src/legacy/core_plugins/kbn_vislib_vis_types/public/pie_fn.test.js index 5fc68a42cb81d0..7cb8c73435d540 100644 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/pie_fn.test.js +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/pie_fn.test.js @@ -20,6 +20,8 @@ import { functionWrapper } from '../../interpreter/test_helpers'; import { kibanaPie } from './pie_fn'; +jest.mock('ui/new_platform', () => require('../../../ui/public/new_platform/index.test.mocks').mockNewPlatformBackdoor()); + const mockResponseHandler = jest.fn().mockReturnValue(Promise.resolve({ hits: 1, names: ['Count'], diff --git a/src/legacy/core_plugins/markdown_vis/public/markdown_fn.test.js b/src/legacy/core_plugins/markdown_vis/public/markdown_fn.test.js index 2d4642636fa0c3..2f0656ad68552a 100644 --- a/src/legacy/core_plugins/markdown_vis/public/markdown_fn.test.js +++ b/src/legacy/core_plugins/markdown_vis/public/markdown_fn.test.js @@ -20,6 +20,8 @@ import { functionWrapper } from '../../interpreter/test_helpers'; import { kibanaMarkdown } from './markdown_fn'; +jest.mock('ui/new_platform', () => require('../../../ui/public/new_platform/index.test.mocks').mockNewPlatformBackdoor()); + describe('interpreter/functions#markdown', () => { const fn = functionWrapper(kibanaMarkdown); const args = { diff --git a/src/legacy/core_plugins/metric_vis/public/metric_vis_fn.test.js b/src/legacy/core_plugins/metric_vis/public/metric_vis_fn.test.js index bf98b55b39543c..699423a5c5918c 100644 --- a/src/legacy/core_plugins/metric_vis/public/metric_vis_fn.test.js +++ b/src/legacy/core_plugins/metric_vis/public/metric_vis_fn.test.js @@ -20,6 +20,8 @@ import { functionWrapper } from '../../interpreter/test_helpers'; import { metric } from './metric_vis_fn'; +jest.mock('ui/new_platform', () => require('../../../ui/public/new_platform/index.test.mocks').mockNewPlatformBackdoor()); + describe('interpreter/functions#metric', () => { const fn = functionWrapper(metric); const context = { diff --git a/src/legacy/core_plugins/region_map/public/region_map_fn.test.js b/src/legacy/core_plugins/region_map/public/region_map_fn.test.js index 0239dc22b6c48b..12a9982b3674bf 100644 --- a/src/legacy/core_plugins/region_map/public/region_map_fn.test.js +++ b/src/legacy/core_plugins/region_map/public/region_map_fn.test.js @@ -20,6 +20,8 @@ import { functionWrapper } from '../../interpreter/test_helpers'; import { regionmap } from './region_map_fn'; +jest.mock('ui/new_platform', () => require('../../../ui/public/new_platform/index.test.mocks').mockNewPlatformBackdoor()); + describe('interpreter/functions#regionmap', () => { const fn = functionWrapper(regionmap); const context = { diff --git a/src/legacy/core_plugins/table_vis/public/table_vis_fn.test.js b/src/legacy/core_plugins/table_vis/public/table_vis_fn.test.js index 1d2ff5ef723999..1d17dc1f183d2d 100644 --- a/src/legacy/core_plugins/table_vis/public/table_vis_fn.test.js +++ b/src/legacy/core_plugins/table_vis/public/table_vis_fn.test.js @@ -20,6 +20,8 @@ import { functionWrapper } from '../../interpreter/test_helpers'; import { kibanaTable } from './table_vis_fn'; +jest.mock('ui/new_platform', () => require('../../../ui/public/new_platform/index.test.mocks').mockNewPlatformBackdoor()); + const mockResponseHandler = jest.fn().mockReturnValue(Promise.resolve({ tables: [{ columns: [], rows: [] }], })); diff --git a/src/legacy/core_plugins/tagcloud/public/tag_cloud_fn.test.js b/src/legacy/core_plugins/tagcloud/public/tag_cloud_fn.test.js index 774a9dc35b290f..85aadb689268f3 100644 --- a/src/legacy/core_plugins/tagcloud/public/tag_cloud_fn.test.js +++ b/src/legacy/core_plugins/tagcloud/public/tag_cloud_fn.test.js @@ -20,6 +20,8 @@ import { functionWrapper } from '../../interpreter/test_helpers'; import { tagcloud } from './tag_cloud_fn'; +jest.mock('ui/new_platform', () => require('../../../ui/public/new_platform/index.test.mocks').mockNewPlatformBackdoor()); + describe('interpreter/functions#tagcloud', () => { const fn = functionWrapper(tagcloud); const context = { diff --git a/src/legacy/core_plugins/tests_bundle/index.js b/src/legacy/core_plugins/tests_bundle/index.js index 58092e1abf77f1..e10582df46b131 100644 --- a/src/legacy/core_plugins/tests_bundle/index.js +++ b/src/legacy/core_plugins/tests_bundle/index.js @@ -21,6 +21,7 @@ import { createReadStream } from 'fs'; import globby from 'globby'; import MultiStream from 'multistream'; +import webpackMerge from 'webpack-merge'; import { fromRoot } from '../../../legacy/utils'; import { replacePlaceholder } from '../../../optimize/public_path_placeholder'; @@ -94,7 +95,7 @@ export default (kibana) => { uiBundles.addPostLoader({ test: /\.js$/, exclude: /[\/\\](__tests__|node_modules|bower_components|webpackShims)[\/\\]/, - loader: 'istanbul-instrumenter-loader' + loader: 'istanbul-instrumenter-loader', }); } @@ -102,6 +103,13 @@ export default (kibana) => { id: 'tests', modules: [...modules], template: createTestEntryTemplate(uiSettingDefaults), + extendConfig(webpackConfig) { + return webpackMerge({ + resolve: { + extensions: ['.karma_mock.js', '.karma_mock.tsx', '.karma_mock.ts'] + } + }, webpackConfig); + } }); kbnServer.server.route({ diff --git a/src/legacy/core_plugins/tile_map/public/tilemap_fn.test.js b/src/legacy/core_plugins/tile_map/public/tilemap_fn.test.js index ec680502fd236d..5a7276a433d340 100644 --- a/src/legacy/core_plugins/tile_map/public/tilemap_fn.test.js +++ b/src/legacy/core_plugins/tile_map/public/tilemap_fn.test.js @@ -20,6 +20,7 @@ import { functionWrapper } from '../../interpreter/test_helpers'; import { tilemap } from './tilemap_fn'; +jest.mock('ui/new_platform', () => require('../../../ui/public/new_platform/index.test.mocks').mockNewPlatformBackdoor()); jest.mock('ui/vis/map/convert_to_geojson', () => ({ convertToGeoJson: jest.fn().mockReturnValue({ featureCollection: { diff --git a/src/legacy/ui/public/new_platform/index.test.mocks.ts b/src/legacy/ui/public/new_platform/index.test.mocks.ts new file mode 100644 index 00000000000000..2e8d22faadfec8 --- /dev/null +++ b/src/legacy/ui/public/new_platform/index.test.mocks.ts @@ -0,0 +1,68 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export const mockNewPlatformBackdoor = () => { + return { + __setup__: () => {}, + __start__: () => {}, + npSetup: { + core: { + i18n: { + Context: {}, + }, + chrome: { + recentlyAccessed: false, + }, + }, + plugins: { + data: { + expressions: { + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + functions: { + register: () => {}, + }, + renderers: { + register: () => {}, + }, + types: { + register: () => {}, + }, + }, + }, + }, + }, + }, + npStart: { + core: { + uiSettings: { + get: () => true, + }, + chrome: { + recentlyAccessed: false, + }, + i18n: { + Context: () => {}, + }, + }, + plugins: { + data: {}, + }, + }, + }; +}; diff --git a/src/legacy/ui/public/new_platform/new_platform.ts b/src/legacy/ui/public/new_platform/new_platform.ts index 694e92f352015c..cfcf99fcbc9f2b 100644 --- a/src/legacy/ui/public/new_platform/new_platform.ts +++ b/src/legacy/ui/public/new_platform/new_platform.ts @@ -17,15 +17,24 @@ * under the License. */ import { InternalCoreSetup, InternalCoreStart } from '../../../../core/public'; +import { Plugin as DataPlugin } from '../../../../plugins/data/public'; + +export interface PluginsSetup { + data: ReturnType; +} + +export interface PluginsStart { + data: ReturnType; +} export const npSetup = { core: (null as unknown) as InternalCoreSetup, - plugins: {} as Record, + plugins: {} as PluginsSetup, }; export const npStart = { core: (null as unknown) as InternalCoreStart, - plugins: {} as Record, + plugins: {} as PluginsStart, }; /** @@ -34,15 +43,17 @@ export const npStart = { */ export function __reset__() { npSetup.core = (null as unknown) as InternalCoreSetup; + npSetup.plugins = {} as any; npStart.core = (null as unknown) as InternalCoreStart; + npStart.plugins = {} as any; } -export function __setup__(coreSetup: InternalCoreSetup, plugins: Record) { +export function __setup__(coreSetup: InternalCoreSetup, plugins: PluginsSetup) { npSetup.core = coreSetup; npSetup.plugins = plugins; } -export function __start__(coreStart: InternalCoreStart, plugins: Record) { +export function __start__(coreStart: InternalCoreStart, plugins: PluginsStart) { npStart.core = coreStart; npStart.plugins = plugins; } diff --git a/src/legacy/ui/public/visualize/loader/embedded_visualize_handler.test.ts b/src/legacy/ui/public/visualize/loader/embedded_visualize_handler.test.ts index 24a806bf27b18e..48d71655252fc3 100644 --- a/src/legacy/ui/public/visualize/loader/embedded_visualize_handler.test.ts +++ b/src/legacy/ui/public/visualize/loader/embedded_visualize_handler.test.ts @@ -26,25 +26,9 @@ import { VisResponseData } from './types'; import { Inspector } from '../../inspector'; import { EmbeddedVisualizeHandler } from './embedded_visualize_handler'; -jest.mock('ui/new_platform', () => ({ - npStart: { - core: { - i18n: { - Context: {}, - }, - chrome: { - recentlyAccessed: false, - }, - }, - }, - npSetup: { - core: { - uiSettings: { - get: () => true, - }, - }, - }, -})); +jest.mock('ui/new_platform', () => + require('../../../../ui/public/new_platform/index.test.mocks').mockNewPlatformBackdoor() +); describe('EmbeddedVisualizeHandler', () => { let handler: any; diff --git a/src/legacy/ui/ui_bundles/ui_bundle.js b/src/legacy/ui/ui_bundles/ui_bundle.js index 200235af633a2f..8e51c6f39a8e33 100644 --- a/src/legacy/ui/ui_bundles/ui_bundle.js +++ b/src/legacy/ui/ui_bundles/ui_bundle.js @@ -32,12 +32,14 @@ export class UiBundle { modules, template, controller, + extendConfig, } = options; this._id = id; this._modules = modules; this._template = template; this._controller = controller; + this._extendConfig = extendConfig; } getId() { @@ -126,4 +128,12 @@ export class UiBundle { outputPath: this.getOutputPath() }; } + + getExtendedConfig(webpackConfig) { + if (!this._extendConfig) { + return webpackConfig; + } + + return this._extendConfig(webpackConfig); + } } diff --git a/src/legacy/ui/ui_bundles/ui_bundles_controller.js b/src/legacy/ui/ui_bundles/ui_bundles_controller.js index ca77683a6cacec..a4521268ea121c 100644 --- a/src/legacy/ui/ui_bundles/ui_bundles_controller.js +++ b/src/legacy/ui/ui_bundles/ui_bundles_controller.js @@ -96,6 +96,7 @@ export class UiBundlesController { id, modules, template, + extendConfig, } = bundleSpec; if (this._filter.test(id)) { @@ -104,6 +105,7 @@ export class UiBundlesController { modules, template, controller: this, + extendConfig, })); } } @@ -223,4 +225,8 @@ export class UiBundlesController { return this._bundles .map(bundle => bundle.getId()); } + + getExtendedConfig(webpackConfig) { + return this._bundles.reduce((acc, bundle) => bundle.getExtendedConfig(acc), webpackConfig); + } } diff --git a/src/optimize/base_optimizer.js b/src/optimize/base_optimizer.js index 01ef4d1f6eaf3a..ac72363b672242 100644 --- a/src/optimize/base_optimizer.js +++ b/src/optimize/base_optimizer.js @@ -472,14 +472,16 @@ export default class BaseOptimizer { } }; - return webpackMerge( - commonConfig, - IS_KIBANA_DISTRIBUTABLE - ? isDistributableConfig - : {}, - this.uiBundles.isDevMode() - ? webpackMerge(watchingConfig, supportEnzymeConfig) - : productionConfig + return this.uiBundles.getExtendedConfig( + webpackMerge( + commonConfig, + IS_KIBANA_DISTRIBUTABLE + ? isDistributableConfig + : {}, + this.uiBundles.isDevMode() + ? webpackMerge(watchingConfig, supportEnzymeConfig) + : productionConfig + ) ); } diff --git a/src/plugins/data/README.md b/src/plugins/data/README.md new file mode 100644 index 00000000000000..53618ec049e7c4 --- /dev/null +++ b/src/plugins/data/README.md @@ -0,0 +1,9 @@ +# data + +`data` plugin provides common data access services. + +- `expressions` — run pipeline functions and render results. +- `filter` +- `index_patterns` +- `query` +- `search` diff --git a/src/legacy/core_plugins/interpreter/common/interpreter/create_error.js b/src/plugins/data/common/expressions/create_error.ts similarity index 95% rename from src/legacy/core_plugins/interpreter/common/interpreter/create_error.js rename to src/plugins/data/common/expressions/create_error.ts index 2740358b1c9605..78a12cb07c663e 100644 --- a/src/legacy/core_plugins/interpreter/common/interpreter/create_error.js +++ b/src/plugins/data/common/expressions/create_error.ts @@ -17,7 +17,7 @@ * under the License. */ -export const createError = err => ({ +export const createError = (err: any) => ({ type: 'error', error: { stack: process.env.NODE_ENV === 'production' ? undefined : err.stack, diff --git a/src/legacy/core_plugins/interpreter/common/types/boolean.ts b/src/plugins/data/common/expressions/expression_types/boolean.ts similarity index 96% rename from src/legacy/core_plugins/interpreter/common/types/boolean.ts rename to src/plugins/data/common/expressions/expression_types/boolean.ts index 6b68678cf11843..84beaf1cc66e51 100644 --- a/src/legacy/core_plugins/interpreter/common/types/boolean.ts +++ b/src/plugins/data/common/expressions/expression_types/boolean.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ExpressionType } from '../../types'; +import { ExpressionType } from '../types'; import { Datatable } from './datatable'; import { Render } from './render'; diff --git a/src/legacy/core_plugins/interpreter/common/types/datatable.ts b/src/plugins/data/common/expressions/expression_types/datatable.ts similarity index 99% rename from src/legacy/core_plugins/interpreter/common/types/datatable.ts rename to src/plugins/data/common/expressions/expression_types/datatable.ts index bc3eee640854fe..ef5e24278f4970 100644 --- a/src/legacy/core_plugins/interpreter/common/types/datatable.ts +++ b/src/plugins/data/common/expressions/expression_types/datatable.ts @@ -19,7 +19,7 @@ import { map, pick, zipObject } from 'lodash'; -import { ExpressionType } from '../../types'; +import { ExpressionType } from '../types'; import { PointSeries } from './pointseries'; import { Render } from './render'; diff --git a/src/legacy/core_plugins/interpreter/common/types/error.ts b/src/plugins/data/common/expressions/expression_types/error.ts similarity index 96% rename from src/legacy/core_plugins/interpreter/common/types/error.ts rename to src/plugins/data/common/expressions/expression_types/error.ts index 761c3ec4682675..ffafc1ecd91849 100644 --- a/src/legacy/core_plugins/interpreter/common/types/error.ts +++ b/src/plugins/data/common/expressions/expression_types/error.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ExpressionType } from '../../types'; +import { ExpressionType } from '../types'; import { Render } from './render'; const name = 'error'; diff --git a/src/legacy/core_plugins/interpreter/common/types/filter.ts b/src/plugins/data/common/expressions/expression_types/filter.ts similarity index 96% rename from src/legacy/core_plugins/interpreter/common/types/filter.ts rename to src/plugins/data/common/expressions/expression_types/filter.ts index 3fd63086cd7a34..2608da6854b180 100644 --- a/src/legacy/core_plugins/interpreter/common/types/filter.ts +++ b/src/plugins/data/common/expressions/expression_types/filter.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ExpressionType } from '../../types'; +import { ExpressionType } from '../types'; const name = 'filter'; diff --git a/src/legacy/core_plugins/interpreter/common/types/image.ts b/src/plugins/data/common/expressions/expression_types/image.ts similarity index 96% rename from src/legacy/core_plugins/interpreter/common/types/image.ts rename to src/plugins/data/common/expressions/expression_types/image.ts index b75ec4b5f237c5..b4b6b27bbc8bc0 100644 --- a/src/legacy/core_plugins/interpreter/common/types/image.ts +++ b/src/plugins/data/common/expressions/expression_types/image.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ExpressionType } from '../../types'; +import { ExpressionType } from '../types'; import { Render } from './render'; const name = 'image'; diff --git a/src/legacy/core_plugins/interpreter/common/types/index.ts b/src/plugins/data/common/expressions/expression_types/index.ts similarity index 100% rename from src/legacy/core_plugins/interpreter/common/types/index.ts rename to src/plugins/data/common/expressions/expression_types/index.ts diff --git a/src/legacy/core_plugins/interpreter/common/types/kibana_context.ts b/src/plugins/data/common/expressions/expression_types/kibana_context.ts similarity index 91% rename from src/legacy/core_plugins/interpreter/common/types/kibana_context.ts rename to src/plugins/data/common/expressions/expression_types/kibana_context.ts index 89c976611c8f04..1d5c4a22b3a0a5 100644 --- a/src/legacy/core_plugins/interpreter/common/types/kibana_context.ts +++ b/src/plugins/data/common/expressions/expression_types/kibana_context.ts @@ -17,12 +17,16 @@ * under the License. */ -import { Query } from 'src/legacy/core_plugins/data/public'; -import { TimeRange } from 'ui/timefilter/time_history'; import { Filter } from '@kbn/es-query'; +import { Query } from '../../query/types'; const name = 'kibana_context'; +interface TimeRange { + from: string; + to: string; +} + export interface KibanaContext { type: typeof name; query?: Query; diff --git a/src/legacy/core_plugins/interpreter/common/types/kibana_datatable.ts b/src/plugins/data/common/expressions/expression_types/kibana_datatable.ts similarity index 100% rename from src/legacy/core_plugins/interpreter/common/types/kibana_datatable.ts rename to src/plugins/data/common/expressions/expression_types/kibana_datatable.ts diff --git a/src/legacy/core_plugins/interpreter/common/types/null.ts b/src/plugins/data/common/expressions/expression_types/null.ts similarity index 95% rename from src/legacy/core_plugins/interpreter/common/types/null.ts rename to src/plugins/data/common/expressions/expression_types/null.ts index 98f75d688c8630..63039507870fc1 100644 --- a/src/legacy/core_plugins/interpreter/common/types/null.ts +++ b/src/plugins/data/common/expressions/expression_types/null.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ExpressionType } from '../../types'; +import { ExpressionType } from '../types'; const name = 'null'; diff --git a/src/legacy/core_plugins/interpreter/common/types/number.ts b/src/plugins/data/common/expressions/expression_types/number.ts similarity index 96% rename from src/legacy/core_plugins/interpreter/common/types/number.ts rename to src/plugins/data/common/expressions/expression_types/number.ts index aa8281a5eeb161..8434536f8f6b83 100644 --- a/src/legacy/core_plugins/interpreter/common/types/number.ts +++ b/src/plugins/data/common/expressions/expression_types/number.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ExpressionType } from '../../types'; +import { ExpressionType } from '../types'; import { Datatable } from './datatable'; import { Render } from './render'; diff --git a/src/legacy/core_plugins/interpreter/common/types/pointseries.ts b/src/plugins/data/common/expressions/expression_types/pointseries.ts similarity index 97% rename from src/legacy/core_plugins/interpreter/common/types/pointseries.ts rename to src/plugins/data/common/expressions/expression_types/pointseries.ts index bedbd596c5c173..dfad139dd20c57 100644 --- a/src/legacy/core_plugins/interpreter/common/types/pointseries.ts +++ b/src/plugins/data/common/expressions/expression_types/pointseries.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ExpressionType } from '../../types'; +import { ExpressionType } from '../types'; import { Datatable } from './datatable'; import { Render } from './render'; diff --git a/src/legacy/core_plugins/interpreter/common/types/range.ts b/src/plugins/data/common/expressions/expression_types/range.ts similarity index 94% rename from src/legacy/core_plugins/interpreter/common/types/range.ts rename to src/plugins/data/common/expressions/expression_types/range.ts index b08cc7b971de73..c1a0e4d2075fa8 100644 --- a/src/legacy/core_plugins/interpreter/common/types/range.ts +++ b/src/plugins/data/common/expressions/expression_types/range.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ExpressionType, Render } from '../../types'; +import { ExpressionType, Render } from '../../../common/expressions/types'; const name = 'range'; diff --git a/src/legacy/core_plugins/interpreter/common/types/render.ts b/src/plugins/data/common/expressions/expression_types/render.ts similarity index 96% rename from src/legacy/core_plugins/interpreter/common/types/render.ts rename to src/plugins/data/common/expressions/expression_types/render.ts index 80b04381e423ef..22c6e469eb7717 100644 --- a/src/legacy/core_plugins/interpreter/common/types/render.ts +++ b/src/plugins/data/common/expressions/expression_types/render.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ExpressionType } from '../../types'; +import { ExpressionType } from '../types'; const name = 'render'; diff --git a/src/legacy/core_plugins/interpreter/common/types/shape.ts b/src/plugins/data/common/expressions/expression_types/shape.ts similarity index 95% rename from src/legacy/core_plugins/interpreter/common/types/shape.ts rename to src/plugins/data/common/expressions/expression_types/shape.ts index 3f51fb8e7873d6..434bab97e40379 100644 --- a/src/legacy/core_plugins/interpreter/common/types/shape.ts +++ b/src/plugins/data/common/expressions/expression_types/shape.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ExpressionType } from '../../types'; +import { ExpressionType } from '../types'; import { Render } from './render'; const name = 'shape'; diff --git a/src/legacy/core_plugins/interpreter/common/types/string.ts b/src/plugins/data/common/expressions/expression_types/string.ts similarity index 96% rename from src/legacy/core_plugins/interpreter/common/types/string.ts rename to src/plugins/data/common/expressions/expression_types/string.ts index 63be3d989caae0..52b7c351896128 100644 --- a/src/legacy/core_plugins/interpreter/common/types/string.ts +++ b/src/plugins/data/common/expressions/expression_types/string.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ExpressionType } from '../../types'; +import { ExpressionType } from '../types'; import { Datatable } from './datatable'; import { Render } from './render'; diff --git a/src/legacy/core_plugins/interpreter/common/types/style.ts b/src/plugins/data/common/expressions/expression_types/style.ts similarity index 95% rename from src/legacy/core_plugins/interpreter/common/types/style.ts rename to src/plugins/data/common/expressions/expression_types/style.ts index b74dd658e9dce2..f6ef0f1fe42e6a 100644 --- a/src/legacy/core_plugins/interpreter/common/types/style.ts +++ b/src/plugins/data/common/expressions/expression_types/style.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ExpressionType } from '../../types'; +import { ExpressionType } from '../types'; const name = 'style'; diff --git a/src/legacy/core_plugins/interpreter/common/constants.js b/src/plugins/data/common/expressions/index.ts similarity index 94% rename from src/legacy/core_plugins/interpreter/common/constants.js rename to src/plugins/data/common/expressions/index.ts index 6b07791576a1d0..d8f7b5091eb8f6 100644 --- a/src/legacy/core_plugins/interpreter/common/constants.js +++ b/src/plugins/data/common/expressions/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export const API_ROUTE = '/api/interpreter'; +export * from './types'; diff --git a/src/legacy/core_plugins/interpreter/common/type.js b/src/plugins/data/common/expressions/interpreter.ts similarity index 66% rename from src/legacy/core_plugins/interpreter/common/type.js rename to src/plugins/data/common/expressions/interpreter.ts index 448449bf45ab2e..07146b6eb31810 100644 --- a/src/legacy/core_plugins/interpreter/common/type.js +++ b/src/plugins/data/common/expressions/interpreter.ts @@ -17,13 +17,18 @@ * under the License. */ -// All types must be universal and be castable on the client or on the server import { get } from 'lodash'; -import { getType } from '@kbn/interpreter/common'; -// TODO: Currently all casting functions must be syncronous. +function getType(node: any) { + if (node == null) return 'null'; + if (typeof node === 'object') { + if (!node.type) throw new Error('Objects must have a type property'); + return node.type; + } + return typeof node; +} -export function Type(config) { +export function Type(this: any, config: any) { // Required this.name = config.name; @@ -40,28 +45,27 @@ export function Type(config) { this.serialize = config.serialize; this.deserialize = config.deserialize; - const getToFn = type => get(config, ['to', type]) || get(config, ['to', '*']); - const getFromFn = type => get(config, ['from', type]) || get(config, ['from', '*']); + const getToFn = (type: any) => get(config, ['to', type]) || get(config, ['to', '*']); + const getFromFn = (type: any) => get(config, ['from', type]) || get(config, ['from', '*']); - this.castsTo = type => typeof getToFn(type) === 'function'; - this.castsFrom = type => typeof getFromFn(type) === 'function'; + this.castsTo = (type: any) => typeof getToFn(type) === 'function'; + this.castsFrom = (type: any) => typeof getFromFn(type) === 'function'; - this.to = (node, toTypeName, types) => { + this.to = (node: any, toTypeName: any, types: any) => { const typeName = getType(node); if (typeName !== this.name) { throw new Error(`Can not cast object of type '${typeName}' using '${this.name}'`); - } - else if (!this.castsTo(toTypeName)) { + } else if (!this.castsTo(toTypeName)) { throw new Error(`Can not cast '${typeName}' to '${toTypeName}'`); } - return getToFn(toTypeName)(node, types); + return (getToFn(toTypeName) as any)(node, types); }; - this.from = (node, types) => { + this.from = (node: any, types: any) => { const typeName = getType(node); if (!this.castsFrom(typeName)) throw new Error(`Can not cast '${this.name}' from ${typeName}`); - return getFromFn(typeName)(node, types); + return (getFromFn(typeName) as any)(node, types); }; } diff --git a/src/legacy/core_plugins/interpreter/common/interpreter/interpret.js b/src/plugins/data/common/expressions/interpreter_provider.ts similarity index 80% rename from src/legacy/core_plugins/interpreter/common/interpreter/interpret.js rename to src/plugins/data/common/expressions/interpreter_provider.ts index 68e1d251c950f3..ed26701de5d871 100644 --- a/src/legacy/core_plugins/interpreter/common/interpreter/interpret.js +++ b/src/plugins/data/common/expressions/interpreter_provider.ts @@ -17,19 +17,25 @@ * under the License. */ -import clone from 'lodash.clone'; -import { each, keys, last, mapValues, reduce, zipObject } from 'lodash'; -import { getType, fromExpression, getByAlias, castProvider } from '@kbn/interpreter/common'; +/* eslint-disable @typescript-eslint/no-var-requires */ +import { clone, each, keys, last, mapValues, reduce, zipObject } from 'lodash'; + +// @ts-ignore +import { fromExpression, getType, getByAlias, castProvider } from '@kbn/interpreter/common'; + import { createError } from './create_error'; +import { ExpressionAST } from './types'; + +export { createError }; -export function interpreterProvider(config) { +export function interpreterProvider(config: any) { const { functions, types } = config; const handlers = { ...config.handlers, types }; const cast = castProvider(types); return interpret; - async function interpret(node, context = null) { + async function interpret(node: ExpressionAST, context = null) { switch (getType(node)) { case 'expression': return invokeChain(node.chain, context); @@ -43,7 +49,7 @@ export function interpreterProvider(config) { } } - async function invokeChain(chainArr, context) { + async function invokeChain(chainArr: any, context: any): Promise { if (!chainArr.length) return Promise.resolve(context); const chain = clone(chainArr); @@ -75,7 +81,7 @@ export function interpreterProvider(config) { } } - async function invokeFunction(fnDef, context, args) { + async function invokeFunction(fnDef: any, context: any, args: any): Promise { // Check function input. const acceptableContext = cast(context, fnDef.context.types); const fnOutput = await fnDef.fn(acceptableContext, args, handlers); @@ -105,23 +111,23 @@ export function interpreterProvider(config) { } // Processes the multi-valued AST argument values into arguments that can be passed to the function - async function resolveArgs(fnDef, context, argAsts) { + async function resolveArgs(fnDef: any, context: any, argAsts: any): Promise { const argDefs = fnDef.args; // Use the non-alias name from the argument definition const dealiasedArgAsts = reduce( argAsts, - (argAsts, argAst, argName) => { + (acc, argAst, argName) => { const argDef = getByAlias(argDefs, argName); // TODO: Implement a system to allow for undeclared arguments if (!argDef) { throw new Error(`Unknown argument '${argName}' passed to function '${fnDef.name}'`); } - argAsts[argDef.name] = (argAsts[argDef.name] || []).concat(argAst); - return argAsts; + acc[argDef.name] = (acc[argDef.name] || []).concat(argAst); + return acc; }, - {} + {} as any ); // Check for missing required arguments @@ -144,25 +150,25 @@ export function interpreterProvider(config) { // Fill in default values from argument definition const argAstsWithDefaults = reduce( argDefs, - (argAsts, argDef, argName) => { - if (typeof argAsts[argName] === 'undefined' && typeof argDef.default !== 'undefined') { - argAsts[argName] = [fromExpression(argDef.default, 'argument')]; + (acc: any, argDef: any, argName: any) => { + if (typeof acc[argName] === 'undefined' && typeof argDef.default !== 'undefined') { + acc[argName] = [(fromExpression as any)(argDef.default, 'argument')]; } - return argAsts; + return acc; }, dealiasedArgAsts ); // Create the functions to resolve the argument ASTs into values // These are what are passed to the actual functions if you opt out of resolving - const resolveArgFns = mapValues(argAstsWithDefaults, (argAsts, argName) => { - return argAsts.map(argAst => { + const resolveArgFns = mapValues(argAstsWithDefaults, (asts, argName) => { + return asts.map((item: any) => { return async (ctx = context) => { - const newContext = await interpret(argAst, ctx); + const newContext = await interpret(item, ctx); // This is why when any sub-expression errors, the entire thing errors if (getType(newContext) === 'error') throw newContext.error; - return cast(newContext, argDefs[argName].types); + return cast(newContext, argDefs[argName as any].types); }; }); }); @@ -174,7 +180,7 @@ export function interpreterProvider(config) { argNames.map(argName => { const interpretFns = resolveArgFns[argName]; if (!argDefs[argName].resolve) return interpretFns; - return Promise.all(interpretFns.map(fn => fn())); + return Promise.all(interpretFns.map((fn: any) => fn())); }) ); @@ -182,8 +188,8 @@ export function interpreterProvider(config) { // Just return the last unless the argument definition allows multiple const resolvedArgs = mapValues(resolvedMultiArgs, (argValues, argName) => { - if (argDefs[argName].multi) return argValues; - return last(argValues); + if (argDefs[argName as any].multi) return argValues; + return last(argValues as any); }); // Return an object here because the arguments themselves might actually have a 'then' diff --git a/src/legacy/core_plugins/interpreter/common/serialize.js b/src/plugins/data/common/expressions/serialize_provider.ts similarity index 72% rename from src/legacy/core_plugins/interpreter/common/serialize.js rename to src/plugins/data/common/expressions/serialize_provider.ts index cbf53e6f9318d4..1bd06a38a25602 100644 --- a/src/legacy/core_plugins/interpreter/common/serialize.js +++ b/src/plugins/data/common/expressions/serialize_provider.ts @@ -18,19 +18,27 @@ */ import { get, identity } from 'lodash'; -import { getType } from '@kbn/interpreter/common'; -export function serializeProvider(types) { +export function getType(node: any) { + if (node == null) return 'null'; + if (typeof node === 'object') { + if (!node.type) throw new Error('Objects must have a type property'); + return node.type; + } + return typeof node; +} + +export function serializeProvider(types: any) { return { serialize: provider('serialize'), deserialize: provider('deserialize'), }; - function provider(key) { - return context => { + function provider(key: any) { + return (context: any) => { const type = getType(context); const typeDef = types[type]; - const fn = get(typeDef, key) || identity; + const fn: any = get(typeDef, key) || identity; return fn(context); }; } diff --git a/src/plugins/data/common/expressions/types/arguments.ts b/src/plugins/data/common/expressions/types/arguments.ts new file mode 100644 index 00000000000000..20bec9359a5937 --- /dev/null +++ b/src/plugins/data/common/expressions/types/arguments.ts @@ -0,0 +1,142 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { KnownTypeToString, TypeString, UnmappedTypeStrings } from './common'; + +/** + * This type represents all of the possible combinations of properties of an + * Argument in an Expression Function. The presence or absence of certain fields + * influence the shape and presence of others within each `arg` in the specification. + */ +export type ArgumentType = + | SingleArgumentType + | MultipleArgumentType + | UnresolvedSingleArgumentType + | UnresolvedMultipleArgumentType; + +/** + * Map the type within the the generic array to a string-based + * representation of the type. + */ +// prettier-ignore +type ArrayTypeToArgumentString = + T extends Array ? TypeString : + T extends null ? 'null' : + never; + +/** + * Map the return type of the function within the generic to a + * string-based representation of the return type. + */ +// prettier-ignore +type UnresolvedTypeToArgumentString = + T extends (...args: any) => infer ElementType ? TypeString : + T extends null ? 'null' : + never; + +/** + * Map the array-based return type of the function within the generic to a + * string-based representation of the return type. + */ +// prettier-ignore +type UnresolvedArrayTypeToArgumentString = + T extends Array<(...args: any) => infer ElementType> ? TypeString : + T extends (...args: any) => infer ElementType ? ArrayTypeToArgumentString : + T extends null ? 'null' : + never; + +/** A type containing properties common to all Function Arguments. */ +interface BaseArgumentType { + /** Alternate names for the Function valid for use in the Expression Editor */ + aliases?: string[]; + /** Help text for the Argument to be displayed in the Expression Editor */ + help: string; + /** Default options for the Argument */ + options?: T[]; + /** + * Is this Argument required? + * @default false + */ + required?: boolean; + /** + * If false, the Argument is supplied as a function to be invoked in the + * implementation, rather than a value. + * @default true + */ + resolve?: boolean; + /** Names of types that are valid values of the Argument. */ + types?: string[]; + /** The optional default value of the Argument. */ + default?: T | string; + /** + * If true, multiple values may be supplied to the Argument. + * @default false + */ + multi?: boolean; +} + +/** + * The `types` array in a `FunctionSpec` should contain string + * representations of the `ArgumentsSpec` types: + * + * `someArgument: boolean | string` results in `types: ['boolean', 'string']` + */ +type SingleArgumentType = BaseArgumentType & { + multi?: false; + resolve?: true; + types?: Array | UnmappedTypeStrings>; +}; + +/** + * If the `multi` property on the argument is true, the `types` array should + * contain string representations of the `ArgumentsSpec` array types: + * + * `someArgument: boolean[] | string[]` results in: `types: ['boolean', 'string']` + */ +type MultipleArgumentType = BaseArgumentType & { + multi: true; + resolve?: true; + types?: Array | UnmappedTypeStrings>; +}; + +/** + * If the `resolve` property on the arugument is false, the `types` array, if + * present, should contain string representations of the result of the argument + * function: + * + * `someArgument: () => string` results in `types: ['string']` + */ +type UnresolvedSingleArgumentType = BaseArgumentType & { + multi?: false; + resolve: false; + types?: Array | UnmappedTypeStrings>; +}; + +/** + * If the `resolve` property on the arugument is false, the `types` array, if + * present, should contain string representations of the result of the argument + * function: + * + * `someArgument: () => string[]` results in `types: ['string']` + */ +type UnresolvedMultipleArgumentType = BaseArgumentType & { + multi: true; + resolve: false; + types?: Array | UnmappedTypeStrings>; +}; diff --git a/src/plugins/data/common/expressions/types/common.ts b/src/plugins/data/common/expressions/types/common.ts new file mode 100644 index 00000000000000..55a3ed579c6869 --- /dev/null +++ b/src/plugins/data/common/expressions/types/common.ts @@ -0,0 +1,60 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * This can convert a type into a known Expression string representation of + * that type. For example, `TypeToString` will resolve to `'datatable'`. + * This allows Expression Functions to continue to specify their type in a + * simple string format. + */ +export type TypeToString = KnownTypeToString | UnmappedTypeStrings; + +/** + * Map the type of the generic to a string-based representation of the type. + * + * If the provided generic is its own type interface, we use the value of + * the `type` key as a string literal type for it. + */ +// prettier-ignore +export type KnownTypeToString = + T extends string ? 'string' : + T extends boolean ? 'boolean' : + T extends number ? 'number' : + T extends null ? 'null' : + T extends { type: string } ? T['type'] : + never; + +/** + * If the type extends a Promise, we still need to return the string representation: + * + * `someArgument: Promise` results in `types: ['boolean', 'string']` + */ +export type TypeString = KnownTypeToString>; + +/** + * Types used in Expressions that don't map to a primitive cleanly: + * + * `date` is typed as a number or string, and represents a date + */ +export type UnmappedTypeStrings = 'date' | 'filter'; + +/** + * Utility type: extracts returned type from a Promise. + */ +export type UnwrapPromise = T extends Promise ? P : T; diff --git a/src/plugins/data/common/expressions/types/functions.ts b/src/plugins/data/common/expressions/types/functions.ts new file mode 100644 index 00000000000000..d640e351c5640d --- /dev/null +++ b/src/plugins/data/common/expressions/types/functions.ts @@ -0,0 +1,47 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { ArgumentType } from './arguments'; +import { TypeToString, UnwrapPromise } from './common'; + +/** + * A generic type which represents an Expression Function definition. + */ +export interface ExpressionFunction { + /** Arguments for the Function */ + args: { [key in keyof Arguments]: ArgumentType }; + aliases?: string[]; + context?: { + types: Array>; + }; + /** Help text displayed in the Expression editor */ + help: string; + /** The name of the Function */ + name: Name; + /** The type of the Function */ + type?: TypeToString>; + /** The implementation of the Function */ + fn(context: Context, args: Arguments, handlers: FunctionHandlers): Return; +} + +// TODO: Handlers can be passed to the `fn` property of the Function. At the moment, these Functions +// are not strongly defined. +interface FunctionHandlers { + [key: string]: (...args: any) => any; +} diff --git a/src/plugins/data/common/expressions/types/index.ts b/src/plugins/data/common/expressions/types/index.ts new file mode 100644 index 00000000000000..06f19023320a2c --- /dev/null +++ b/src/plugins/data/common/expressions/types/index.ts @@ -0,0 +1,45 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { ArgumentType } from './arguments'; +export { + TypeToString, + KnownTypeToString, + TypeString, + UnmappedTypeStrings, + UnwrapPromise, +} from './common'; +export { ExpressionFunction } from './functions'; +export { ExpressionType } from './types'; +export * from '../expression_types'; + +export type ExpressionArgAST = string | boolean | number | ExpressionAST; + +export interface ExpressionFunctionAST { + type: 'function'; + function: string; + arguments: { + [key: string]: ExpressionArgAST[]; + }; +} + +export interface ExpressionAST { + type: 'expression'; + chain: ExpressionFunctionAST[]; +} diff --git a/src/plugins/data/common/expressions/types/types.ts b/src/plugins/data/common/expressions/types/types.ts new file mode 100644 index 00000000000000..a6c8a564a4484a --- /dev/null +++ b/src/plugins/data/common/expressions/types/types.ts @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * A generic type which represents a custom Expression Type Definition that's + * registered to the Interpreter. + */ +export interface ExpressionType { + name: Name; + validate?: (type: any) => void | Error; + serialize?: (type: Type) => SerializedType; + deserialize?: (type: SerializedType) => Type; + // TODO: Update typings for the `availableTypes` parameter once interfaces for this + // have been added elsewhere in the interpreter. + from?: Record) => Type>; + to?: Record) => unknown>; +} diff --git a/src/legacy/core_plugins/interpreter/public/registries/type_registry.js b/src/plugins/data/common/index.ts similarity index 87% rename from src/legacy/core_plugins/interpreter/public/registries/type_registry.js rename to src/plugins/data/common/index.ts index bd9189f719db0b..af870208f4865c 100644 --- a/src/legacy/core_plugins/interpreter/public/registries/type_registry.js +++ b/src/plugins/data/common/index.ts @@ -17,6 +17,4 @@ * under the License. */ -import { TypesRegistry } from '../../common/types_registry'; - -export const typesRegistry = new TypesRegistry(); +export * from './expressions'; diff --git a/src/legacy/core_plugins/interpreter/public/registries/functions_registry.js b/src/plugins/data/common/query/types.ts similarity index 86% rename from src/legacy/core_plugins/interpreter/public/registries/functions_registry.js rename to src/plugins/data/common/query/types.ts index 098314123ac006..61b5d5b2b7b4ad 100644 --- a/src/legacy/core_plugins/interpreter/public/registries/functions_registry.js +++ b/src/plugins/data/common/query/types.ts @@ -17,6 +17,7 @@ * under the License. */ -import { FunctionsRegistry } from '../../common/functions_registry'; - -export const functionsRegistry = new FunctionsRegistry(); +export interface Query { + query: string | { [key: string]: any }; + language: string; +} diff --git a/src/plugins/data/kibana.json b/src/plugins/data/kibana.json new file mode 100644 index 00000000000000..090c0218aabb7d --- /dev/null +++ b/src/plugins/data/kibana.json @@ -0,0 +1,6 @@ +{ + "id": "data", + "version": "8", + "server": true, + "ui": true +} diff --git a/src/plugins/data/public/expressions/expressions_service.ts b/src/plugins/data/public/expressions/expressions_service.ts new file mode 100644 index 00000000000000..329dadc81df285 --- /dev/null +++ b/src/plugins/data/public/expressions/expressions_service.ts @@ -0,0 +1,48 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { FunctionsRegistry, RenderFunctionsRegistry, TypesRegistry } from './interpreter'; +import { ExpressionType } from '../../common/expressions/types'; + +export class ExpressionsService { + private readonly functions = new FunctionsRegistry(); + private readonly renderers = new RenderFunctionsRegistry(); + private readonly types = new TypesRegistry(); + + public setup() { + const { functions, renderers, types } = this; + + return { + registerFunction: (fn: any) => { + this.functions.register(fn); + }, + registerRenderer: (renderer: any) => { + this.renderers.register(renderer); + }, + registerType: (type: () => ExpressionType) => { + this.types.register(type); + }, + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + functions, + renderers, + types, + }, + }; + } +} diff --git a/src/plugins/data/public/expressions/interpreter.ts b/src/plugins/data/public/expressions/interpreter.ts new file mode 100644 index 00000000000000..336d672f0a6218 --- /dev/null +++ b/src/plugins/data/public/expressions/interpreter.ts @@ -0,0 +1,173 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * @todo + * This whole file needs major refactoring. `Registry` class does not do anything + * useful. "Wrappers" like `RenderFunction` basically just set default props on the objects. + */ + +/* eslint-disable max-classes-per-file */ +import { clone, mapValues, includes } from 'lodash'; +import { Type } from '../../common/expressions/interpreter'; +import { ExpressionType } from '../../common/expressions/types'; + +export class Registry { + _prop: string; + _indexed: any; + + constructor(prop: string = 'name') { + if (typeof prop !== 'string') throw new Error('Registry property name must be a string'); + this._prop = prop; + this._indexed = new Object(); + } + + wrapper(obj: ItemSpec) { + return obj; + } + + register(fn: () => ItemSpec) { + if (typeof fn !== 'function') throw new Error(`Register requires an function`); + + const obj = fn() as any; + + if (typeof obj !== 'object' || !obj[this._prop]) { + throw new Error(`Registered functions must return an object with a ${this._prop} property`); + } + + this._indexed[obj[this._prop].toLowerCase()] = this.wrapper(obj); + } + + toJS(): Record { + return Object.keys(this._indexed).reduce( + (acc, key) => { + acc[key] = this.get(key); + return acc; + }, + {} as any + ); + } + + toArray(): Item[] { + return Object.keys(this._indexed).map(key => this.get(key)!); + } + + get(name: string): Item | null { + if (name === undefined) { + return null; + } + const lowerCaseName = name.toLowerCase(); + return this._indexed[lowerCaseName] ? clone(this._indexed[lowerCaseName]) : null; + } + + getProp(): string { + return this._prop; + } + + reset() { + this._indexed = new Object(); + } +} + +function RenderFunction(this: any, config: any) { + // This must match the name of the function that is used to create the `type: render` object + this.name = config.name; + + // Use this to set a more friendly name + this.displayName = config.displayName || this.name; + + // A sentence or few about what this element does + this.help = config.help; + + // used to validate the data before calling the render function + this.validate = config.validate || function validate() {}; + + // tell the renderer if the dom node should be reused, it's recreated each time by default + this.reuseDomNode = Boolean(config.reuseDomNode); + + // the function called to render the data + this.render = + config.render || + function render(domNode: any, data: any, done: any) { + done(); + }; +} + +export function Arg(this: any, config: any) { + if (config.name === '_') throw Error('Arg names must not be _. Use it in aliases instead.'); + this.name = config.name; + this.required = config.required || false; + this.help = config.help || ''; + this.types = config.types || []; + this.default = config.default; + this.aliases = config.aliases || []; + this.multi = config.multi == null ? false : config.multi; + this.resolve = config.resolve == null ? true : config.resolve; + this.options = config.options || []; + this.accepts = (type: any) => { + if (!this.types.length) return true; + return includes(config.types, type); + }; +} + +export function Fn(this: any, config: any) { + // Required + this.name = config.name; // Name of function + + // Return type of function. + // This SHOULD be supplied. We use it for UI and autocomplete hinting, + // We may also use it for optimizations in the future. + this.type = config.type; + this.aliases = config.aliases || []; + + // Function to run function (context, args) + this.fn = (...args: any) => Promise.resolve(config.fn(...args)); + + // Optional + this.help = config.help || ''; // A short help text + this.args = mapValues( + config.args || {}, + (arg: any, name: any) => new (Arg as any)({ name, ...arg }) + ); + + this.context = config.context || {}; + + this.accepts = (type: any) => { + if (!this.context.types) return true; // If you don't tell us about context, we'll assume you don't care what you get + return includes(this.context.types, type); // Otherwise, check it + }; +} + +export class RenderFunctionsRegistry extends Registry { + wrapper(obj: any) { + return new (RenderFunction as any)(obj); + } +} + +export class FunctionsRegistry extends Registry { + wrapper(obj: any) { + return new (Fn as any)(obj); + } +} + +export class TypesRegistry extends Registry, any> { + wrapper(obj: any) { + return new (Type as any)(obj); + } +} diff --git a/src/legacy/core_plugins/interpreter/common/functions_registry.js b/src/plugins/data/public/index.ts similarity index 74% rename from src/legacy/core_plugins/interpreter/common/functions_registry.js rename to src/plugins/data/public/index.ts index fec36e9cb217ab..532a062b5b8dad 100644 --- a/src/legacy/core_plugins/interpreter/common/functions_registry.js +++ b/src/plugins/data/public/index.ts @@ -17,10 +17,11 @@ * under the License. */ -import { Fn, Registry } from '@kbn/interpreter/common'; +import { PluginInitializerContext } from '../../../core/public'; +import { DataPublicPlugin } from './plugin'; -export class FunctionsRegistry extends Registry { - wrapper(obj) { - return new Fn(obj); - } +export function plugin(initializerContext: PluginInitializerContext) { + return new DataPublicPlugin(initializerContext); } + +export { DataPublicPlugin as Plugin }; diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts new file mode 100644 index 00000000000000..96dcb7ca27fada --- /dev/null +++ b/src/plugins/data/public/plugin.ts @@ -0,0 +1,37 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../core/public'; +import { ExpressionsService } from './expressions/expressions_service'; + +export class DataPublicPlugin implements Plugin<{}> { + expressions = new ExpressionsService(); + + constructor(initializerContext: PluginInitializerContext) {} + + public setup(core: CoreSetup) { + const expressions = this.expressions.setup(); + return { + expressions, + }; + } + + public start(core: CoreStart) {} + public stop() {} +} diff --git a/src/legacy/core_plugins/interpreter/common/types_registry.js b/src/plugins/data/server/index.ts similarity index 74% rename from src/legacy/core_plugins/interpreter/common/types_registry.js rename to src/plugins/data/server/index.ts index 9872beb9c9b0ba..60734f25b46a37 100644 --- a/src/legacy/core_plugins/interpreter/common/types_registry.js +++ b/src/plugins/data/server/index.ts @@ -17,11 +17,11 @@ * under the License. */ -import { Registry } from '@kbn/interpreter/common'; -import { Type } from './type'; +import { PluginInitializerContext } from '../../../core/server'; +import { DataServerPlugin } from './plugin'; -export class TypesRegistry extends Registry { - wrapper(obj) { - return new Type(obj); - } +export function plugin(initializerContext: PluginInitializerContext) { + return new DataServerPlugin(initializerContext); } + +export { DataServerPlugin as Plugin }; diff --git a/src/legacy/core_plugins/interpreter/public/registries/renderer_registry.js b/src/plugins/data/server/plugin.ts similarity index 70% rename from src/legacy/core_plugins/interpreter/public/registries/renderer_registry.js rename to src/plugins/data/server/plugin.ts index 0f90cd5e53e74c..3aa04c7a5be7a4 100644 --- a/src/legacy/core_plugins/interpreter/public/registries/renderer_registry.js +++ b/src/plugins/data/server/plugin.ts @@ -17,6 +17,13 @@ * under the License. */ -import { RenderFunctionsRegistry } from '../lib/render_functions_registry'; +import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../core/server'; -export const renderersRegistry = new RenderFunctionsRegistry(); +export class DataServerPlugin implements Plugin { + constructor(initializerContext: PluginInitializerContext) {} + public setup(core: CoreSetup) {} + public start(core: CoreStart) {} + public stop() {} +} + +export { DataServerPlugin as Plugin }; diff --git a/src/plugins/testbed/public/plugin.ts b/src/plugins/testbed/public/plugin.ts index b690c7f9e79e1c..bf51dbf0b8e78a 100644 --- a/src/plugins/testbed/public/plugin.ts +++ b/src/plugins/testbed/public/plugin.ts @@ -32,6 +32,8 @@ export class TestbedPlugin implements Plugin; diff --git a/test/plugin_functional/plugins/core_plugin_a/public/plugin.tsx b/test/plugin_functional/plugins/core_plugin_a/public/plugin.tsx index aa8c50e6f59501..263e87a173ddf9 100644 --- a/test/plugin_functional/plugins/core_plugin_a/public/plugin.tsx +++ b/test/plugin_functional/plugins/core_plugin_a/public/plugin.tsx @@ -29,6 +29,7 @@ export class CorePluginAPlugin implements Plugin; diff --git a/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx b/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx index 680b3c2db7fb81..9ac49a88901445 100644 --- a/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx +++ b/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx @@ -37,6 +37,7 @@ export class CorePluginBPlugin } public start() {} + public stop() {} } export type CorePluginBPluginSetup = ReturnType;