[7.x] [Canvas] Update Type Documentation (#38554) (#38821)

* Add docs; fix nits

* Updating documentation

* Tweaks

* Fix missed conversions
This commit is contained in:
Clint Andrew Hall 2019-06-12 17:45:03 -05:00 committed by GitHub
parent f1efbf0654
commit 78a6c3dd4e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 216 additions and 48 deletions

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { ExpressionFunction } from 'src/legacy/core_plugins/interpreter/public';
import { ContainerStyle } from '../types';
import { ContainerStyle, Overflow, BackgroundRepeat, BackgroundSize } from '../types';
import { getFunctionHelp, getFunctionErrors } from '../../strings';
// @ts-ignore untyped local
import { isValidUrl } from '../../../common/lib/url';
@ -55,13 +55,13 @@ export function containerStyle(): ExpressionFunction<
types: ['string'],
help: argHelp.backgroundSize,
default: 'contain',
options: ['contain', 'cover', 'auto'],
options: Object.values(BackgroundSize),
},
backgroundRepeat: {
types: ['string'],
help: argHelp.backgroundRepeat,
default: 'no-repeat',
options: ['repeat-x', 'repeat', 'space', 'round', 'no-repeat', 'space'],
options: Object.values(BackgroundRepeat),
},
opacity: {
types: ['number'],
@ -70,7 +70,7 @@ export function containerStyle(): ExpressionFunction<
overflow: {
types: ['string'],
help: argHelp.overflow,
options: ['visible', 'hidden', 'scroll', 'auto'],
options: Object.values(Overflow),
default: 'hidden',
},
},

View file

