Skip to content

Commit

Permalink
support unknown keys for object type in @kbn/schema-config (#39448)
Browse files Browse the repository at this point in the history
* support unknown keys for object type in @kbn/schema-config

* add test for children objects

* update snapshot test

* allowUnknowns as TypeOptions
  • Loading branch information
mshustov authored Jun 24, 2019
1 parent 4d88aaa commit 99c36d8
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 10 deletions.
6 changes: 2 additions & 4 deletions packages/kbn-config-schema/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
NumberOptions,
NumberType,
ObjectType,
ObjectTypeOptions,
Props,
RecordOfOptions,
RecordOfType,
Expand Down Expand Up @@ -94,10 +95,7 @@ function maybe<V>(type: Type<V>): Type<V | undefined> {
return new MaybeType(type);
}

function object<P extends Props>(
props: P,
options?: TypeOptions<{ [K in keyof P]: TypeOf<P[K]> }>
): ObjectType<P> {
function object<P extends Props>(props: P, options?: ObjectTypeOptions<P>): ObjectType<P> {
return new ObjectType(props, options);
}

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/kbn-config-schema/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export { LiteralType } from './literal_type';
export { MaybeType } from './maybe_type';
export { MapOfOptions, MapOfType } from './map_type';
export { NumberOptions, NumberType } from './number_type';
export { ObjectType, Props, TypeOf } from './object_type';
export { ObjectType, ObjectTypeOptions, Props, TypeOf } from './object_type';
export { RecordOfOptions, RecordOfType } from './record_type';
export { StringOptions, StringType } from './string_type';
export { UnionType } from './union_type';
Expand Down
44 changes: 44 additions & 0 deletions packages/kbn-config-schema/src/types/object_type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,47 @@ test('individual keys can validated', () => {
`"bar is not a valid part of this schema"`
);
});

test('allow unknown keys when allowUnknowns = true', () => {
const type = schema.object(
{ foo: schema.string({ defaultValue: 'test' }) },
{ allowUnknowns: true }
);

expect(
type.validate({
bar: 'baz',
})
).toEqual({
foo: 'test',
bar: 'baz',
});
});

test('allowUnknowns = true affects only own keys', () => {
const type = schema.object(
{ foo: schema.object({ bar: schema.string() }) },
{ allowUnknowns: true }
);

expect(() =>
type.validate({
foo: {
bar: 'bar',
baz: 'baz',
},
})
).toThrowErrorMatchingSnapshot();
});

test('does not allow unknown keys when allowUnknowns = false', () => {
const type = schema.object(
{ foo: schema.string({ defaultValue: 'test' }) },
{ allowUnknowns: false }
);
expect(() =>
type.validate({
bar: 'baz',
})
).toThrowErrorMatchingSnapshot();
});
16 changes: 11 additions & 5 deletions packages/kbn-config-schema/src/types/object_type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,31 @@ export type TypeOf<RT extends Type<any>> = RT['type'];

// Because of https://github.com/Microsoft/TypeScript/issues/14041
// this might not have perfect _rendering_ output, but it will be typed.

export type ObjectResultType<P extends Props> = Readonly<{ [K in keyof P]: TypeOf<P[K]> }>;

export type ObjectTypeOptions<P extends Props = any> = TypeOptions<
{ [K in keyof P]: TypeOf<P[K]> }
> & {
allowUnknowns?: boolean;
};

export class ObjectType<P extends Props = any> extends Type<ObjectResultType<P>> {
private props: Record<string, AnySchema>;

constructor(props: P, options: TypeOptions<{ [K in keyof P]: TypeOf<P[K]> }> = {}) {
constructor(props: P, options: ObjectTypeOptions<P> = {}) {
const schemaKeys = {} as Record<string, AnySchema>;
for (const [key, value] of Object.entries(props)) {
schemaKeys[key] = value.getSchema();
}

const { allowUnknowns, ...typeOptions } = options;
const schema = internals
.object()
.keys(schemaKeys)
.optional()
.default();
.default()
.unknown(Boolean(allowUnknowns));

super(schema, options);
super(schema, typeOptions);
this.props = schemaKeys;
}

Expand Down

0 comments on commit 99c36d8

Please sign in to comment.