Skip to content

Commit

Permalink
[APM] Extract server type utils to package (#96349)
Browse files Browse the repository at this point in the history
  • Loading branch information
dgieselaar authored Apr 8, 2021
1 parent d9ef5c2 commit bfc940c
Show file tree
Hide file tree
Showing 76 changed files with 2,822 additions and 1,685 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,12 @@
"@kbn/crypto": "link:packages/kbn-crypto",
"@kbn/i18n": "link:packages/kbn-i18n",
"@kbn/interpreter": "link:packages/kbn-interpreter",
"@kbn/io-ts-utils": "link:packages/kbn-io-ts-utils",
"@kbn/legacy-logging": "link:packages/kbn-legacy-logging",
"@kbn/logging": "link:packages/kbn-logging",
"@kbn/monaco": "link:packages/kbn-monaco",
"@kbn/server-http-tools": "link:packages/kbn-server-http-tools",
"@kbn/server-route-repository": "link:packages/kbn-server-route-repository",
"@kbn/std": "link:packages/kbn-std",
"@kbn/tinymath": "link:packages/kbn-tinymath",
"@kbn/ui-framework": "link:packages/kbn-ui-framework",
Expand Down
13 changes: 13 additions & 0 deletions packages/kbn-io-ts-utils/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

module.exports = {
preset: '@kbn/test',
rootDir: '../..',
roots: ['<rootDir>/packages/kbn-io-ts-utils'],
};
13 changes: 13 additions & 0 deletions packages/kbn-io-ts-utils/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "@kbn/io-ts-utils",
"main": "./target/index.js",
"types": "./target/index.d.ts",
"version": "1.0.0",
"license": "SSPL-1.0 OR Elastic License 2.0",
"private": true,
"scripts": {
"build": "../../node_modules/.bin/tsc",
"kbn:bootstrap": "yarn build",
"kbn:watch": "yarn build --watch"
}
}
11 changes: 11 additions & 0 deletions packages/kbn-io-ts-utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export { jsonRt } from './json_rt';
export { mergeRt } from './merge_rt';
export { strictKeysRt } from './strict_keys_rt';
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import * as t from 'io-ts';
Expand All @@ -12,9 +13,7 @@ import { Right } from 'fp-ts/lib/Either';
import { pipe } from 'fp-ts/lib/pipeable';
import { identity } from 'fp-ts/lib/function';