@ -9,7 +9,15 @@ import inlineStyle from 'inline-style';
import { ExpressionFunction } from 'src/legacy/core_plugins/interpreter/public';
import { openSans } from '../../../common/lib/fonts';
import { getFunctionHelp, getFunctionErrors } from '../../strings';
import { CSSStyle, FontFamily, FontWeight, Style, TextAlignment, TEXT_ALIGNMENTS } from '../types';
import {
CSSStyle,
FontFamily,
FontWeight,
TextDecoration,
Style,
TextAlignment,
FontStyle,
} from '../types';
interface Arguments {
align: TextAlignment;
@ -38,7 +46,7 @@ export function font(): ExpressionFunction<'font', null, Arguments, Style> {
align: {
default: 'left',
help: argHelp.align,
options: TEXT_ALIGNMENTS,
options: Object.values(TextAlignment),
types: ['string'],
},
color: {
@ -83,7 +91,7 @@ export function font(): ExpressionFunction<'font', null, Arguments, Style> {
if (!Object.values(FontWeight).includes(args.weight)) {
throw errors.invalidFontWeight(args.weight);
}
if (!TEXT_ALIGNMENTS.includes(args.align)) {
if (!Object.values(TextAlignment).includes(args.align)) {
throw errors.invalidTextAlignment(args.align);
}
@ -94,8 +102,8 @@ export function font(): ExpressionFunction<'font', null, Arguments, Style> {
const spec: CSSStyle = {
fontFamily: args.family,
fontWeight: args.weight,
fontStyle: args.italic ? 'italic' : 'normal',
textDecoration: args.underline ? 'underline' : 'none',
fontStyle: args.italic ? FontStyle.ITALIC : FontStyle.NORMAL,
textDecoration: args.underline ? TextDecoration.UNDERLINE : TextDecoration.NONE,
textAlign: args.align,
fontSize: `${args.size}px`, // apply font size as a pixel setting
lineHeight, // apply line height as a pixel setting

View file

@ -9,20 +9,80 @@ import { functions as commonFunctions } from '../../functions/common';
import { functions as browserFunctions } from '../../functions/browser';
import { functions as serverFunctions } from '../../functions/server';
// A reducing type for Function Factories to a base `Function`.
// This is useful for collecting all of the Functions and the concepts they share as
// one useable type.
/**
* A `ExpressionFunctionFactory` is a powerful type used for any function that produces
* an `ExpressionFunction`. If it does not meet the signature for such a function,
* or if it does not produce an `ExpressionFunction`, it will be typed as
* returning `never`.
*
* This type will, in turn, strongly-type both a factory that produces an
* `ExpressionFunction`, *and* the `ExpressionFunction` itself. This means one can
* effectively introspect properties from the factory in other places.
*
* As an example, given the following:
*
```
function foo(): ExpressionFunction<'foo', Context, Arguments, Return> {
// ...
}
```
*
* `foo` would be an `ExpressionFunctionFactory`. Using the `FunctionFactory` type allows one to
* introspect the generics from the `ExpressionFunction` without needing to access it
* directly:
*
```
type Baz = FunctionFactory<typeof foo>;
```
*
* Thus, in reality, and in a Typescript-enabled IDE, one would see the following definition
* for `Baz`:
*
```
type Baz = ExpressionFunction<"foo", Context, Arguments, Return>
```
*
* Why is this useful? Given a collection of `ExpressionFunctions` that have been registered
* with the `Interpreter`, you could take that collection and do any number of other
* introspected, strongly-typed operations.
*
* One example would to create a dictionary of all of the names of the `ExpressionFunctions`
* that have been registered:
*
```
const someFunctions = [
functionOne: ExpressionFunction<'functionOne', Context, Arguments, Return>,
functionTwo: ExpressionFunction<'functionTwo', Context, Arguments, Return>,
functionThree: ExpressionFunction<'functionThree', Context, Arguments, Return>,
];
export type FunctionName = FunctionFactory<typeof someFunctions[number]>['name'];
const name: FunctionName = 'functionOne'; // passes
const nonName: FunctionName = 'elastic`; // fails
```
*
* A more practical example would be to use the introspected generics to create dictionaries,
* like of help strings or documentation, that would contain only valid functions and their
* generics, but nothing extraneous. This is actually used in a number of built-in functions
* in Kibana and Canvas.
*/
// prettier-ignore
export type ExpressionFunctionFactory<Name extends string, Context, Arguments, Return> =
() => ExpressionFunction<Name, Context, Arguments, Return>;
/**
* `FunctionFactory` exists as a name shim between the `ExpressionFunction` type and
* the functions that already existed in Canvas. This type can likely be removed, and
* callsites converted, if `ExpressionFunctionFactory` is moved into the Interpreter, (perhaps
* with a shorter name).
*/
// prettier-ignore
export type FunctionFactory<FnFactory> =
FnFactory extends ExpressionFunctionFactory<infer Name, infer Context, infer Arguments, infer Return> ?
ExpressionFunction<Name, Context, Arguments, Return> :
never;
// A `ExpressionFunctionFactory` defines a function that produces a named `ExpressionFunction`.
// prettier-ignore
type ExpressionFunctionFactory<Name extends string, Context, Arguments, Return> =
() => ExpressionFunction<Name, Context, Arguments, Return>;
// A type containing all of the raw Function definitions in Canvas.
// prettier-ignore
type Functions =
@ -31,11 +91,11 @@ type Functions =
typeof browserFunctions[number];
/**
* A type containing all Canvas Functions.
* A union type of all Canvas Functions.
*/
export type AvailableFunctions = FunctionFactory<Functions>;
export type CanvasFunction = FunctionFactory<Functions>;
/**
* A type containing all Canvas Function names.
* A union type of all Canvas Function names.
*/
export type AvailableFunctionNames = AvailableFunctions['name'];
export type CanvasFunctionName = CanvasFunction['name'];

View file

@ -8,7 +8,36 @@ import { FontLabel } from '../../../common/lib/fonts';
export { FontLabel as FontFamily, FontValue } from '../../../common/lib/fonts';
/**
* Type containing font weights.
* Enum of supported CSS `background-repeat` properties.
*/
export enum BackgroundRepeat {
REPEAT = 'repeat',
REPEAT_NO = 'no-repeat',
REPEAT_X = 'repeat-x',
REPEAT_Y = 'repeat-y',
ROUND = 'round',
SPACE = 'space',
}
/**
* Enum of supported CSS `background-size` properties.
*/
export enum BackgroundSize {
AUTO = 'auto',
CONTAIN = 'contain',
COVER = 'cover',
}
/**
* Enum of supported CSS `font-style` properties.
*/
export enum FontStyle {
ITALIC = 'italic',
NORMAL = 'normal',
}
/**
* Enum of supported CSS `font-weight` properties.
*/
export enum FontWeight {
NORMAL = 'normal',
@ -27,14 +56,32 @@ export enum FontWeight {
}
/**
* Type containing valid text alignments.
* Enum of supported CSS `overflow` properties.
*/
export type TextAlignment = 'center' | 'left' | 'right' | 'justify';
export enum Overflow {
AUTO = 'auto',
HIDDEN = 'hidden',
SCROLL = 'scroll',
VISIBLE = 'visible',
}
/**
* Collection of text alignments.
* Enum of supported CSS `text-align` properties.
*/
export const TEXT_ALIGNMENTS: TextAlignment[] = ['center', 'left', 'right', 'justify'];
export enum TextAlignment {
CENTER = 'center',
JUSTIFY = 'justify',
LEFT = 'left',
RIGHT = 'right',
}
/**
* Enum of supported CSS `text-decoration` properties.
*/
export enum TextDecoration {
NONE = 'none',
UNDERLINE = 'underline',
}
/**
* Represents the various style properties that can be applied to an element.
@ -44,11 +91,11 @@ export interface CSSStyle {
fill?: string;
fontFamily?: FontLabel;
fontSize?: string;
fontStyle?: 'italic' | 'normal';
fontStyle?: FontStyle;
fontWeight?: FontWeight;
lineHeight?: number | string;
textAlign?: TextAlignment;
textDecoration?: 'underline' | 'none';
textDecoration?: TextDecoration;
}
/**
@ -60,10 +107,10 @@ export interface ContainerStyle {
padding: string | null;
backgroundColor: string | null;
backgroundImage: string | null;
backgroundSize: 'contain' | 'cover' | 'auto';
backgroundRepeat: 'repeat-x' | 'repeat' | 'space' | 'round' | 'no-repeat' | 'space';
backgroundSize: BackgroundSize;
backgroundRepeat: BackgroundRepeat;
opacity: number | null;
overflow: 'visible' | 'hidden' | 'scroll' | 'auto';
overflow: Overflow;
}
/**

View file

@ -5,7 +5,7 @@
*/
import { ExpressionFunction } from 'src/legacy/core_plugins/interpreter/public';
import { AvailableFunctions } from '../../functions/types';
import { CanvasFunction } from '../../functions/types';
import { UnionToIntersection } from '../../functions/types';
import { help as all } from './all';
@ -72,8 +72,33 @@ import { help as timefilterControl } from './timefilterControl';
import { help as urlparam } from './urlparam';
/**
* This type infers Function argument types. This allows for validation that every
* function argument has the correct help strings.
* This type defines an entry in the `FunctionHelpMap`. It uses
* an `ExpressionFunction` to infer its `Arguments` in order to strongly-type that
* entry.
*
* For example:
*
```
interface Arguments {
bar: string;
baz: number;
}
function foo(): ExpressionFunction<'foo', Context, Arguments, Return> {
// ...
}
const help: FunctionHelp<typeof foo> = {
help: 'Some help for foo',
args: {
bar: 'Help for bar.', // pass; error if missing
baz: 'Help for baz.', // pass; error if missing
zap: 'Help for zap.`, // error: zap doesn't exist
}
};
```
* This allows one to ensure each argument is present, and no extraneous arguments
* remain.
*/
export type FunctionHelp<T> = T extends ExpressionFunction<
infer Name,
@ -87,8 +112,22 @@ export type FunctionHelp<T> = T extends ExpressionFunction<
}
: never;
// This type infers a Function name and Arguments to ensure every Function is defined
// in the `dict` and all Arguments have help strings.
// This internal type infers a Function name and uses `FunctionHelp` above to build
// a dictionary entry. This can be used to ensure every Function is defined and all
// Arguments have help strings.
//
// For example:
//
// function foo(): ExpressionFunction<'foo', Context, Arguments, Return> {
// // ...
// }
//
// const map: FunctionHelpMap<typeof foo> = {
// foo: FunctionHelp<typeof foo>,
// }
//
// Given a collection of functions, the map would contain each entry.
//
type FunctionHelpMap<T> = T extends ExpressionFunction<
infer Name,
infer Context,
@ -98,17 +137,17 @@ type FunctionHelpMap<T> = T extends ExpressionFunction<
? { [key in Name]: FunctionHelp<T> }
: never;
// This type represents an exhaustive dictionary of Function help strings,
// organized by Function and then Function Argument.
// This internal type represents an exhaustive dictionary of `FunctionHelp` types,
// organized by Function Name and then Function Argument.
//
// This type indexes the existing function factories, reverses the union to an
// intersection, and produces the dictionary of strings.
type FunctionHelpDict = UnionToIntersection<FunctionHelpMap<AvailableFunctions>>;
type FunctionHelpDict = UnionToIntersection<FunctionHelpMap<CanvasFunction>>;
/**
* Help text for Canvas Functions should be properly localized. This function will
* return a dictionary of help strings, organized by Canvas Function specification
* and then by available arguments.
* return a dictionary of help strings, organized by `CanvasFunction` specification
* and then by available arguments within each `CanvasFunction`.
*
* This a function, rather than an object, to future-proof string initialization,
* if ever necessary.

View file

@ -4,20 +4,31 @@
* you may not use this file except in compliance with the Elastic License.
*/
export type FontValue = typeof fonts[number]['value'];
/**
* This type contains a unions of all supported font labels, or the the name of
* the font the user would see in a UI.
*/
export type FontLabel = typeof fonts[number]['label'];
/**
* This type contains a union of all supported font values, equivalent to the CSS
* `font-value` property.
*/
export type FontValue = typeof fonts[number]['value'];
/**
* An interface representing a font in Canvas, with a textual label and the CSS
* `font-value`.
*/
export interface Font {
label: FontLabel;
value: FontValue;
}
/**
* This function allows one to create a strongly-typed font for inclusion in
* the font collection. As a result, the values and labels are known to the
* type system, preventing one from specifying a non-existent font at build
* time.
*/
// This function allows one to create a strongly-typed font for inclusion in
// the font collection. As a result, the values and labels are known to the
// type system, preventing one from specifying a non-existent font at build
// time.
function createFont<
RawFont extends { value: RawFontValue; label: RawFontLabel },
RawFontValue extends string,
@ -104,6 +115,9 @@ export const palatino = createFont({
value: "Palatino, 'Book Antiqua', Georgia, Garamond, 'Times New Roman', Times, serif",
});
/**
* A collection of supported fonts.
*/
export const fonts = [
americanTypewriter,
arial,