diff --git a/README.md b/README.md index 548e28cf..7cb62330 100644 --- a/README.md +++ b/README.md @@ -328,6 +328,39 @@ enum EnumWithStrings { } ``` +### Nullable in OpenApi v2 +You can use the unofficial `x-nullable` backport in your specification to generate nullable properties in OpenApi v2. + +```json +{ + "ModelWithNullableString": { + "required": ["requiredProp"], + "description": "This is a model with one string property", + "type": "object", + "properties": { + "prop": { + "description": "This is a simple string property", + "type": "string", + "x-nullable": true + }, + "requiredProp": { + "description": "This is a simple string property", + "type": "string", + "x-nullable": true, + } + } + } +} +``` + +Generated code: +```typescript +enum ModelWithNullableString { + prop?: string | null, + requiredProp: string | null +} +``` + ### Authorization The OpenAPI generator supports Bearer Token authorization. In order to enable the sending diff --git a/src/index.spec.ts b/src/index.spec.ts index 29251d33..d1170357 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -3,8 +3,8 @@ import * as OpenAPI from './index'; describe('index', () => { it('parses v2 without issues', async () => { await OpenAPI.generate({ - input: './test/spec/v3.json', - output: './generated/v3/', + input: './test/spec/v2.json', + output: './generated/v2/', write: false, }); }); diff --git a/src/openApi/v2/interfaces/Extensions/WithNullableExtension.d.ts b/src/openApi/v2/interfaces/Extensions/WithNullableExtension.d.ts new file mode 100644 index 00000000..2f7c05f7 --- /dev/null +++ b/src/openApi/v2/interfaces/Extensions/WithNullableExtension.d.ts @@ -0,0 +1,6 @@ +/** + * Supported extension for enums + */ +export interface WithNullableExtension { + 'x-nullable'?: boolean; +} diff --git a/src/openApi/v2/interfaces/OpenApiSchema.d.ts b/src/openApi/v2/interfaces/OpenApiSchema.d.ts index abba5fce..4ac0f559 100644 --- a/src/openApi/v2/interfaces/OpenApiSchema.d.ts +++ b/src/openApi/v2/interfaces/OpenApiSchema.d.ts @@ -1,5 +1,6 @@ import type { Dictionary } from '../../../utils/types'; import type { WithEnumExtension } from './Extensions/WithEnumExtension'; +import type { WithNullableExtension } from './Extensions/WithNullableExtension'; import type { OpenApiExternalDocs } from './OpenApiExternalDocs'; import type { OpenApiReference } from './OpenApiReference'; import type { OpenApiXml } from './OpenApiXml'; @@ -7,7 +8,7 @@ import type { OpenApiXml } from './OpenApiXml'; /** * https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#schemaObject */ -export interface OpenApiSchema extends OpenApiReference, WithEnumExtension { +export interface OpenApiSchema extends OpenApiReference, WithEnumExtension, WithNullableExtension { title?: string; description?: string; default?: any; diff --git a/src/openApi/v2/parser/getModelProperties.ts b/src/openApi/v2/parser/getModelProperties.ts index 7623814e..cb824aba 100644 --- a/src/openApi/v2/parser/getModelProperties.ts +++ b/src/openApi/v2/parser/getModelProperties.ts @@ -26,7 +26,7 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema, isDefinition: false, isReadOnly: property.readOnly === true, isRequired: propertyRequired === true, - isNullable: false, + isNullable: property['x-nullable'] === true, format: property.format, maximum: property.maximum, exclusiveMaximum: property.exclusiveMaximum, @@ -60,7 +60,7 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema, isDefinition: false, isReadOnly: property.readOnly === true, isRequired: propertyRequired === true, - isNullable: false, + isNullable: property['x-nullable'] === true, format: property.format, maximum: property.maximum, exclusiveMaximum: property.exclusiveMaximum, @@ -84,6 +84,5 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema, } } } - return models; } diff --git a/test/__snapshots__/index.spec.js.snap b/test/__snapshots__/index.spec.js.snap index 840010cd..f72bb679 100644 --- a/test/__snapshots__/index.spec.js.snap +++ b/test/__snapshots__/index.spec.js.snap @@ -293,6 +293,7 @@ export type { ModelWithInteger } from './models/ModelWithInteger'; export type { ModelWithLink } from './models/ModelWithLink'; export type { ModelWithNestedEnums } from './models/ModelWithNestedEnums'; export type { ModelWithNestedProperties } from './models/ModelWithNestedProperties'; +export type { ModelWithNullableString } from './models/ModelWithNullableString'; export type { ModelWithOrderedProperties } from './models/ModelWithOrderedProperties'; export type { ModelWithPattern } from './models/ModelWithPattern'; export type { ModelWithProperties } from './models/ModelWithProperties'; @@ -335,6 +336,7 @@ export { $ModelWithInteger } from './schemas/$ModelWithInteger'; export { $ModelWithLink } from './schemas/$ModelWithLink'; export { $ModelWithNestedEnums } from './schemas/$ModelWithNestedEnums'; export { $ModelWithNestedProperties } from './schemas/$ModelWithNestedProperties'; +export { $ModelWithNullableString } from './schemas/$ModelWithNullableString'; export { $ModelWithOrderedProperties } from './schemas/$ModelWithOrderedProperties'; export { $ModelWithPattern } from './schemas/$ModelWithPattern'; export { $ModelWithProperties } from './schemas/$ModelWithProperties'; @@ -825,6 +827,26 @@ export interface ModelWithNestedProperties { " `; +exports[`v2 should generate: ./test/generated/v2/models/ModelWithNullableString.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +/** + * This is a model with one string property + */ +export interface ModelWithNullableString { + /** + * This is a simple string property + */ + nullableProp?: string | null; + /** + * This is a simple string property + */ + nullableRequiredProp: string | null; +} +" +`; + exports[`v2 should generate: ./test/generated/v2/models/ModelWithOrderedProperties.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -1354,6 +1376,25 @@ export const $ModelWithNestedProperties = { };" `; +exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithNullableString.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $ModelWithNullableString = { + properties: { + nullableProp: { + type: 'string', + isNullable: true, + }, + nullableRequiredProp: { + type: 'string', + isRequired: true, + isNullable: true, + }, + }, +};" +`; + exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithOrderedProperties.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ diff --git a/test/spec/v2.json b/test/spec/v2.json index e4b9b579..f0561825 100644 --- a/test/spec/v2.json +++ b/test/spec/v2.json @@ -858,6 +858,23 @@ } } }, + "ModelWithNullableString": { + "description": "This is a model with one string property", + "type": "object", + "required": ["nullableRequiredProp"], + "properties": { + "nullableProp": { + "description": "This is a simple string property", + "type": "string", + "x-nullable": true + }, + "nullableRequiredProp": { + "description": "This is a simple string property", + "type": "string", + "x-nullable": true + } + } + }, "ModelWithEnum": { "description": "This is a model with one enum", "type": "object",