function getValueOrThrow<TEither extends Either<any, any>>(
either: TEither
): Right<TEither> {
function getValueOrThrow<TEither extends Either<any, any>>(either: TEither): Right<TEither> {
const value = pipe(
either,
fold(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import * as t from 'io-ts';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import * as t from 'io-ts';
import { isLeft } from 'fp-ts/lib/Either';
import { merge } from './';
import { mergeRt } from '.';
import { jsonRt } from '../json_rt';

describe('merge', () => {
it('fails on one or more errors', () => {
const type = merge([t.type({ foo: t.string }), t.type({ bar: t.number })]);
const type = mergeRt(t.type({ foo: t.string }), t.type({ bar: t.number }));

const result = type.decode({ foo: '' });

expect(isLeft(result)).toBe(true);
});

it('merges left to right', () => {
const typeBoolean = merge([
t.type({ foo: t.string }),
t.type({ foo: jsonRt.pipe(t.boolean) }),
]);
const typeBoolean = mergeRt(t.type({ foo: t.string }), t.type({ foo: jsonRt.pipe(t.boolean) }));

const resultBoolean = typeBoolean.decode({
foo: 'true',
Expand All @@ -34,10 +32,7 @@ describe('merge', () => {
foo: true,
});

const typeString = merge([
t.type({ foo: jsonRt.pipe(t.boolean) }),
t.type({ foo: t.string }),
]);
const typeString = mergeRt(t.type({ foo: jsonRt.pipe(t.boolean) }), t.type({ foo: t.string }));

const resultString = typeString.decode({
foo: 'true',
Expand All @@ -50,10 +45,10 @@ describe('merge', () => {
});

it('deeply merges values', () => {
const type = merge([
const type = mergeRt(
t.type({ foo: t.type({ baz: t.string }) }),
t.type({ foo: t.type({ bar: t.string }) }),
]);
t.type({ foo: t.type({ bar: t.string }) })
);

const result = type.decode({
foo: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,40 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import * as t from 'io-ts';
import { merge as lodashMerge } from 'lodash';
import { isLeft } from 'fp-ts/lib/Either';
import { ValuesType } from 'utility-types';

export type MergeType<
T extends t.Any[],
U extends ValuesType<T> = ValuesType<T>
> = t.Type<U['_A'], U['_O'], U['_I']> & {
_tag: 'MergeType';
types: T;
};
type PlainObject = Record<string | number | symbol, any>;

type DeepMerge<T, U> = U extends PlainObject
? T extends PlainObject
? Omit<T, keyof U> &
{
[key in keyof U]: T extends { [k in key]: any } ? DeepMerge<T[key], U[key]> : U[key];
}
: U
: U;

// this is similar to t.intersection, but does a deep merge
// instead of a shallow merge

export function merge<A extends t.Mixed, B extends t.Mixed>(
types: [A, B]
): MergeType<[A, B]>;
export type MergeType<T1 extends t.Any, T2 extends t.Any> = t.Type<
DeepMerge<t.TypeOf<T1>, t.TypeOf<T2>>,
DeepMerge<t.OutputOf<T1>, t.OutputOf<T2>>
> & {
_tag: 'MergeType';
types: [T1, T2];
};

export function mergeRt<T1 extends t.Any, T2 extends t.Any>(a: T1, b: T2): MergeType<T1, T2>;

export function merge(types: t.Any[]) {
export function mergeRt(...types: t.Any[]) {
const mergeType = new t.Type(
'merge',
(u): u is unknown => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import * as t from 'io-ts';
Expand All @@ -14,10 +15,7 @@ describe('strictKeysRt', () => {
it('correctly and deeply validates object keys', () => {
const checks: Array<{ type: t.Type<any>; passes: any[]; fails: any[] }> = [
{
type: t.intersection([
t.type({ foo: t.string }),
t.partial({ bar: t.string }),
]),
type: t.intersection([t.type({ foo: t.string }), t.partial({ bar: t.string })]),
passes: [{ foo: '' }, { foo: '', bar: '' }],
fails: [
{ foo: '', unknownKey: '' },
Expand All @@ -26,15 +24,9 @@ describe('strictKeysRt', () => {
},
{
type: t.type({
path: t.union([
t.type({ serviceName: t.string }),
t.type({ transactionType: t.string }),
]),
path: t.union([t.type({ serviceName: t.string }), t.type({ transactionType: t.string })]),
}),
passes: [
{ path: { serviceName: '' } },
{ path: { transactionType: '' } },
],
passes: [{ path: { serviceName: '' } }, { path: { transactionType: '' } }],
fails: [
{ path: { serviceName: '', unknownKey: '' } },
{ path: { transactionType: '', unknownKey: '' } },
Expand Down Expand Up @@ -62,9 +54,7 @@ describe('strictKeysRt', () => {

if (!isRight(result)) {
throw new Error(
`Expected ${JSON.stringify(
value
)} to be allowed, but validation failed with ${
`Expected ${JSON.stringify(value)} to be allowed, but validation failed with ${
result.left[0].message
}`
);
Expand All @@ -76,9 +66,7 @@ describe('strictKeysRt', () => {

if (!isLeft(result)) {
throw new Error(
`Expected ${JSON.stringify(
value
)} to be disallowed, but validation succeeded`
`Expected ${JSON.stringify(value)} to be disallowed, but validation succeeded`
);
}
});
Expand Down
Loading

0 comments on commit bfc940c

Please sign in to comment.