diff --git a/src/openApi/v3/interfaces/JsonCustomVocabulary.d.ts b/src/openApi/v3/interfaces/JsonCustomVocabulary.d.ts new file mode 100644 index 000000000..60ef7384e --- /dev/null +++ b/src/openApi/v3/interfaces/JsonCustomVocabulary.d.ts @@ -0,0 +1,5 @@ +// https://json-schema.org/draft/2020-12/json-schema-core.html#name-non-json-instances + +export interface JsonCustomVocabulary { + const?: string | number; +} diff --git a/src/openApi/v3/interfaces/OpenApiSchema.d.ts b/src/openApi/v3/interfaces/OpenApiSchema.d.ts index a51456f3b..91f732e05 100644 --- a/src/openApi/v3/interfaces/OpenApiSchema.d.ts +++ b/src/openApi/v3/interfaces/OpenApiSchema.d.ts @@ -1,5 +1,6 @@ import type { Dictionary } from '../../../utils/types'; import type { WithEnumExtension } from './Extensions/WithEnumExtension'; +import type { JsonCustomVocabulary } from './JsonCustomVocabulary'; import type { OpenApiDiscriminator } from './OpenApiDiscriminator'; import type { OpenApiExternalDocs } from './OpenApiExternalDocs'; import type { OpenApiReference } from './OpenApiReference'; @@ -8,7 +9,7 @@ import type { OpenApiXml } from './OpenApiXml'; /** * https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject */ -export interface OpenApiSchema extends OpenApiReference, WithEnumExtension { +export interface OpenApiSchema extends OpenApiReference, WithEnumExtension, JsonCustomVocabulary { title?: string; multipleOf?: number; maximum?: number; diff --git a/src/openApi/v3/parser/getModel.ts b/src/openApi/v3/parser/getModel.ts index b20371353..0c7fa2010 100644 --- a/src/openApi/v3/parser/getModel.ts +++ b/src/openApi/v3/parser/getModel.ts @@ -1,3 +1,4 @@ +import { Enum } from '../../../client/interfaces/Enum'; import type { Model } from '../../../client/interfaces/Model'; import { getPattern } from '../../../utils/getPattern'; import type { OpenApi } from '../interfaces/OpenApi'; @@ -8,6 +9,7 @@ import { getModelComposition } from './getModelComposition'; import { getModelDefault } from './getModelDefault'; import { getModelProperties } from './getModelProperties'; import { getType } from './getType'; +import { getOneOfEnum } from "./getOneOfEnum"; export const getModel = ( openApi: OpenApi, @@ -68,6 +70,7 @@ export const getModel = ( model.base = 'string'; model.enum.push(...extendedEnumerators); model.default = getModelDefault(definition, model); + return model; } } @@ -118,7 +121,22 @@ export const getModel = ( } } - if (definition.oneOf?.length) { + if ( + definition.oneOf?.length && + (definition.type === 'integer' || definition.type === 'string') && + (typeof definition.oneOf?.at(0)?.const === 'number' || typeof definition.oneOf?.at(0)?.const === 'string') + ) { + const enumerator: Enum[] = getOneOfEnum(definition.oneOf); + if (enumerator.length) { + model.export = 'enum'; + model.type = 'string'; + model.base = 'string'; + model.enum.push(...enumerator); + model.default = getModelDefault(definition, model); + + return model; + } + } else if (definition.oneOf?.length) { const composition = getModelComposition(openApi, definition, definition.oneOf, 'one-of', getModel); model.export = composition.type; model.imports.push(...composition.imports); diff --git a/src/openApi/v3/parser/getOneOfEnum.ts b/src/openApi/v3/parser/getOneOfEnum.ts new file mode 100644 index 000000000..9a1c4b897 --- /dev/null +++ b/src/openApi/v3/parser/getOneOfEnum.ts @@ -0,0 +1,22 @@ +import type { Enum } from '../../../client/interfaces/Enum'; +import { OpenApiSchema } from '../interfaces/OpenApiSchema'; + +export const getOneOfEnum = (oneOf: OpenApiSchema[]): Enum[] => + oneOf.reduce((enums, item) => { + if (typeof item.const === 'number') { + enums.push({ + value: String(item.const), + name: `${item.title}` || `'_${item.const}'`, + type: 'number', + description: item.description || item.title || null, + }); + } else { + enums.push({ + value: `'${item.const}'`, + name: `${item.title}` || `'${item.const}'`, + type: 'string', + description: item.description || item.title || null, + }); + } + return enums; + }, [] as Enum[]); diff --git a/test/__snapshots__/index.spec.ts.snap b/test/__snapshots__/index.spec.ts.snap index cb3405f2a..fed8a020f 100644 --- a/test/__snapshots__/index.spec.ts.snap +++ b/test/__snapshots__/index.spec.ts.snap @@ -3639,6 +3639,8 @@ export type { DictionaryWithProperties } from './models/DictionaryWithProperties export type { DictionaryWithReference } from './models/DictionaryWithReference'; export type { DictionaryWithString } from './models/DictionaryWithString'; export type { EnumFromDescription } from './models/EnumFromDescription'; +export { EnumViaOneOfNumeric } from './models/EnumViaOneOfNumeric'; +export { EnumViaOneOfString } from './models/EnumViaOneOfString'; export { EnumWithExtensions } from './models/EnumWithExtensions'; export { EnumWithNumbers } from './models/EnumWithNumbers'; export { EnumWithStrings } from './models/EnumWithStrings'; @@ -3704,6 +3706,8 @@ export { $DictionaryWithProperties } from './schemas/$DictionaryWithProperties'; export { $DictionaryWithReference } from './schemas/$DictionaryWithReference'; export { $DictionaryWithString } from './schemas/$DictionaryWithString'; export { $EnumFromDescription } from './schemas/$EnumFromDescription'; +export { $EnumViaOneOfNumeric } from './schemas/$EnumViaOneOfNumeric'; +export { $EnumViaOneOfString } from './schemas/$EnumViaOneOfString'; export { $EnumWithExtensions } from './schemas/$EnumWithExtensions'; export { $EnumWithNumbers } from './schemas/$EnumWithNumbers'; export { $EnumWithStrings } from './schemas/$EnumWithStrings'; @@ -4247,6 +4251,82 @@ export type EnumFromDescription = number; " `; +exports[`v3 should generate: ./test/generated/v3/models/EnumLike.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +/** + * OpenApi 3.1 style numeric enum + */ +export enum EnumLike { + /** + * Success + * / + SUCCESS = 0, + /** + * Warning + */ + 'WARNING' = 1, + /** + * Error + */ + 'ERROR' = 3, +}; + +" +`; + +exports[`v3 should generate: ./test/generated/v3/models/EnumViaOneOfNumeric.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +/** + * OpenApi 3.1 style numeric enum + */ +export enum EnumViaOneOfNumeric { + /** + * Success + */ + SUCCESS = 0, + /** + * Warning + */ + WARNING = 1, + /** + * Error + */ + ERROR = 3, +} +" +`; + +exports[`v3 should generate: ./test/generated/v3/models/EnumViaOneOfString.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +/** + * OpenApi 3.1 style numeric enum + */ +export enum EnumViaOneOfString { + /** + * Success + */ + SUCCESS = 'SUCCESS', + /** + * Warning + */ + WARNING = 'SUCCESS', + /** + * Error + */ + ERROR = 'SUCCESS', +} +" +`; + exports[`v3 should generate: ./test/generated/v3/models/EnumWithExtensions.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -4281,6 +4361,7 @@ exports[`v3 should generate: ./test/generated/v3/models/EnumWithNumbers.ts 1`] = * This is a simple enum with numbers */ export enum EnumWithNumbers { + '_0' = 0, '_1' = 1, '_2' = 2, '_3' = 3, @@ -5447,6 +5528,26 @@ export const $EnumFromDescription = { " `; +exports[`v3 should generate: ./test/generated/v3/schemas/$EnumViaOneOfNumeric.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $EnumViaOneOfNumeric = { + type: 'Enum', +} as const; +" +`; + +exports[`v3 should generate: ./test/generated/v3/schemas/$EnumViaOneOfString.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $EnumViaOneOfString = { + type: 'Enum', +} as const; +" +`; + exports[`v3 should generate: ./test/generated/v3/schemas/$EnumWithExtensions.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ diff --git a/test/spec/v3.json b/test/spec/v3.json index aca05acaf..376da156f 100644 --- a/test/spec/v3.json +++ b/test/spec/v3.json @@ -1567,6 +1567,7 @@ "EnumWithNumbers": { "description": "This is a simple enum with numbers", "enum": [ + 0, 1, 2, 3, @@ -1606,6 +1607,48 @@ "Used when the status of something has an error" ] }, + "EnumViaOneOfNumeric": { + "description": "OpenApi 3.1 style numeric enum", + "type": "integer", + "oneOf": [ + { + "const": 0, + "title": "SUCCESS", + "description": "Success" + }, + { + "const": 1, + "title": "WARNING", + "description": "Warning" + }, + { + "const": 3, + "title": "ERROR", + "description": "Error" + } + ] + }, + "EnumViaOneOfString": { + "description": "OpenApi 3.1 style titled enum", + "type": "string", + "oneOf": [ + { + "const": "SUCCESS", + "title": "SUCCESS", + "description": "Success" + }, + { + "const": "SUCCESS", + "title": "WARNING", + "description": "Warning" + }, + { + "const": "SUCCESS", + "title": "ERROR", + "description": "Error" + } + ] + }, "ArrayWithNumbers": { "description": "This is a simple array with numbers", "type": "array",