From ab9c15d579b5caa63e3ea6df797005bb84201877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Kaln=C3=BD?= Date: Wed, 23 Aug 2023 13:49:29 +0200 Subject: [PATCH] Made additionalProperties add an index signature to unkown when explicit properties are specified --- src/openApi/v3/parser/getModel.ts | 38 +++++++++++- test/__snapshots__/index.spec.ts.snap | 84 +++++++++++++++++++++++++++ test/spec/v3.json | 20 +++++++ 3 files changed, 140 insertions(+), 2 deletions(-) diff --git a/src/openApi/v3/parser/getModel.ts b/src/openApi/v3/parser/getModel.ts index 9e9c60a98..c3d941797 100644 --- a/src/openApi/v3/parser/getModel.ts +++ b/src/openApi/v3/parser/getModel.ts @@ -19,7 +19,7 @@ export const getModel = ( name, export: 'interface', type: 'any', - base: 'any', + base: 'unknown', template: null, link: null, description: definition.description || null, @@ -97,7 +97,8 @@ export const getModel = ( if ( definition.type === 'object' && - (typeof definition.additionalProperties === 'object' || definition.additionalProperties === true) + (typeof definition.additionalProperties === 'object' || definition.additionalProperties === true) && + !definition.properties ) { const ap = typeof definition.additionalProperties === 'object' ? definition.additionalProperties : {}; if (ap.$ref) { @@ -165,6 +166,39 @@ export const getModel = ( model.enums.push(modelProperty); } }); + + if (definition.additionalProperties) { + const apModel: Model = { + base: 'unknown', + description: 'Additional properties are not explicitly defined may be present.', + enum: [], + enums: [], + export: 'generic', + imports: [], + isDefinition: false, + isNullable: false, + isReadOnly: false, + isRequired: true, + link: null, + name: '[additionalProperty: string]', + properties: [], + template: null, + type: 'unknown', + }; + + if (typeof definition.additionalProperties === 'object') { + const additionalProperties = getModel(openApi, definition.additionalProperties); + apModel.type = additionalProperties.type; + apModel.base = additionalProperties.base; + apModel.template = additionalProperties.template; + apModel.link = additionalProperties; + apModel.imports.push(...additionalProperties.imports); + apModel.default = getModelDefault(definition, model); + } + + model.properties.push(apModel); + } + return model; } else { const additionalProperties = getModel(openApi, {}); diff --git a/test/__snapshots__/index.spec.ts.snap b/test/__snapshots__/index.spec.ts.snap index ef6b18554..72b046fea 100644 --- a/test/__snapshots__/index.spec.ts.snap +++ b/test/__snapshots__/index.spec.ts.snap @@ -3724,6 +3724,8 @@ export type { ModelWithPattern } from './models/ModelWithPattern'; export type { ModelWithProperties } from './models/ModelWithProperties'; export type { ModelWithReference } from './models/ModelWithReference'; export type { ModelWithString } from './models/ModelWithString'; +export type { ObjectWithAdditionalPropertiesEqEmptyObject } from './models/ObjectWithAdditionalPropertiesEqEmptyObject'; +export type { ObjectWithAdditionalPropertiesEqTrue } from './models/ObjectWithAdditionalPropertiesEqTrue'; export type { Pageable } from './models/Pageable'; export type { SimpleBoolean } from './models/SimpleBoolean'; export type { SimpleFile } from './models/SimpleFile'; @@ -3794,6 +3796,8 @@ export { $ModelWithPattern } from './schemas/$ModelWithPattern'; export { $ModelWithProperties } from './schemas/$ModelWithProperties'; export { $ModelWithReference } from './schemas/$ModelWithReference'; export { $ModelWithString } from './schemas/$ModelWithString'; +export { $ObjectWithAdditionalPropertiesEqEmptyObject } from './schemas/$ObjectWithAdditionalPropertiesEqEmptyObject'; +export { $ObjectWithAdditionalPropertiesEqTrue } from './schemas/$ObjectWithAdditionalPropertiesEqTrue'; export { $Pageable } from './schemas/$Pageable'; export { $SimpleBoolean } from './schemas/$SimpleBoolean'; export { $SimpleFile } from './schemas/$SimpleFile'; @@ -4853,6 +4857,44 @@ export type ModelWithString = { " `; +exports[`v3 should generate: test/generated/v3/models/ObjectWithAdditionalPropertiesEqEmptyObject.ts 1`] = ` +"/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +/** + * This is an object with additionalProperties: {}. + */ +export type ObjectWithAdditionalPropertiesEqEmptyObject = { + name?: string; + /** + * Additional properties are not explicitly defined may be present. + */ + [additionalProperty: string]: unknown; +}; + +" +`; + +exports[`v3 should generate: test/generated/v3/models/ObjectWithAdditionalPropertiesEqTrue.ts 1`] = ` +"/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +/** + * This is an object with additionalProperties: true. + */ +export type ObjectWithAdditionalPropertiesEqTrue = { + name?: string; + /** + * Additional properties are not explicitly defined may be present. + */ + [additionalProperty: string]: unknown; +}; + +" +`; + exports[`v3 should generate: test/generated/v3/models/Pageable.ts 1`] = ` "/* generated using openapi-typescript-codegen -- do no edit */ /* istanbul ignore file */ @@ -6243,6 +6285,48 @@ export const $ModelWithString = { " `; +exports[`v3 should generate: test/generated/v3/schemas/$ObjectWithAdditionalPropertiesEqEmptyObject.ts 1`] = ` +"/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $ObjectWithAdditionalPropertiesEqEmptyObject = { + description: \`This is an object with additionalProperties: {}.\`, + properties: { + name: { + type: 'string', + }, + [additionalProperty: string]: { + type: 'any', + description: \`Additional properties are not explicitly defined may be present.\`, + isRequired: true, + }, + }, +} as const; +" +`; + +exports[`v3 should generate: test/generated/v3/schemas/$ObjectWithAdditionalPropertiesEqTrue.ts 1`] = ` +"/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $ObjectWithAdditionalPropertiesEqTrue = { + description: \`This is an object with additionalProperties: true.\`, + properties: { + name: { + type: 'string', + }, + [additionalProperty: string]: { + type: 'unknown', + description: \`Additional properties are not explicitly defined may be present.\`, + isRequired: true, + }, + }, +} as const; +" +`; + exports[`v3 should generate: test/generated/v3/schemas/$Pageable.ts 1`] = ` "/* generated using openapi-typescript-codegen -- do no edit */ /* istanbul ignore file */ diff --git a/test/spec/v3.json b/test/spec/v3.json index cb590d0b7..828f545c4 100644 --- a/test/spec/v3.json +++ b/test/spec/v3.json @@ -2553,6 +2553,26 @@ "description": "This is a free-form object with additionalProperties: {}.", "type": "object", "additionalProperties": {} + }, + "ObjectWithAdditionalPropertiesEqTrue": { + "description": "This is an object with additionalProperties: true.", + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "additionalProperties": true + }, + "ObjectWithAdditionalPropertiesEqEmptyObject": { + "description": "This is an object with additionalProperties: {}.", + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "additionalProperties": {} } } }