mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Test: TypeScript type specification strength tests (#32905)
* Test: TypeScript type specification strength tests * Chore: post-merge lint * Post-merge conflict fix
This commit is contained in:
parent
407c35b9a6
commit
45d6453fa7
11 changed files with 153 additions and 29 deletions
|
@ -48,6 +48,7 @@
|
|||
"test:ui:runner": "node scripts/functional_test_runner",
|
||||
"test:server": "grunt test:server",
|
||||
"test:coverage": "grunt test:coverage",
|
||||
"typespec": "typings-tester --config x-pack/plugins/canvas/public/lib/aeroelastic/tsconfig.json x-pack/plugins/canvas/public/lib/aeroelastic/__fixtures__/typescript/typespec_tests.ts",
|
||||
"checkLicenses": "grunt licenses --dev",
|
||||
"build": "node scripts/build --all-platforms",
|
||||
"start": "node --trace-warnings --trace-deprecation scripts/kibana --dev ",
|
||||
|
@ -409,6 +410,7 @@
|
|||
"tslint-microsoft-contrib": "^6.0.0",
|
||||
"tslint-plugin-prettier": "^2.0.0",
|
||||
"typescript": "^3.3.3333",
|
||||
"typings-tester": "^0.3.2",
|
||||
"vinyl-fs": "^3.0.2",
|
||||
"xml2js": "^0.4.19",
|
||||
"xmlbuilder": "9.0.4",
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
import { select } from '../../select';
|
||||
import { Json, Selector } from '../..';
|
||||
|
||||
/*
|
||||
|
||||
Type checking isn't too useful if future commits can accidentally weaken the type constraints, because a
|
||||
TypeScript linter will not complain - everything that passed before will continue to pass. The coder
|
||||
will not have feedback that the original intent with the typing got compromised. To declare the intent
|
||||
via passing and failing type checks, test cases are needed, some of which designed to expect a TS pass,
|
||||
some of them to expect a TS complaint. It documents intent for peers too, as type specs are a tough read.
|
||||
|
||||
Run compile-time type specification tests in the `kibana` root with:
|
||||
|
||||
yarn typespec
|
||||
|
||||
Test "cases" expecting to pass TS checks are not annotated, while ones we want TS to complain about
|
||||
are prepended with the comment
|
||||
|
||||
// typings:expect-error
|
||||
|
||||
The test "suite" and "cases" are wrapped in IIFEs to prevent linters from complaining about the unused
|
||||
binding. It can be structured internally as desired.
|
||||
|
||||
*/
|
||||
|
||||
((): void => {
|
||||
/**
|
||||
* TYPE TEST SUITE
|
||||
*/
|
||||
|
||||
(function jsonTests(plain: Json): void {
|
||||
// numbers are OK
|
||||
plain = 1;
|
||||
plain = NaN;
|
||||
plain = Infinity;
|
||||
plain = -Infinity;
|
||||
plain = Math.pow(2, 6);
|
||||
// other JSON primitive types are OK
|
||||
plain = false;
|
||||
plain = 'hello';
|
||||
plain = null;
|
||||
// structures made of above and of structures are OK
|
||||
plain = {};
|
||||
plain = [];
|
||||
plain = { a: 1 };
|
||||
plain = [0, null, false, NaN, 3.14, 'one more'];
|
||||
plain = { a: { b: 5, c: { d: [1, 'a', -Infinity, null], e: -1 }, f: 'b' }, g: false };
|
||||
|
||||
// typings:expect-error
|
||||
plain = undefined; // it's undefined
|
||||
// typings:expect-error
|
||||
plain = a => a; // it's a function
|
||||
// typings:expect-error
|
||||
plain = [new Date()]; // it's a time
|
||||
// typings:expect-error
|
||||
plain = { a: Symbol('haha') }; // symbol isn't permitted either
|
||||
// typings:expect-error
|
||||
plain = window || void 0;
|
||||
// typings:expect-error
|
||||
plain = { a: { b: 5, c: { d: [1, 'a', undefined, null] } } }; // going deep into the structure
|
||||
|
||||
return; // jsonTests
|
||||
})(null);
|
||||
|
||||
(function selectTests(selector: Selector): void {
|
||||
selector = select((a: Json) => a); // one arg
|
||||
selector = select((a: Json, b: Json): Json => `${a} and ${b}`); // more args
|
||||
selector = select(() => 1); // zero arg
|
||||
selector = select((...args: Json[]) => args); // variadic
|
||||
|
||||
// typings:expect-error
|
||||
selector = (a: Json) => a; // not a selector
|
||||
// typings:expect-error
|
||||
selector = select(() => {}); // should yield a JSON value, but it returns void
|
||||
// typings:expect-error
|
||||
selector = select((x: Json) => ({ a: x, b: undefined })); // should return a Json
|
||||
|
||||
return; // selectTests
|
||||
})(select((a: Json) => a));
|
||||
|
||||
return; // test suite
|
||||
})();
|
|
@ -4,6 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
// linear algebra
|
||||
type f64 = number; // eventual AssemblyScript compatibility; doesn't hurt with vanilla TS either
|
||||
type f = f64; // shorthand
|
||||
|
||||
|
@ -15,16 +16,36 @@ export type transformMatrix2d = [f, f, f, f, f, f, f, f, f] &
|
|||
export type transformMatrix3d = [f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f] &
|
||||
ReadonlyArray<f> & { __nominal: 'transformMatrix3d' };
|
||||
|
||||
// plain, JSON-bijective value
|
||||
export type Json = JsonPrimitive | JsonArray | JsonMap;
|
||||
type JsonPrimitive = null | boolean | number | string;
|
||||
interface JsonArray extends Array<Json> {}
|
||||
interface JsonMap extends IMap<Json> {}
|
||||
interface IMap<T> {
|
||||
[key: string]: T;
|
||||
}
|
||||
|
||||
// state object
|
||||
export type State = JsonMap & WithActionId;
|
||||
export type ActionId = number;
|
||||
interface WithActionId {
|
||||
primaryUpdate: { type: string; payload: { uid: ActionId; [propName: string]: Json } };
|
||||
[propName: string]: Json; // allow other arbitrary props
|
||||
}
|
||||
|
||||
// reselect-based data flow
|
||||
export type PlainFun = (...args: Json[]) => Json;
|
||||
export type Selector = (...fns: Resolve[]) => Resolve;
|
||||
type Resolve = ((obj: State) => Json);
|
||||
|
||||
//
|
||||
export interface Meta {
|
||||
silent: boolean;
|
||||
}
|
||||
export type ActionId = number;
|
||||
export type TypeName = string;
|
||||
export type NodeResult = any;
|
||||
export type Payload = any;
|
||||
export type NodeFunction = (...args: any[]) => any;
|
||||
export type UpdaterFunction = (arg: NodeResult) => NodeResult;
|
||||
export type Payload = JsonMap;
|
||||
export type UpdaterFunction = (arg: State) => State;
|
||||
export type ChangeCallbackFunction = (
|
||||
{ type, state }: { type: TypeName; state: NodeResult },
|
||||
{ type, state }: { type: TypeName; state: State },
|
||||
meta: Meta
|
||||
) => void;
|
|
@ -24,7 +24,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import { transformMatrix3d, vector3d } from './types';
|
||||
import { transformMatrix3d, vector3d } from '.';
|
||||
|
||||
const NANMATRIX = [
|
||||
NaN,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { transformMatrix2d, vector2d } from './types';
|
||||
import { transformMatrix2d, vector2d } from '.';
|
||||
|
||||
export const ORIGIN = [0, 0, 1] as vector2d;
|
||||
|
||||
|
|
|
@ -4,13 +4,11 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ActionId, NodeFunction, NodeResult } from './types';
|
||||
import { ActionId, Json, PlainFun, Selector, State } from '.';
|
||||
|
||||
export const select = (fun: NodeFunction): NodeFunction => (...fns) => {
|
||||
export const select = (fun: PlainFun): Selector => (...fns) => {
|
||||
let prevId: ActionId = NaN;
|
||||
let cache: NodeResult = null;
|
||||
const old = (object: NodeResult): boolean =>
|
||||
prevId === (prevId = object.primaryUpdate.payload.uid);
|
||||
return (obj: NodeResult) =>
|
||||
old(obj) ? cache : (cache = fun(...fns.map(f => f(obj) as NodeResult)));
|
||||
let cache: Json = null;
|
||||
const old = (object: State): boolean => prevId === (prevId = object.primaryUpdate.payload.uid);
|
||||
return (obj: State) => (old(obj) ? cache : (cache = fun(...fns.map(f => f(obj) as State))));
|
||||
};
|
||||
|
|
|
@ -8,16 +8,16 @@ import {
|
|||
ActionId,
|
||||
ChangeCallbackFunction,
|
||||
Meta,
|
||||
NodeResult,
|
||||
Payload,
|
||||
State,
|
||||
TypeName,
|
||||
UpdaterFunction,
|
||||
} from './types';
|
||||
} from '.';
|
||||
|
||||
let counter = 0 as ActionId;
|
||||
|
||||
export const createStore = (
|
||||
initialState: NodeResult,
|
||||
initialState: State,
|
||||
updater: UpdaterFunction,
|
||||
onChangeCallback: ChangeCallbackFunction
|
||||
) => {
|
||||
|
|
21
x-pack/plugins/canvas/public/lib/aeroelastic/tsconfig.json
Normal file
21
x-pack/plugins/canvas/public/lib/aeroelastic/tsconfig.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"extends": "../../../../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"lib": ["esnext", "dom"],
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": false,
|
||||
"strictPropertyInitialization": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitReturns": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"layout/*": ["aeroelastic/*"]
|
||||
},
|
||||
"types": ["@kbn/x-pack/plugins/canvas/public/lib/aeroelastic"]
|
||||
},
|
||||
"exclude": ["node_modules", "**/*.spec.ts", "node_modules/@types/mocha"]
|
||||
}
|
|
@ -4,11 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { transformMatrix3d } from './aeroelastic/types';
|
||||
import { transformMatrix3d } from './aeroelastic';
|
||||
|
||||
// converts a transform matrix to a CSS string
|
||||
export const matrixToCSS = (transformMatrix: transformMatrix3d): string =>
|
||||
transformMatrix ? 'matrix3d(' + transformMatrix.join(',') + ')' : 'translate3d(0,0,0)';
|
||||
|
||||
// converts to string, and adds `px` if non-zero
|
||||
export const px = (value: number): string => (value === 0 ? '0' : value + 'px');
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
"test_utils/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"test/**/*"
|
||||
"test/**/*",
|
||||
"**/typespec_tests.ts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"outDir": ".",
|
||||
|
|
14
yarn.lock
14
yarn.lock
|
@ -6675,7 +6675,7 @@ commander@0.6.1:
|
|||
resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06"
|
||||
integrity sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=
|
||||
|
||||
commander@2, commander@2.19.0, commander@^2.11.0, commander@^2.12.1, commander@^2.19.0, commander@^2.9.0:
|
||||
commander@2, commander@2.19.0, commander@^2.11.0, commander@^2.12.1, commander@^2.12.2, commander@^2.19.0, commander@^2.9.0:
|
||||
version "2.19.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
|
||||
integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
|
||||
|
@ -23530,12 +23530,14 @@ typescript@^3.3.3333:
|
|||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.3333.tgz#171b2c5af66c59e9431199117a3bcadc66fdcfd6"
|
||||
integrity sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==
|
||||
|
||||
ua-parser-js@^0.7.18:
|
||||
version "0.7.18"
|
||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed"
|
||||
integrity sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA==
|
||||
typings-tester@^0.3.2:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/typings-tester/-/typings-tester-0.3.2.tgz#04cc499d15ab1d8b2d14dd48415a13d01333bc5b"
|
||||
integrity sha512-HjGoAM2UoGhmSKKy23TYEKkxlphdJFdix5VvqWFLzH1BJVnnwG38tpC6SXPgqhfFGfHY77RlN1K8ts0dbWBQ7A==
|
||||
dependencies:
|
||||
commander "^2.12.2"
|
||||
|
||||
ua-parser-js@^0.7.9:
|
||||
ua-parser-js@^0.7.18, ua-parser-js@^0.7.9:
|
||||
version "0.7.19"
|
||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.19.tgz#94151be4c0a7fb1d001af7022fdaca4642659e4b"
|
||||
integrity sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ==
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue