mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* 「AppArch」Interpreter 👉 New Platform (#39329) * feat: 🎸 set-up NP data plugin * refactor: 💡 move interpreter functions registry to NP * refactor: 💡 move interpreter renderer registry to NP plugin * refactor: 💡 move interpreter typesRegistry to NP * refactor: 💡 move interpreter types to NP * chore: 🤖 import typeRegistry from NP and change TS type folder * refactor: 💡 move interpreter expression types to NP * refactor: 💡 move rest of interpreter common folder to NP plugin * fix: 🐛 fix TypeScript errors * test: 💍 improve typings and test mocks * refactor: 💡 make Interpreter internal registry impl private * test: 💍 inline NP backdoor mock creation in test suites * chore: 🤖 change @kbn/interpreter import paths to try fix errors * fix: 🐛 improve core Plugin interfaces * feat: 🎸 add stop() lifecycle to NP data plugins * refactor: 💡 move interpreter into expressions service data NP * refactor: 💡 inline Registry @kbn/interpreter class * refactor: 💡 remove dependency on @kbn/interpreter in data pub * refactor: 💡 move interpreter common dir into expressions dir * fix: 🐛 use TS types in kibana_context * feat: 🎸 add types suggested in PR review * feat: 🎸 add semantic interpreter registration functions * refactor: 💡 use require for all @kbn/interpreter imports * test: 💍 add Karma test mocks, thx @spalger 🙏 * docs: ✏️ update Core docs * test: 💍 add Sinon stubs for registries * chore: 🤖 change import syntax in hopes CI will work * chore: 🤖 set App Architecture as owners of data plugin * docs: ✏️ add README * chore: 🤖 change import in hopes to fix optimizer * fix: 🐛 make stop() plugin life-cycle optional * docs: ✏️ update Core API docs * test: 💍 remove unnecessary Jest mock * chore: 🤖 don't import from deeply inside a plugin * refactor: 💡 try different interpreter import * fix: 🐛 fix Karma mocking * fix: 🐛 fix TypeScript type imports * test: 💍 fix broken test * fix: 🐛 use "kibana" version to make it work everywhere * style: 💄 fix linter error
This commit is contained in:
parent
4a4d29eee2
commit
b057a93244
82 changed files with 1042 additions and 406 deletions
|
@ -9,14 +9,14 @@ The interface that should be returned by a `PluginInitializer`<!-- -->.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface Plugin<TSetup, TStart, TPluginsSetup extends Record<string, unknown> = {}, TPluginsStart extends Record<string, unknown> = {}>
|
||||
export interface Plugin<TSetup = void, TStart = void, TPluginsSetup extends {} = {}, TPluginsStart extends {} = {}>
|
||||
```
|
||||
|
||||
## Properties
|
||||
## Methods
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [setup](./kibana-plugin-public.plugin.setup.md) | <code>(core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise<TSetup></code> | |
|
||||
| [start](./kibana-plugin-public.plugin.start.md) | <code>(core: CoreStart, plugins: TPluginsStart) => TStart | Promise<TStart></code> | |
|
||||
| [stop](./kibana-plugin-public.plugin.stop.md) | <code>() => void</code> | |
|
||||
| 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) | |
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
setup: (core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise<TSetup>;
|
||||
setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise<TSetup>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| core | <code>CoreSetup</code> | |
|
||||
| plugins | <code>TPluginsSetup</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`TSetup | Promise<TSetup>`
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
start: (core: CoreStart, plugins: TPluginsStart) => TStart | Promise<TStart>;
|
||||
start(core: CoreStart, plugins: TPluginsStart): TStart | Promise<TStart>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| core | <code>CoreStart</code> | |
|
||||
| plugins | <code>TPluginsStart</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`TStart | Promise<TStart>`
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
stop?: () => void;
|
||||
stop?(): void;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`void`
|
||||
|
||||
|
|
|
@ -9,14 +9,14 @@ The interface that should be returned by a `PluginInitializer`<!-- -->.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface Plugin<TSetup, TStart, TPluginsSetup extends Record<PluginName, unknown> = {}, TPluginsStart extends Record<PluginName, unknown> = {}>
|
||||
export interface Plugin<TSetup = void, TStart = void, TPluginsSetup extends {} = {}, TPluginsStart extends {} = {}>
|
||||
```
|
||||
|
||||
## Properties
|
||||
## Methods
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [setup](./kibana-plugin-server.plugin.setup.md) | <code>(core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise<TSetup></code> | |
|
||||
| [start](./kibana-plugin-server.plugin.start.md) | <code>(core: CoreStart, plugins: TPluginsStart) => TStart | Promise<TStart></code> | |
|
||||
| [stop](./kibana-plugin-server.plugin.stop.md) | <code>() => void</code> | |
|
||||
| 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) | |
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
setup: (core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise<TSetup>;
|
||||
setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise<TSetup>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| core | <code>CoreSetup</code> | |
|
||||
| plugins | <code>TPluginsSetup</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`TSetup | Promise<TSetup>`
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
start: (core: CoreStart, plugins: TPluginsStart) => TStart | Promise<TStart>;
|
||||
start(core: CoreStart, plugins: TPluginsStart): TStart | Promise<TStart>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| core | <code>CoreStart</code> | |
|
||||
| plugins | <code>TPluginsStart</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`TStart | Promise<TStart>`
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
stop?: () => void;
|
||||
stop?(): void;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`void`
|
||||
|
||||
|
|
|
@ -28,14 +28,14 @@ import { CoreStart, CoreSetup } from '..';
|
|||
* @public
|
||||
*/
|
||||
export interface Plugin<
|
||||
TSetup,
|
||||
TStart,
|
||||
TPluginsSetup extends Record<string, unknown> = {},
|
||||
TPluginsStart extends Record<string, unknown> = {}
|
||||
TSetup = void,
|
||||
TStart = void,
|
||||
TPluginsSetup extends {} = {},
|
||||
TPluginsStart extends {} = {}
|
||||
> {
|
||||
setup: (core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise<TSetup>;
|
||||
start: (core: CoreStart, plugins: TPluginsStart) => TStart | Promise<TStart>;
|
||||
stop?: () => void;
|
||||
setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise<TSetup>;
|
||||
start(core: CoreStart, plugins: TPluginsStart): TStart | Promise<TStart>;
|
||||
stop?(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -475,13 +475,13 @@ export interface OverlayStart {
|
|||
}
|
||||
|
||||
// @public
|
||||
export interface Plugin<TSetup, TStart, TPluginsSetup extends Record<string, unknown> = {}, TPluginsStart extends Record<string, unknown> = {}> {
|
||||
export interface Plugin<TSetup = void, TStart = void, TPluginsSetup extends {} = {}, TPluginsStart extends {} = {}> {
|
||||
// (undocumented)
|
||||
setup: (core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise<TSetup>;
|
||||
setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise<TSetup>;
|
||||
// (undocumented)
|
||||
start: (core: CoreStart, plugins: TPluginsStart) => TStart | Promise<TStart>;
|
||||
start(core: CoreStart, plugins: TPluginsStart): TStart | Promise<TStart>;
|
||||
// (undocumented)
|
||||
stop?: () => void;
|
||||
stop?(): void;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
|
|
@ -136,14 +136,14 @@ export interface DiscoveredPluginInternal extends DiscoveredPlugin {
|
|||
* @public
|
||||
*/
|
||||
export interface Plugin<
|
||||
TSetup,
|
||||
TStart,
|
||||
TPluginsSetup extends Record<PluginName, unknown> = {},
|
||||
TPluginsStart extends Record<PluginName, unknown> = {}
|
||||
TSetup = void,
|
||||
TStart = void,
|
||||
TPluginsSetup extends {} = {},
|
||||
TPluginsStart extends {} = {}
|
||||
> {
|
||||
setup: (core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise<TSetup>;
|
||||
start: (core: CoreStart, plugins: TPluginsStart) => TStart | Promise<TStart>;
|
||||
stop?: () => void;
|
||||
setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise<TSetup>;
|
||||
start(core: CoreStart, plugins: TPluginsStart): TStart | Promise<TStart>;
|
||||
stop?(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -329,13 +329,13 @@ export interface OnPreAuthToolkit {
|
|||
}
|
||||
|
||||
// @public
|
||||
export interface Plugin<TSetup, TStart, TPluginsSetup extends Record<PluginName, unknown> = {}, TPluginsStart extends Record<PluginName, unknown> = {}> {
|
||||
export interface Plugin<TSetup = void, TStart = void, TPluginsSetup extends {} = {}, TPluginsStart extends {} = {}> {
|
||||
// (undocumented)
|
||||
setup: (core: CoreSetup, plugins: TPluginsSetup) => TSetup | Promise<TSetup>;
|
||||
setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise<TSetup>;
|
||||
// (undocumented)
|
||||
start: (core: CoreStart, plugins: TPluginsStart) => TStart | Promise<TStart>;
|
||||
start(core: CoreStart, plugins: TPluginsStart): TStart | Promise<TStart>;
|
||||
// (undocumented)
|
||||
stop?: () => void;
|
||||
stop?(): void;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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<any, any> {
|
||||
wrapper(obj: any) {
|
||||
return new (Type as any)(obj);
|
||||
}
|
||||
}
|
||||
|
||||
export class FunctionsRegistry extends Registry<any, any> {
|
||||
wrapper(obj: any) {
|
||||
return new Fn(obj);
|
||||
}
|
||||
}
|
||||
|
||||
export const registries = {
|
||||
types: new TypesRegistry(),
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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: () => ({}) }),
|
||||
}));
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -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 };
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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<T> =
|
||||
| SingleArgumentType<T>
|
||||
| MultipleArgumentType<T>
|
||||
| UnresolvedSingleArgumentType<T>
|
||||
| UnresolvedMultipleArgumentType<T>;
|
||||
|
||||
/**
|
||||
* Map the type within the the generic array to a string-based
|
||||
* representation of the type.
|
||||
*/
|
||||
// prettier-ignore
|
||||
type ArrayTypeToArgumentString<T> =
|
||||
T extends Array<infer ElementType> ? TypeString<ElementType> :
|
||||
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> =
|
||||
T extends (...args: any) => infer ElementType ? TypeString<ElementType> :
|
||||
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> =
|
||||
T extends Array<(...args: any) => infer ElementType> ? TypeString<ElementType> :
|
||||
T extends (...args: any) => infer ElementType ? ArrayTypeToArgumentString<ElementType> :
|
||||
T extends null ? 'null' :
|
||||
never;
|
||||
|
||||
/** A type containing properties common to all Function Arguments. */
|
||||
interface BaseArgumentType<T> {
|
||||
/** 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<T> = BaseArgumentType<T> & {
|
||||
multi?: false;
|
||||
resolve?: true;
|
||||
types?: Array<KnownTypeToString<T> | 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<T> = BaseArgumentType<T> & {
|
||||
multi: true;
|
||||
resolve?: true;
|
||||
types?: Array<ArrayTypeToArgumentString<T> | 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<T> = BaseArgumentType<T> & {
|
||||
multi?: false;
|
||||
resolve: false;
|
||||
types?: Array<UnresolvedTypeToArgumentString<T> | 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<T> = BaseArgumentType<T> & {
|
||||
multi: true;
|
||||
resolve: false;
|
||||
types?: Array<UnresolvedArrayTypeToArgumentString<T> | UnmappedTypeStrings>;
|
||||
};
|
||||
export * from '../../../../plugins/data/common/expressions/types/arguments';
|
||||
|
|
|
@ -17,44 +17,4 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This can convert a type into a known Expression string representation of
|
||||
* that type. For example, `TypeToString<Datatable>` will resolve to `'datatable'`.
|
||||
* This allows Expression Functions to continue to specify their type in a
|
||||
* simple string format.
|
||||
*/
|
||||
export type TypeToString<T> = KnownTypeToString<T> | 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> =
|
||||
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<boolean | string>` results in `types: ['boolean', 'string']`
|
||||
*/
|
||||
export type TypeString<T> = KnownTypeToString<UnwrapPromise<T>>;
|
||||
|
||||
/**
|
||||
* 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> = T extends Promise<infer P> ? P : T;
|
||||
export * from '../../../../plugins/data/common/expressions/types/common';
|
||||
|
|
|
@ -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<Name extends string, Context, Arguments, Return> {
|
||||
/** Arguments for the Function */
|
||||
args: { [key in keyof Arguments]: ArgumentType<Arguments[key]> };
|
||||
aliases?: string[];
|
||||
context?: {
|
||||
types: Array<TypeToString<Context>>;
|
||||
};
|
||||
/** Help text displayed in the Expression editor */
|
||||
help: string;
|
||||
/** The name of the Function */
|
||||
name: Name;
|
||||
/** The type of the Function */
|
||||
type?: TypeToString<UnwrapPromise<Return>>;
|
||||
/** 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';
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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 extends string, Type, SerializedType = undefined> {
|
||||
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<string, (ctx: any, availableTypes: Record<string, any>) => Type>;
|
||||
to?: Record<string, (type: Type, availableTypes: Record<string, any>) => unknown>;
|
||||
}
|
||||
export * from '../../../../plugins/data/common/expressions/types/types';
|
||||
|
|
|
@ -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'],
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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: [] }],
|
||||
}));
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
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 = {
|
||||
|
|
68
src/legacy/ui/public/new_platform/index.test.mocks.ts
Normal file
68
src/legacy/ui/public/new_platform/index.test.mocks.ts
Normal file
|
@ -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: {},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
|
@ -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<DataPlugin['setup']>;
|
||||
}
|
||||
|
||||
export interface PluginsStart {
|
||||
data: ReturnType<DataPlugin['start']>;
|
||||
}
|
||||
|
||||
export const npSetup = {
|
||||
core: (null as unknown) as InternalCoreSetup,
|
||||
plugins: {} as Record<string, unknown>,
|
||||
plugins: {} as PluginsSetup,
|
||||
};
|
||||
|
||||
export const npStart = {
|
||||
core: (null as unknown) as InternalCoreStart,
|
||||
plugins: {} as Record<string, unknown>,
|
||||
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<string, unknown>) {
|
||||
export function __setup__(coreSetup: InternalCoreSetup, plugins: PluginsSetup) {
|
||||
npSetup.core = coreSetup;
|
||||
npSetup.plugins = plugins;
|
||||
}
|
||||
|
||||
export function __start__(coreStart: InternalCoreStart, plugins: Record<string, unknown>) {
|
||||
export function __start__(coreStart: InternalCoreStart, plugins: PluginsStart) {
|
||||
npStart.core = coreStart;
|
||||
npStart.plugins = plugins;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
9
src/plugins/data/README.md
Normal file
9
src/plugins/data/README.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# data
|
||||
|
||||
`data` plugin provides common data access services.
|
||||
|
||||
- `expressions` — run pipeline functions and render results.
|
||||
- `filter`
|
||||
- `index_patterns`
|
||||
- `query`
|
||||
- `search`
|
|
@ -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,
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ExpressionType } from '../../types';
|
||||
import { ExpressionType } from '../types';
|
||||
import { Datatable } from './datatable';
|
||||
import { Render } from './render';
|
||||
|
|
@ -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';
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ExpressionType } from '../../types';
|
||||
import { ExpressionType } from '../types';
|
||||
import { Render } from './render';
|
||||
|
||||
const name = 'error';
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ExpressionType } from '../../types';
|
||||
import { ExpressionType } from '../types';
|
||||
|
||||
const name = 'filter';
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ExpressionType } from '../../types';
|
||||
import { ExpressionType } from '../types';
|
||||
import { Render } from './render';
|
||||
|
||||
const name = 'image';
|
|
@ -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;
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ExpressionType } from '../../types';
|
||||
import { ExpressionType } from '../types';
|
||||
|
||||
const name = 'null';
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ExpressionType } from '../../types';
|
||||
import { ExpressionType } from '../types';
|
||||
import { Datatable } from './datatable';
|
||||
import { Render } from './render';
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ExpressionType } from '../../types';
|
||||
import { ExpressionType } from '../types';
|
||||
import { Datatable } from './datatable';
|
||||
import { Render } from './render';
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ExpressionType, Render } from '../../types';
|
||||
import { ExpressionType, Render } from '../../../common/expressions/types';
|
||||
|
||||
const name = 'range';
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ExpressionType } from '../../types';
|
||||
import { ExpressionType } from '../types';
|
||||
|
||||
const name = 'render';
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ExpressionType } from '../../types';
|
||||
import { ExpressionType } from '../types';
|
||||
import { Render } from './render';
|
||||
|
||||
const name = 'shape';
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ExpressionType } from '../../types';
|
||||
import { ExpressionType } from '../types';
|
||||
import { Datatable } from './datatable';
|
||||
import { Render } from './render';
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ExpressionType } from '../../types';
|
||||
import { ExpressionType } from '../types';
|
||||
|
||||
const name = 'style';
|
||||
|
|
@ -17,4 +17,4 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export const API_ROUTE = '/api/interpreter';
|
||||
export * from './types';
|
|
@ -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);
|
||||
};
|
||||
}
|
|
@ -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';
|
||||
import { createError } from './create_error';
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
import { clone, each, keys, last, mapValues, reduce, zipObject } from 'lodash';
|
||||
|
||||
export function interpreterProvider(config) {
|
||||
// @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: 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<any> {
|
||||
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<any> {
|
||||
// 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<any> {
|
||||
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'
|
|
@ -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);
|
||||
};
|
||||
}
|
142
src/plugins/data/common/expressions/types/arguments.ts
Normal file
142
src/plugins/data/common/expressions/types/arguments.ts
Normal file
|
@ -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<T> =
|
||||
| SingleArgumentType<T>
|
||||
| MultipleArgumentType<T>
|
||||
| UnresolvedSingleArgumentType<T>
|
||||
| UnresolvedMultipleArgumentType<T>;
|
||||
|
||||
/**
|
||||
* Map the type within the the generic array to a string-based
|
||||
* representation of the type.
|
||||
*/
|
||||
// prettier-ignore
|
||||
type ArrayTypeToArgumentString<T> =
|
||||
T extends Array<infer ElementType> ? TypeString<ElementType> :
|
||||
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> =
|
||||
T extends (...args: any) => infer ElementType ? TypeString<ElementType> :
|
||||
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> =
|
||||
T extends Array<(...args: any) => infer ElementType> ? TypeString<ElementType> :
|
||||
T extends (...args: any) => infer ElementType ? ArrayTypeToArgumentString<ElementType> :
|
||||
T extends null ? 'null' :
|
||||
never;
|
||||
|
||||
/** A type containing properties common to all Function Arguments. */
|
||||
interface BaseArgumentType<T> {
|
||||
/** 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<T> = BaseArgumentType<T> & {
|
||||
multi?: false;
|
||||
resolve?: true;
|
||||
types?: Array<KnownTypeToString<T> | 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<T> = BaseArgumentType<T> & {
|
||||
multi: true;
|
||||
resolve?: true;
|
||||
types?: Array<ArrayTypeToArgumentString<T> | 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<T> = BaseArgumentType<T> & {
|
||||
multi?: false;
|
||||
resolve: false;
|
||||
types?: Array<UnresolvedTypeToArgumentString<T> | 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<T> = BaseArgumentType<T> & {
|
||||
multi: true;
|
||||
resolve: false;
|
||||
types?: Array<UnresolvedArrayTypeToArgumentString<T> | UnmappedTypeStrings>;
|
||||
};
|
60
src/plugins/data/common/expressions/types/common.ts
Normal file
60
src/plugins/data/common/expressions/types/common.ts
Normal file
|
@ -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<Datatable>` will resolve to `'datatable'`.
|
||||
* This allows Expression Functions to continue to specify their type in a
|
||||
* simple string format.
|
||||
*/
|
||||
export type TypeToString<T> = KnownTypeToString<T> | 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> =
|
||||
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<boolean | string>` results in `types: ['boolean', 'string']`
|
||||
*/
|
||||
export type TypeString<T> = KnownTypeToString<UnwrapPromise<T>>;
|
||||
|
||||
/**
|
||||
* 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> = T extends Promise<infer P> ? P : T;
|
47
src/plugins/data/common/expressions/types/functions.ts
Normal file
47
src/plugins/data/common/expressions/types/functions.ts
Normal file
|
@ -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<Name extends string, Context, Arguments, Return> {
|
||||
/** Arguments for the Function */
|
||||
args: { [key in keyof Arguments]: ArgumentType<Arguments[key]> };
|
||||
aliases?: string[];
|
||||
context?: {
|
||||
types: Array<TypeToString<Context>>;
|
||||
};
|
||||
/** Help text displayed in the Expression editor */
|
||||
help: string;
|
||||
/** The name of the Function */
|
||||
name: Name;
|
||||
/** The type of the Function */
|
||||
type?: TypeToString<UnwrapPromise<Return>>;
|
||||
/** 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;
|
||||
}
|
45
src/plugins/data/common/expressions/types/index.ts
Normal file
45
src/plugins/data/common/expressions/types/index.ts
Normal file
|
@ -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[];
|
||||
}
|
33
src/plugins/data/common/expressions/types/types.ts
Normal file
33
src/plugins/data/common/expressions/types/types.ts
Normal file
|
@ -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 extends string, Type, SerializedType = undefined> {
|
||||
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<string, (ctx: any, availableTypes: Record<string, any>) => Type>;
|
||||
to?: Record<string, (type: Type, availableTypes: Record<string, any>) => unknown>;
|
||||
}
|
|
@ -17,6 +17,4 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { TypesRegistry } from '../../common/types_registry';
|
||||
|
||||
export const typesRegistry = new TypesRegistry();
|
||||
export * from './expressions';
|
|
@ -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;
|
||||
}
|
6
src/plugins/data/kibana.json
Normal file
6
src/plugins/data/kibana.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"id": "data",
|
||||
"version": "kibana",
|
||||
"server": true,
|
||||
"ui": true
|
||||
}
|
48
src/plugins/data/public/expressions/expressions_service.ts
Normal file
48
src/plugins/data/public/expressions/expressions_service.ts
Normal file
|
@ -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<any, any>) => {
|
||||
this.types.register(type);
|
||||
},
|
||||
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
|
||||
functions,
|
||||
renderers,
|
||||
types,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
173
src/plugins/data/public/expressions/interpreter.ts
Normal file
173
src/plugins/data/public/expressions/interpreter.ts
Normal file
|
@ -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<ItemSpec, Item> {
|
||||
_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<string, any> {
|
||||
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<any, any> {
|
||||
wrapper(obj: any) {
|
||||
return new (RenderFunction as any)(obj);
|
||||
}
|
||||
}
|
||||
|
||||
export class FunctionsRegistry extends Registry<any, any> {
|
||||
wrapper(obj: any) {
|
||||
return new (Fn as any)(obj);
|
||||
}
|
||||
}
|
||||
|
||||
export class TypesRegistry extends Registry<ExpressionType<any, any>, any> {
|
||||
wrapper(obj: any) {
|
||||
return new (Type as any)(obj);
|
||||
}
|
||||
}
|
|
@ -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 };
|
37
src/plugins/data/public/plugin.ts
Normal file
37
src/plugins/data/public/plugin.ts
Normal file
|
@ -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() {}
|
||||
}
|
|
@ -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 };
|
|
@ -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 };
|
|
@ -32,6 +32,8 @@ export class TestbedPlugin implements Plugin<TestbedPluginSetup, TestbedPluginSt
|
|||
// eslint-disable-next-line no-console
|
||||
console.log(`Testbed plugin started`);
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
}
|
||||
|
||||
export type TestbedPluginSetup = ReturnType<TestbedPlugin['setup']>;
|
||||
|
|
|
@ -29,6 +29,7 @@ export class CorePluginAPlugin implements Plugin<CorePluginAPluginSetup, CorePlu
|
|||
}
|
||||
|
||||
public start() {}
|
||||
public stop() {}
|
||||
}
|
||||
|
||||
export type CorePluginAPluginSetup = ReturnType<CorePluginAPlugin['setup']>;
|
||||
|
|
|
@ -37,6 +37,7 @@ export class CorePluginBPlugin
|
|||
}
|
||||
|
||||
public start() {}
|
||||
public stop() {}
|
||||
}
|
||||
|
||||
export type CorePluginBPluginSetup = ReturnType<CorePluginBPlugin['setup']>;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue