From e003116fa52c3ab790bfb6306b80677c3bef05d6 Mon Sep 17 00:00:00 2001 From: kshramt Date: Wed, 27 Jul 2022 12:23:44 +0900 Subject: [PATCH] Support free-form objects > A free-form object (arbitrary property/value pairs) is defined as: > > type: object > > This is equivalent to > > type: object > additionalProperties: true > > and > > type: object > additionalProperties: {} https://swagger.io/docs/specification/data-models/data-types/ --- src/openApi/v3/parser/getModel.ts | 34 +++++++--- test/__snapshots__/index.spec.ts.snap | 90 ++++++++++++++++++++++++++- test/spec/v3.json | 14 +++++ 3 files changed, 125 insertions(+), 13 deletions(-) diff --git a/src/openApi/v3/parser/getModel.ts b/src/openApi/v3/parser/getModel.ts index b2037135..9e9c60a9 100644 --- a/src/openApi/v3/parser/getModel.ts +++ b/src/openApi/v3/parser/getModel.ts @@ -95,9 +95,13 @@ export const getModel = ( } } - if (definition.type === 'object' && typeof definition.additionalProperties === 'object') { - if (definition.additionalProperties.$ref) { - const additionalProperties = getType(definition.additionalProperties.$ref); + if ( + definition.type === 'object' && + (typeof definition.additionalProperties === 'object' || definition.additionalProperties === true) + ) { + const ap = typeof definition.additionalProperties === 'object' ? definition.additionalProperties : {}; + if (ap.$ref) { + const additionalProperties = getType(ap.$ref); model.export = 'dictionary'; model.type = additionalProperties.type; model.base = additionalProperties.base; @@ -106,7 +110,7 @@ export const getModel = ( model.default = getModelDefault(definition, model); return model; } else { - const additionalProperties = getModel(openApi, definition.additionalProperties); + const additionalProperties = getModel(openApi, ap); model.export = 'dictionary'; model.type = additionalProperties.type; model.base = additionalProperties.base; @@ -146,12 +150,12 @@ export const getModel = ( } if (definition.type === 'object') { - model.export = 'interface'; - model.type = 'any'; - model.base = 'any'; - model.default = getModelDefault(definition, model); - if (definition.properties) { + model.export = 'interface'; + model.type = 'any'; + model.base = 'any'; + model.default = getModelDefault(definition, model); + const modelProperties = getModelProperties(openApi, definition, getModel, model); modelProperties.forEach(modelProperty => { model.imports.push(...modelProperty.imports); @@ -161,8 +165,18 @@ export const getModel = ( model.enums.push(modelProperty); } }); + return model; + } else { + const additionalProperties = getModel(openApi, {}); + model.export = 'dictionary'; + model.type = additionalProperties.type; + model.base = additionalProperties.base; + model.template = additionalProperties.template; + model.link = additionalProperties; + model.imports.push(...additionalProperties.imports); + model.default = getModelDefault(definition, model); + return model; } - return model; } // If the schema has a type than it can be a basic or generic type. diff --git a/test/__snapshots__/index.spec.ts.snap b/test/__snapshots__/index.spec.ts.snap index cb3405f2..73383c3e 100644 --- a/test/__snapshots__/index.spec.ts.snap +++ b/test/__snapshots__/index.spec.ts.snap @@ -3643,6 +3643,9 @@ export { EnumWithExtensions } from './models/EnumWithExtensions'; export { EnumWithNumbers } from './models/EnumWithNumbers'; export { EnumWithStrings } from './models/EnumWithStrings'; export type { File } from './models/File'; +export type { FreeFormObjectWithAdditionalPropertiesEqEmptyObject } from './models/FreeFormObjectWithAdditionalPropertiesEqEmptyObject'; +export type { FreeFormObjectWithAdditionalPropertiesEqTrue } from './models/FreeFormObjectWithAdditionalPropertiesEqTrue'; +export type { FreeFormObjectWithoutAdditionalProperties } from './models/FreeFormObjectWithoutAdditionalProperties'; export type { ModelCircle } from './models/ModelCircle'; export type { ModelSquare } from './models/ModelSquare'; export type { ModelThatExtends } from './models/ModelThatExtends'; @@ -3708,6 +3711,9 @@ export { $EnumWithExtensions } from './schemas/$EnumWithExtensions'; export { $EnumWithNumbers } from './schemas/$EnumWithNumbers'; export { $EnumWithStrings } from './schemas/$EnumWithStrings'; export { $File } from './schemas/$File'; +export { $FreeFormObjectWithAdditionalPropertiesEqEmptyObject } from './schemas/$FreeFormObjectWithAdditionalPropertiesEqEmptyObject'; +export { $FreeFormObjectWithAdditionalPropertiesEqTrue } from './schemas/$FreeFormObjectWithAdditionalPropertiesEqTrue'; +export { $FreeFormObjectWithoutAdditionalProperties } from './schemas/$FreeFormObjectWithoutAdditionalProperties'; export { $ModelCircle } from './schemas/$ModelCircle'; export { $ModelSquare } from './schemas/$ModelSquare'; export { $ModelThatExtends } from './schemas/$ModelThatExtends'; @@ -4334,6 +4340,42 @@ export type File = { " `; +exports[`v3 should generate: ./test/generated/v3/models/FreeFormObjectWithAdditionalPropertiesEqEmptyObject.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +/** + * This is a free-form object with additionalProperties: {}. + */ +export type FreeFormObjectWithAdditionalPropertiesEqEmptyObject = Record; +" +`; + +exports[`v3 should generate: ./test/generated/v3/models/FreeFormObjectWithAdditionalPropertiesEqTrue.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +/** + * This is a free-form object with additionalProperties: true. + */ +export type FreeFormObjectWithAdditionalPropertiesEqTrue = Record; +" +`; + +exports[`v3 should generate: ./test/generated/v3/models/FreeFormObjectWithoutAdditionalProperties.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +/** + * This is a free-form object without additionalProperties. + */ +export type FreeFormObjectWithoutAdditionalProperties = Record; +" +`; + exports[`v3 should generate: ./test/generated/v3/models/ModelCircle.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -5514,6 +5556,48 @@ export const $File = { " `; +exports[`v3 should generate: ./test/generated/v3/schemas/$FreeFormObjectWithAdditionalPropertiesEqEmptyObject.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $FreeFormObjectWithAdditionalPropertiesEqEmptyObject = { + type: 'dictionary', + contains: { + properties: { + }, + }, +} as const; +" +`; + +exports[`v3 should generate: ./test/generated/v3/schemas/$FreeFormObjectWithAdditionalPropertiesEqTrue.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $FreeFormObjectWithAdditionalPropertiesEqTrue = { + type: 'dictionary', + contains: { + properties: { + }, + }, +} as const; +" +`; + +exports[`v3 should generate: ./test/generated/v3/schemas/$FreeFormObjectWithoutAdditionalProperties.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $FreeFormObjectWithoutAdditionalProperties = { + type: 'dictionary', + contains: { + properties: { + }, + }, +} as const; +" +`; + exports[`v3 should generate: ./test/generated/v3/schemas/$ModelCircle.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -7148,14 +7232,14 @@ export class TypesService { */ public static types( parameterArray: Array | null, - parameterDictionary: any, + parameterDictionary: Record | null, parameterEnum: 'Success' | 'Warning' | 'Error' | null, parameterNumber: number = 123, parameterString: string | null = 'default', parameterBoolean: boolean | null = true, - parameterObject: any = null, + parameterObject: Record | null = null, id?: number, - ): CancelablePromise { + ): CancelablePromise> { return __request(OpenAPI, { method: 'GET', url: '/api/v{api-version}/types', diff --git a/test/spec/v3.json b/test/spec/v3.json index aca05aca..3cfa965e 100644 --- a/test/spec/v3.json +++ b/test/spec/v3.json @@ -2527,6 +2527,20 @@ } } } + }, + "FreeFormObjectWithoutAdditionalProperties": { + "description": "This is a free-form object without additionalProperties.", + "type": "object" + }, + "FreeFormObjectWithAdditionalPropertiesEqTrue": { + "description": "This is a free-form object with additionalProperties: true.", + "type": "object", + "additionalProperties": true + }, + "FreeFormObjectWithAdditionalPropertiesEqEmptyObject": { + "description": "This is a free-form object with additionalProperties: {}.", + "type": "object", + "additionalProperties": {} } } }