Skip to content

Commit

Permalink
feat: add nullable support for OpenAPI3
Browse files Browse the repository at this point in the history
  • Loading branch information
raveclassic committed Jan 23, 2020
1 parent 7ba0400 commit 937c21f
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ describe('SchemaObject', () => {
type: constant<'string'>('string'),
format: constant(none),
deprecated: constant(none),
nullable: constant(none),
}),
format: constant(none),
deprecated: constant(none),
nullable: constant(none),
});
assert(
property($refArbitrary, schema, string(), (from, schema, name) => {
Expand Down
27 changes: 18 additions & 9 deletions src/language/typescript/3.0/serializers/schema-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
getSerializedDictionaryType,
getSerializedEnumType,
getSerializedIntersectionType,
getSerializedNullableType,
getSerializedObjectType,
getSerializedOptionPropertyType,
getSerializedRecursiveType,
Expand All @@ -21,7 +22,7 @@ import { Either, mapLeft, right } from 'fp-ts/lib/Either';
import { pipe } from 'fp-ts/lib/pipeable';
import { either, option } from 'fp-ts';
import { serializeDictionary } from '../../../../utils/types';
import { constFalse } from 'fp-ts/lib/function';
import { constFalse, identity } from 'fp-ts/lib/function';
import { includes } from '../../../../utils/array';
import { sequenceEither } from '@devexperts/utils/dist/adt/either.utils';
import { fromString, Ref } from '../../../../utils/ref';
Expand Down Expand Up @@ -51,11 +52,13 @@ export const serializeSchemaObject = (
const serializeSchemaObjectWithRecursion = (from: Ref, shouldTrackRecursion: boolean, name?: string) => (
schemaObject: SchemaObject,
): Either<Error, SerializedType> => {
const isNullable = pipe(schemaObject.nullable, option.exists(identity));
if (OneOfSchemaObjectCodec.is(schemaObject)) {
return pipe(
serializeChildren(from, schemaObject.oneOf),
either.map(getSerializedUnionType),
either.map(getSerializedRecursiveType(from, shouldTrackRecursion)),
either.map(getSerializedNullableType(isNullable)),
);
}

Expand All @@ -64,19 +67,20 @@ const serializeSchemaObjectWithRecursion = (from: Ref, shouldTrackRecursion: boo
serializeChildren(from, schemaObject.allOf),
either.map(getSerializedIntersectionType),
either.map(getSerializedRecursiveType(from, shouldTrackRecursion)),
either.map(getSerializedNullableType(isNullable)),
);
}

if (EnumSchemaObjectCodec.is(schemaObject)) {
return right(getSerializedEnumType(schemaObject.enum));
return pipe(getSerializedEnumType(schemaObject.enum), getSerializedNullableType(isNullable), right);
}

switch (schemaObject.type) {
case 'string':
case 'boolean':
case 'integer':
case 'number': {
return serializePrimitive(from, schemaObject);
return pipe(serializePrimitive(from, schemaObject), getSerializedNullableType(isNullable), right);
}
case 'array': {
const { items } = schemaObject;
Expand All @@ -87,7 +91,11 @@ const serializeSchemaObjectWithRecursion = (from: Ref, shouldTrackRecursion: boo
either.map(getSerializedRefType(from)),
)
: pipe(items, serializeSchemaObjectWithRecursion(from, false, undefined));
return pipe(serialized, either.map(getSerializedArrayType(name)));
return pipe(
serialized,
either.map(getSerializedArrayType(name)),
either.map(getSerializedNullableType(isNullable)),
);
}
case 'object': {
const additionalProperties = pipe(
Expand Down Expand Up @@ -157,6 +165,7 @@ const serializeSchemaObjectWithRecursion = (from: Ref, shouldTrackRecursion: boo
return pipe(
additionalProperties,
option.alt(() => properties),
option.map(either.map(getSerializedNullableType(isNullable))),
option.getOrElse(() => right(SERIALIZED_UNKNOWN_TYPE)),
);
}
Expand All @@ -173,19 +182,19 @@ const serializeChildren = (
: serializeSchemaObjectWithRecursion(from, false)(item),
);

const serializePrimitive = (from: Ref, schemaObject: PrimitiveSchemaObject): Either<Error, SerializedType> => {
const serializePrimitive = (from: Ref, schemaObject: PrimitiveSchemaObject): SerializedType => {
switch (schemaObject.type) {
case 'string': {
return right(getSerializedStringType(schemaObject.format));
return getSerializedStringType(schemaObject.format);
}
case 'number': {
return right(SERIALIZED_NUMBER_TYPE);
return SERIALIZED_NUMBER_TYPE;
}
case 'integer': {
return right(SERIALIZED_INTEGER_TYPE);
return SERIALIZED_INTEGER_TYPE;
}
case 'boolean': {
return right(SERIALIZED_BOOLEAN_TYPE);
return SERIALIZED_BOOLEAN_TYPE;
}
}
};
9 changes: 3 additions & 6 deletions src/language/typescript/common/data/serialized-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,9 @@ export const getSerializedStringType = (format: Option<string>): SerializedType
option.getOrElse(() => SERIALIZED_STRING_TYPE),
);
};
export const SERIALIZED_NULL_TYPE = serializedType(
'null',
'literal(null)',
[serializedDependency('literal', 'io-ts')],
[],
);
export const SERIALIZED_NULL_TYPE = serializedType('null', 'nullType', [serializedDependency('nullType', 'io-ts')], []);
export const getSerializedNullableType = (isNullable: boolean) => (type: SerializedType): SerializedType =>
isNullable ? getSerializedUnionType([type, SERIALIZED_NULL_TYPE]) : type;

export const getSerializedArrayType = (name?: string) => (serialized: SerializedType): SerializedType =>
serializedType(
Expand Down
2 changes: 2 additions & 0 deletions src/schema/3.0/schema-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import { nonEmptyArray } from 'io-ts-types/lib/nonEmptyArray';
export interface BaseSchemaObject {
readonly format: Option<string>;
readonly deprecated: Option<boolean>;
readonly nullable: Option<boolean>;
}

const BaseSchemaObjectCodec: Codec<BaseSchemaObject> = type({
format: optionFromNullable(string),
deprecated: optionFromNullable(boolean),
nullable: optionFromNullable(boolean),
});

export interface EnumSchemaObject extends BaseSchemaObject {
Expand Down
8 changes: 8 additions & 0 deletions test/specs/3.0/demo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ components:
$ref: '#/components/schemas/TestAllOf'
kebab-property:
type: string
TestNullable:
type: array
nullable: true
items:
type: array
items:
type: string
nullable: true
requestBodies:
RefRequestBody:
description: ref request body
Expand Down

0 comments on commit 937c21f

Please sign in to comment.