diff --git a/src/openApi/v3/parser/getModelProperties.ts b/src/openApi/v3/parser/getModelProperties.ts index 1f1d80ce..5d59b3e4 100644 --- a/src/openApi/v3/parser/getModelProperties.ts +++ b/src/openApi/v3/parser/getModelProperties.ts @@ -29,7 +29,7 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema, isDefinition: false, isReadOnly: property.readOnly === true, isRequired: propertyRequired, - isNullable: property.nullable === true, + isNullable: model.isNullable || property.nullable === true, format: property.format, maximum: property.maximum, exclusiveMaximum: property.exclusiveMaximum, @@ -62,7 +62,7 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema, isDefinition: false, isReadOnly: property.readOnly === true, isRequired: propertyRequired, - isNullable: property.nullable === true, + isNullable: model.isNullable || property.nullable === true, format: property.format, maximum: property.maximum, exclusiveMaximum: property.exclusiveMaximum, diff --git a/src/templates/partials/typeInterface.hbs b/src/templates/partials/typeInterface.hbs index 1ca35e27..1adbc5b2 100644 --- a/src/templates/partials/typeInterface.hbs +++ b/src/templates/partials/typeInterface.hbs @@ -7,9 +7,9 @@ */ {{/if}} {{#if ../parent}} -{{>isReadOnly}}{{{name}}}{{>isRequired}}: {{>type parent=../parent}}, +{{>isReadOnly}}{{{name}}}{{>isRequired}}: {{>type parent=../parent}}; {{else}} -{{>isReadOnly}}{{{name}}}{{>isRequired}}: {{>type}}, +{{>isReadOnly}}{{{name}}}{{>isRequired}}: {{>type}}; {{/if}} {{/each}} }{{>isNullable}} diff --git a/test/__snapshots__/index.spec.js.snap b/test/__snapshots__/index.spec.js.snap index 5f0da11c..f46f87e5 100644 --- a/test/__snapshots__/index.spec.js.snap +++ b/test/__snapshots__/index.spec.js.snap @@ -488,7 +488,7 @@ export type { DictionaryWithDictionary } from './models/DictionaryWithDictionary export type { DictionaryWithProperties } from './models/DictionaryWithProperties'; export type { DictionaryWithReference } from './models/DictionaryWithReference'; export type { DictionaryWithString } from './models/DictionaryWithString'; -export { EnumFromDescription } from './models/EnumFromDescription'; +export type { EnumFromDescription } from './models/EnumFromDescription'; export { EnumWithExtensions } from './models/EnumWithExtensions'; export { EnumWithNumbers } from './models/EnumWithNumbers'; export { EnumWithStrings } from './models/EnumWithStrings'; @@ -619,8 +619,8 @@ exports[`v2 should generate: ./test/generated/v2/models/ArrayWithProperties.ts 1 * This is a simple array with properties */ export type ArrayWithProperties = Array<{ - foo?: string, - bar?: string, + foo?: string; + bar?: string; }>;" `; @@ -692,8 +692,8 @@ exports[`v2 should generate: ./test/generated/v2/models/DictionaryWithProperties * This is a complex dictionary */ export type DictionaryWithProperties = Record;" `; @@ -729,11 +729,7 @@ exports[`v2 should generate: ./test/generated/v2/models/EnumFromDescription.ts 1 /** * Success=1,Warning=2,Error=3 */ -export enum EnumFromDescription { - SUCCESS = 1, - WARNING = 2, - ERROR = 3, -}" +export type EnumFromDescription = number;" `; exports[`v2 should generate: ./test/generated/v2/models/EnumWithExtensions.ts 1`] = ` @@ -813,8 +809,8 @@ import type { ModelWithString } from './ModelWithString'; * This is a model that extends another model */ export type ModelThatExtends = (ModelWithString & { - propExtendsA?: string, - propExtendsB?: ModelWithString, + propExtendsA?: string; + propExtendsB?: ModelWithString; }); " `; @@ -831,8 +827,8 @@ import type { ModelWithString } from './ModelWithString'; * This is a model that extends another model */ export type ModelThatExtendsExtends = (ModelWithString & ModelThatExtends & { - propExtendsC?: string, - propExtendsD?: ModelWithString, + propExtendsC?: string; + propExtendsD?: ModelWithString; }); " `; @@ -1061,8 +1057,8 @@ exports[`v2 should generate: ./test/generated/v2/models/ModelWithNestedPropertie export type ModelWithNestedProperties = { readonly first: { readonly second: { - readonly third: string, - }, + readonly third: string; + }; }; } " @@ -1434,7 +1430,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$EnumFromDescription.ts /* tslint:disable */ /* eslint-disable */ export const $EnumFromDescription = { - type: 'Enum', + type: 'number', };" `; @@ -1994,9 +1990,9 @@ export class ComplexService { parameterObject: { first?: { second?: { - third?: string, - }, - }, + third?: string; + }; + }; }, parameterReference: ModelWithString, ): CancelablePromise> { @@ -2358,9 +2354,9 @@ export class ResponseService { * @throws ApiError */ public static callWithResponses(): CancelablePromise<{ - readonly '@namespace.string'?: string, - readonly '@namespace.integer'?: number, - readonly value?: Array, + readonly '@namespace.string'?: string; + readonly '@namespace.integer'?: number; + readonly value?: Array; } | ModelWithString | ModelThatExtends | ModelThatExtendsExtends> { return __request({ method: 'PUT', @@ -2994,6 +2990,8 @@ export type { ArrayWithNumbers } from './models/ArrayWithNumbers'; export type { ArrayWithProperties } from './models/ArrayWithProperties'; export type { ArrayWithReferences } from './models/ArrayWithReferences'; export type { ArrayWithStrings } from './models/ArrayWithStrings'; +export type { CompositionBaseModel } from './models/CompositionBaseModel'; +export type { CompositionExtendedModel } from './models/CompositionExtendedModel'; export type { CompositionWithAllOfAndNullable } from './models/CompositionWithAllOfAndNullable'; export type { CompositionWithAnyOf } from './models/CompositionWithAnyOf'; export type { CompositionWithAnyOfAndNullable } from './models/CompositionWithAnyOfAndNullable'; @@ -3006,7 +3004,7 @@ export type { DictionaryWithDictionary } from './models/DictionaryWithDictionary export type { DictionaryWithProperties } from './models/DictionaryWithProperties'; export type { DictionaryWithReference } from './models/DictionaryWithReference'; export type { DictionaryWithString } from './models/DictionaryWithString'; -export { EnumFromDescription } from './models/EnumFromDescription'; +export type { EnumFromDescription } from './models/EnumFromDescription'; export { EnumWithExtensions } from './models/EnumWithExtensions'; export { EnumWithNumbers } from './models/EnumWithNumbers'; export { EnumWithStrings } from './models/EnumWithStrings'; @@ -3023,6 +3021,7 @@ export { ModelWithEnumFromDescription } from './models/ModelWithEnumFromDescript export type { ModelWithInteger } from './models/ModelWithInteger'; 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'; @@ -3042,6 +3041,8 @@ export { $ArrayWithNumbers } from './schemas/$ArrayWithNumbers'; export { $ArrayWithProperties } from './schemas/$ArrayWithProperties'; export { $ArrayWithReferences } from './schemas/$ArrayWithReferences'; export { $ArrayWithStrings } from './schemas/$ArrayWithStrings'; +export { $CompositionBaseModel } from './schemas/$CompositionBaseModel'; +export { $CompositionExtendedModel } from './schemas/$CompositionExtendedModel'; export { $CompositionWithAllOfAndNullable } from './schemas/$CompositionWithAllOfAndNullable'; export { $CompositionWithAnyOf } from './schemas/$CompositionWithAnyOf'; export { $CompositionWithAnyOfAndNullable } from './schemas/$CompositionWithAnyOfAndNullable'; @@ -3071,6 +3072,7 @@ export { $ModelWithEnumFromDescription } from './schemas/$ModelWithEnumFromDescr export { $ModelWithInteger } from './schemas/$ModelWithInteger'; 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'; @@ -3144,8 +3146,8 @@ exports[`v3 should generate: ./test/generated/v3/models/ArrayWithProperties.ts 1 * This is a simple array with properties */ export type ArrayWithProperties = Array<{ - foo?: string, - bar?: string, + foo?: string; + bar?: string; }>;" `; @@ -3173,6 +3175,37 @@ exports[`v3 should generate: ./test/generated/v3/models/ArrayWithStrings.ts 1`] export type ArrayWithStrings = Array;" `; +exports[`v3 should generate: ./test/generated/v3/models/CompositionBaseModel.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +/** + * This is a base model with two simple optional properties + */ +export type CompositionBaseModel = { + firstName?: string; + lastname?: string; +} +" +`; + +exports[`v3 should generate: ./test/generated/v3/models/CompositionExtendedModel.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { CompositionBaseModel } from './CompositionBaseModel'; + +/** + * This is a model that extends the base model + */ +export type CompositionExtendedModel = (CompositionBaseModel & { + age: number; +}); +" +`; + exports[`v3 should generate: ./test/generated/v3/models/CompositionWithAllOfAndNullable.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -3187,7 +3220,7 @@ import type { ModelWithEnum } from './ModelWithEnum'; */ export type CompositionWithAllOfAndNullable = { propA?: ({ - boolean?: boolean, + boolean?: boolean; } & ModelWithEnum & ModelWithArray & ModelWithDictionary) | null; } " @@ -3226,7 +3259,7 @@ import type { ModelWithEnum } from './ModelWithEnum'; */ export type CompositionWithAnyOfAndNullable = { propA?: ({ - boolean?: boolean, + boolean?: boolean; } | ModelWithEnum | ModelWithArray | ModelWithDictionary) | null; } " @@ -3242,7 +3275,7 @@ exports[`v3 should generate: ./test/generated/v3/models/CompositionWithAnyOfAnon */ export type CompositionWithAnyOfAnonymous = { propA?: ({ - propA?: any, + propA?: string; } | string | number); } " @@ -3281,7 +3314,7 @@ import type { ModelWithEnum } from './ModelWithEnum'; */ export type CompositionWithOneOfAndNullable = { propA?: ({ - boolean?: boolean, + boolean?: boolean; } | ModelWithEnum | ModelWithArray | ModelWithDictionary) | null; } " @@ -3297,7 +3330,7 @@ exports[`v3 should generate: ./test/generated/v3/models/CompositionWithOneOfAnon */ export type CompositionWithOneOfAnonymous = { propA?: ({ - propA?: any, + propA?: string; } | string | number); } " @@ -3336,8 +3369,8 @@ exports[`v3 should generate: ./test/generated/v3/models/DictionaryWithProperties * This is a complex dictionary */ export type DictionaryWithProperties = Record;" `; @@ -3373,11 +3406,7 @@ exports[`v3 should generate: ./test/generated/v3/models/EnumFromDescription.ts 1 /** * Success=1,Warning=2,Error=3 */ -export enum EnumFromDescription { - SUCCESS = 1, - WARNING = 2, - ERROR = 3, -}" +export type EnumFromDescription = number;" `; exports[`v3 should generate: ./test/generated/v3/models/EnumWithExtensions.ts 1`] = ` @@ -3457,8 +3486,8 @@ import type { ModelWithString } from './ModelWithString'; * This is a model that extends another model */ export type ModelThatExtends = (ModelWithString & { - propExtendsA?: string, - propExtendsB?: ModelWithString, + propExtendsA?: string; + propExtendsB?: ModelWithString; }); " `; @@ -3475,8 +3504,8 @@ import type { ModelWithString } from './ModelWithString'; * This is a model that extends another model */ export type ModelThatExtendsExtends = (ModelWithString & ModelThatExtends & { - propExtendsC?: string, - propExtendsD?: ModelWithString, + propExtendsC?: string; + propExtendsD?: ModelWithString; }); " `; @@ -3705,13 +3734,42 @@ exports[`v3 should generate: ./test/generated/v3/models/ModelWithNestedPropertie export type ModelWithNestedProperties = { readonly first: { readonly second: { - readonly third: string | null, - } | null, + readonly third: string | null; + } | null; } | null; } " `; +exports[`v3 should generate: ./test/generated/v3/models/ModelWithNullableString.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +/** + * This is a model with one string property + */ +export type ModelWithNullableString = { + /** + * This is a simple string property + */ + nullableProp1?: string | null; + /** + * This is a simple string property + */ + nullableRequiredProp1: string | null; + /** + * This is a simple string property + */ + nullableProp2?: string | null; + /** + * This is a simple string property + */ + nullableRequiredProp2: string | null; +} +" +`; + exports[`v3 should generate: ./test/generated/v3/models/ModelWithOrderedProperties.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -3971,6 +4029,41 @@ export const $ArrayWithStrings = { };" `; +exports[`v3 should generate: ./test/generated/v3/schemas/$CompositionBaseModel.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $CompositionBaseModel = { + properties: { + firstName: { + type: 'string', + }, + lastname: { + type: 'string', + }, + }, +};" +`; + +exports[`v3 should generate: ./test/generated/v3/schemas/$CompositionExtendedModel.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $CompositionExtendedModel = { + type: 'all-of', + contains: [{ + type: 'CompositionBaseModel', + }, { + properties: { + age: { + type: 'number', + isRequired: true, + }, + }, + }], +};" +`; + exports[`v3 should generate: ./test/generated/v3/schemas/$CompositionWithAllOfAndNullable.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -4058,8 +4151,7 @@ export const $CompositionWithAnyOfAnonymous = { contains: [{ properties: { propA: { - properties: { - }, + type: 'string', }, }, }, { @@ -4132,8 +4224,7 @@ export const $CompositionWithOneOfAnonymous = { contains: [{ properties: { propA: { - properties: { - }, + type: 'string', }, }, }, { @@ -4224,7 +4315,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$EnumFromDescription.ts /* tslint:disable */ /* eslint-disable */ export const $EnumFromDescription = { - type: 'Enum', + type: 'number', };" `; @@ -4510,6 +4601,34 @@ export const $ModelWithNestedProperties = { };" `; +exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithNullableString.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $ModelWithNullableString = { + properties: { + nullableProp1: { + type: 'string', + isNullable: true, + }, + nullableRequiredProp1: { + type: 'string', + isRequired: true, + isNullable: true, + }, + nullableProp2: { + type: 'string', + isNullable: true, + }, + nullableRequiredProp2: { + type: 'string', + isRequired: true, + isNullable: true, + }, + }, +};" +`; + exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithOrderedProperties.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -4776,9 +4895,9 @@ export class ComplexService { parameterObject: { first?: { second?: { - third?: string, - }, - }, + third?: string; + }; + }; }, parameterReference: ModelWithString, ): CancelablePromise> { @@ -4805,17 +4924,17 @@ export class ComplexService { public static complexParams( id: number, requestBody?: { - readonly key: string | null, - name: string | null, - enabled?: boolean, - readonly type: 'Monkey' | 'Horse' | 'Bird', - listOfModels?: Array | null, - listOfStrings?: Array | null, - parameters: (ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary), + readonly key: string | null; + name: string | null; + enabled?: boolean; + readonly type: 'Monkey' | 'Horse' | 'Bird'; + listOfModels?: Array | null; + listOfStrings?: Array | null; + parameters: (ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary); readonly user?: { - readonly id?: number, - readonly name?: string | null, - }, + readonly id?: number; + readonly name?: string | null; + }; }, ): CancelablePromise { return __request({ @@ -5031,11 +5150,11 @@ export class MultipartService { * @throws ApiError */ public static multipartResponse(): CancelablePromise<{ - file?: string, + file?: string; metadata?: { - foo?: string, - bar?: string, - }, + foo?: string; + bar?: string; + }; }> { return __request({ method: 'GET', @@ -5282,9 +5401,9 @@ export class ResponseService { * @throws ApiError */ public static callWithResponses(): CancelablePromise<{ - readonly '@namespace.string'?: string, - readonly '@namespace.integer'?: number, - readonly value?: Array, + readonly '@namespace.string'?: string; + readonly '@namespace.integer'?: number; + readonly value?: Array; } | ModelWithString | ModelThatExtends | ModelThatExtendsExtends> { return __request({ method: 'PUT', @@ -5413,8 +5532,8 @@ export class TypesService { parameterDictionary: any, parameterEnum: 'Success' | 'Warning' | 'Error' | null, parameterNumber: number = 123, - parameterString: string | null = 'default', - parameterBoolean: boolean | null = true, + parameterString: string = 'default', + parameterBoolean: boolean = true, parameterObject: any = null, id?: number, ): CancelablePromise { diff --git a/test/spec/v2.json b/test/spec/v2.json index f657221c..433edc94 100644 --- a/test/spec/v2.json +++ b/test/spec/v2.json @@ -588,7 +588,7 @@ "in": "query", "required": true, "default": 123, - "type": "int" + "type": "number" }, { "description": "This is a string parameter", @@ -832,7 +832,7 @@ }, "EnumFromDescription": { "description": "Success=1,Warning=2,Error=3", - "type": "int" + "type": "number" }, "EnumWithExtensions": { "description": "This is a simple enum with numbers", @@ -1117,7 +1117,7 @@ "propWithNumber": { "type": "array", "items": { - "type": "int" + "type": "number" } } } diff --git a/test/spec/v3.json b/test/spec/v3.json index c588ced8..d07f5f77 100644 --- a/test/spec/v3.json +++ b/test/spec/v3.json @@ -828,7 +828,7 @@ "in": "query", "required": true, "schema": { - "type": "int", + "type": "number", "default": 123 } }, @@ -837,10 +837,10 @@ "name": "parameterString", "in": "query", "required": true, - "nullable": true, "schema": { "type": "string", - "default": "default" + "default": "default", + "nullable": true } }, { @@ -848,10 +848,10 @@ "name": "parameterBoolean", "in": "query", "required": true, - "nullable": true, "schema": { "type": "boolean", - "default": true + "default": true, + "nullable": true } }, { @@ -859,10 +859,10 @@ "name": "parameterObject", "in": "query", "required": true, - "nullable": true, "schema": { "type": "object", - "default": null + "default": null, + "nullable": true } }, { @@ -870,12 +870,12 @@ "name": "parameterArray", "in": "query", "required": true, - "nullable": true, "schema": { "type": "array", "items": { "type": "string" - } + }, + "nullable": true } }, { @@ -883,12 +883,12 @@ "name": "parameterDictionary", "in": "query", "required": true, - "nullable": true, "schema": { "type": "object", "items": { "type": "string" - } + }, + "nullable": true } }, { @@ -896,13 +896,13 @@ "name": "parameterEnum", "in": "query", "required": true, - "nullable": true, "schema": { "enum": [ "Success", "Warning", "Error" - ] + ], + "nullable": true } }, { @@ -972,16 +972,16 @@ "in": "formData", "required": true, "schema": { - "type": "File" + "type": "file" } }, { "name": "api-version", "in": "path", "required": true, - "nullable": true, "schema": { - "type": "string" + "type": "string", + "nullable": true } } ], @@ -1261,7 +1261,6 @@ "required": false, "content": { "application/json": { - "description": "Message for default response", "schema": { "$ref": "#/components/schemas/ModelWithString" } @@ -1288,7 +1287,7 @@ }, "SimpleFile": { "description": "This is a simple file", - "type": "File" + "type": "file" }, "SimpleReference": { "description": "This is a simple reference", @@ -1331,7 +1330,7 @@ }, "EnumFromDescription": { "description": "Success=1,Warning=2,Error=3", - "type": "int" + "type": "number" }, "EnumWithExtensions": { "description": "This is a simple enum with numbers", @@ -1483,6 +1482,40 @@ } } }, + "ModelWithNullableString": { + "description": "This is a model with one string property", + "type": "object", + "required": [ + "nullableRequiredProp1", + "nullableRequiredProp2" + ], + "properties": { + "nullableProp1": { + "description": "This is a simple string property", + "type": "string", + "nullable": true + }, + "nullableRequiredProp1": { + "description": "This is a simple string property", + "type": "string", + "nullable": true + }, + "nullableProp2": { + "description": "This is a simple string property", + "type": [ + "string", + "null" + ] + }, + "nullableRequiredProp2": { + "description": "This is a simple string property", + "type": [ + "string", + "null" + ] + } + } + }, "ModelWithEnum": { "description": "This is a model with one enum", "type": "object", @@ -1587,13 +1620,13 @@ "propWithFile": { "type": "array", "items": { - "type": "File" + "type": "file" } }, "propWithNumber": { "type": "array", "items": { - "type": "int" + "type": "number" } } } @@ -1653,7 +1686,9 @@ "description": "Anonymous object type", "type": "object", "properties": { - "propA": "string" + "propA": { + "type": "string" + } } }, { @@ -1702,7 +1737,9 @@ "description": "Anonymous object type", "type": "object", "properties": { - "propA": "string" + "propA": { + "type": "string" + } } }, { @@ -1804,6 +1841,37 @@ } } }, + "CompositionBaseModel": { + "description": "This is a base model with two simple optional properties", + "type": "object", + "properties": { + "firstName": { + "type": "string" + }, + "lastname": { + "type": "string" + } + } + }, + "CompositionExtendedModel": { + "description": "This is a model that extends the base model", + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/CompositionBaseModel" + } + ], + "properties": { + "age": { + "type": "number" + } + }, + "required": [ + "firstName", + "lastname", + "age" + ] + }, "ModelWithProperties": { "description": "This is a model with one nested property", "type": "object",