diff --git a/package.json b/package.json index 1375db7f..24cb917a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openapi-typescript-codegen", - "version": "0.1.12", + "version": "0.1.13", "description": "NodeJS library that generates Typescript or Javascript clients based on the OpenAPI specification.", "author": "Ferdi Koomen", "homepage": "https://github.com/ferdikoomen/openapi-typescript-codegen", diff --git a/src/openApi/v3/parser/getModel.ts b/src/openApi/v3/parser/getModel.ts index 853eb29c..fbb5caec 100644 --- a/src/openApi/v3/parser/getModel.ts +++ b/src/openApi/v3/parser/getModel.ts @@ -112,6 +112,26 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isProperty } } + if (definition.anyOf && definition.anyOf.length) { + model.export = 'generic'; + const compositionTypes = definition.anyOf.filter(type => type.$ref).map(type => getType(type.$ref)); + const composition = compositionTypes.map(type => type.type).join(' | '); + model.imports.push(...compositionTypes.map(type => type.base)); + model.type = composition; + model.base = composition; + return model; + } + + if (definition.oneOf && definition.oneOf.length) { + model.export = 'generic'; + const compositionTypes = definition.oneOf.filter(type => type.$ref).map(type => getType(type.$ref)); + const composition = compositionTypes.map(type => type.type).join(' | '); + model.imports.push(...compositionTypes.map(type => type.base)); + model.type = composition; + model.base = composition; + return model; + } + if (definition.type === 'object') { model.export = 'interface'; model.type = PrimaryType.OBJECT; diff --git a/test/__snapshots__/index.spec.js.snap b/test/__snapshots__/index.spec.js.snap index 46ea6baf..c99a8924 100644 --- a/test/__snapshots__/index.spec.js.snap +++ b/test/__snapshots__/index.spec.js.snap @@ -2602,6 +2602,7 @@ export { EnumWithStrings } from './models/EnumWithStrings'; export { ModelLink } from './models/ModelLink'; export { ModelThatExtends } from './models/ModelThatExtends'; export { ModelThatExtendsExtends } from './models/ModelThatExtendsExtends'; +export { ModelWithAnyOf } from './models/ModelWithAnyOf'; export { ModelWithArray } from './models/ModelWithArray'; export { ModelWithBoolean } from './models/ModelWithBoolean'; export { ModelWithCircularReference } from './models/ModelWithCircularReference'; @@ -2614,6 +2615,7 @@ export { ModelWithInteger } from './models/ModelWithInteger'; export { ModelWithLink } from './models/ModelWithLink'; export { ModelWithNestedEnums } from './models/ModelWithNestedEnums'; export { ModelWithNestedProperties } from './models/ModelWithNestedProperties'; +export { ModelWithOneOf } from './models/ModelWithOneOf'; export { ModelWithOrderedProperties } from './models/ModelWithOrderedProperties'; export { ModelWithProperties } from './models/ModelWithProperties'; export { ModelWithReference } from './models/ModelWithReference'; @@ -2641,6 +2643,7 @@ export { $EnumWithStrings } from './schemas/$EnumWithStrings'; export { $ModelLink } from './schemas/$ModelLink'; export { $ModelThatExtends } from './schemas/$ModelThatExtends'; export { $ModelThatExtendsExtends } from './schemas/$ModelThatExtendsExtends'; +export { $ModelWithAnyOf } from './schemas/$ModelWithAnyOf'; export { $ModelWithArray } from './schemas/$ModelWithArray'; export { $ModelWithBoolean } from './schemas/$ModelWithBoolean'; export { $ModelWithCircularReference } from './schemas/$ModelWithCircularReference'; @@ -2653,6 +2656,7 @@ export { $ModelWithInteger } from './schemas/$ModelWithInteger'; export { $ModelWithLink } from './schemas/$ModelWithLink'; export { $ModelWithNestedEnums } from './schemas/$ModelWithNestedEnums'; export { $ModelWithNestedProperties } from './schemas/$ModelWithNestedProperties'; +export { $ModelWithOneOf } from './schemas/$ModelWithOneOf'; export { $ModelWithOrderedProperties } from './schemas/$ModelWithOrderedProperties'; export { $ModelWithProperties } from './schemas/$ModelWithProperties'; export { $ModelWithReference } from './schemas/$ModelWithReference'; @@ -2947,6 +2951,26 @@ export interface ModelThatExtendsExtends extends ModelWithString, ModelThatExten " `; +exports[`generation v3 file(./test/result/v3/models/ModelWithAnyOf.ts): ./test/result/v3/models/ModelWithAnyOf.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +/* prettier-ignore */ + +import { ModelWithArray } from './ModelWithArray'; +import { ModelWithDictionary } from './ModelWithDictionary'; +import { ModelWithEnum } from './ModelWithEnum'; +import { ModelWithString } from './ModelWithString'; + +/** + * This is a model with one property with a 'any of' relationship + */ +export interface ModelWithAnyOf { + propA?: ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary; +} +" +`; + exports[`generation v3 file(./test/result/v3/models/ModelWithArray.ts): ./test/result/v3/models/ModelWithArray.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -3197,6 +3221,26 @@ export interface ModelWithNestedProperties { " `; +exports[`generation v3 file(./test/result/v3/models/ModelWithOneOf.ts): ./test/result/v3/models/ModelWithOneOf.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +/* prettier-ignore */ + +import { ModelWithArray } from './ModelWithArray'; +import { ModelWithDictionary } from './ModelWithDictionary'; +import { ModelWithEnum } from './ModelWithEnum'; +import { ModelWithString } from './ModelWithString'; + +/** + * This is a model with one property with a 'one of' relationship + */ +export interface ModelWithOneOf { + propA?: ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary; +} +" +`; + exports[`generation v3 file(./test/result/v3/models/ModelWithOrderedProperties.ts): ./test/result/v3/models/ModelWithOrderedProperties.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -3553,6 +3597,21 @@ export const $ModelThatExtendsExtends = { };" `; +exports[`generation v3 file(./test/result/v3/schemas/$ModelWithAnyOf.ts): ./test/result/v3/schemas/$ModelWithAnyOf.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +/* prettier-ignore */ + +export const $ModelWithAnyOf = { + properties: { + propA: { + type: 'ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary', + }, + }, +};" +`; + exports[`generation v3 file(./test/result/v3/schemas/$ModelWithArray.ts): ./test/result/v3/schemas/$ModelWithArray.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -3771,6 +3830,21 @@ export const $ModelWithNestedProperties = { };" `; +exports[`generation v3 file(./test/result/v3/schemas/$ModelWithOneOf.ts): ./test/result/v3/schemas/$ModelWithOneOf.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +/* prettier-ignore */ + +export const $ModelWithOneOf = { + properties: { + propA: { + type: 'ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary', + }, + }, +};" +`; + exports[`generation v3 file(./test/result/v3/schemas/$ModelWithOrderedProperties.ts): ./test/result/v3/schemas/$ModelWithOrderedProperties.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -3921,6 +3995,9 @@ exports[`generation v3 file(./test/result/v3/services/ComplexService.ts): ./test /* eslint-disable */ /* prettier-ignore */ +import { ModelWithArray } from '../models/ModelWithArray'; +import { ModelWithDictionary } from '../models/ModelWithDictionary'; +import { ModelWithEnum } from '../models/ModelWithEnum'; import { ModelWithString } from '../models/ModelWithString'; import { ApiError, catchGenericError } from '../core/ApiError'; import { request as __request } from '../core/request'; @@ -3966,6 +4043,40 @@ export class ComplexService { return result.body; } + /** + * @param id + * @param requestBody + * @result ModelWithString Success + * @throws ApiError + */ + public static async 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 user?: { + readonly id?: number, + readonly name?: string | null, + }, + }, + ): Promise { + + const result = await __request({ + method: 'put', + path: \`/api/v\${OpenAPI.VERSION}/complex/\${id}\`, + body: requestBody, + }); + + catchGenericError(result); + + return result.body; + } + }" `; diff --git a/test/mock/v3/spec.json b/test/mock/v3/spec.json index e9a510f8..3617acdc 100644 --- a/test/mock/v3/spec.json +++ b/test/mock/v3/spec.json @@ -589,6 +589,134 @@ } } } + }, + "/api/v{api-version}/complex/{id}": { + "put": { + "tags": [ + "Complex" + ], + "operationId": "ComplexParams", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "api-version", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json-patch+json": { + "schema": { + "required": [ + "key", + "name", + "parameters", + "type" + ], + "type": "object", + "properties": { + "key": { + "maxLength": 64, + "pattern": "^[a-zA-Z0-9_]*$", + "type": "string", + "nullable": true, + "readOnly": true + }, + "name": { + "maxLength": 255, + "type": "string", + "nullable": true + }, + "enabled": { + "type": "boolean", + "default": true + }, + "type": { + "enum": [ + "Monkey", + "Horse", + "Bird" + ], + "type": "string", + "readOnly": true + }, + "listOfModels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelWithString" + }, + "nullable": true + }, + "listOfStrings": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "parameters": { + "type": "object", + "oneOf": [ + { + "$ref": "#/components/schemas/ModelWithString" + }, + { + "$ref": "#/components/schemas/ModelWithEnum" + }, + { + "$ref": "#/components/schemas/ModelWithArray" + }, + { + "$ref": "#/components/schemas/ModelWithDictionary" + } + ] + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "name": { + "type": "string", + "nullable": true, + "readOnly": true + } + }, + "readOnly": true + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelWithString" + } + } + } + } + } + } } }, "components": { @@ -901,6 +1029,52 @@ } } }, + "ModelWithOneOf": { + "description": "This is a model with one property with a 'one of' relationship", + "type": "object", + "properties": { + "propA": { + "type": "object", + "oneOf": [ + { + "$ref": "#/components/schemas/ModelWithString" + }, + { + "$ref": "#/components/schemas/ModelWithEnum" + }, + { + "$ref": "#/components/schemas/ModelWithArray" + }, + { + "$ref": "#/components/schemas/ModelWithDictionary" + } + ] + } + } + }, + "ModelWithAnyOf": { + "description": "This is a model with one property with a 'any of' relationship", + "type": "object", + "properties": { + "propA": { + "type": "object", + "anyOf": [ + { + "$ref": "#/components/schemas/ModelWithString" + }, + { + "$ref": "#/components/schemas/ModelWithEnum" + }, + { + "$ref": "#/components/schemas/ModelWithArray" + }, + { + "$ref": "#/components/schemas/ModelWithDictionary" + } + ] + } + } + }, "ModelWithProperties": { "description": "This is a model with one nested property", "type": "object",