From 540490563b73aae942e00495647ecd675c42eb21 Mon Sep 17 00:00:00 2001 From: Raphael Guttenberger Date: Fri, 2 Feb 2024 12:09:30 +0100 Subject: [PATCH] feat(spec): allow additional fields on enum refs --- e2e/api-spec.json | 59 ++++++++++++++++----------- e2e/express.e2e-spec.ts | 2 +- e2e/fastify.e2e-spec.ts | 2 +- e2e/src/cats/classes/cat.class.ts | 9 ++++ e2e/src/cats/dto/create-cat.dto.ts | 9 ++++ e2e/validate-schema.e2e-spec.ts | 2 +- lib/services/schema-object-factory.ts | 37 +++++++++-------- 7 files changed, 77 insertions(+), 43 deletions(-) diff --git a/e2e/api-spec.json b/e2e/api-spec.json index 2f2ef347a..a5d20add5 100644 --- a/e2e/api-spec.json +++ b/e2e/api-spec.json @@ -205,8 +205,8 @@ "description": "Test", "required": false, "schema": { - "default": "test", - "type": "string" + "type": "string", + "default": "test" } }, { @@ -277,8 +277,8 @@ "description": "Test", "required": false, "schema": { - "default": "test", - "type": "string" + "type": "string", + "default": "test" } }, { @@ -415,8 +415,8 @@ "description": "Test", "required": false, "schema": { - "default": "test", - "type": "string" + "type": "string", + "default": "test" } }, { @@ -474,8 +474,8 @@ "description": "Test", "required": false, "schema": { - "default": "test", - "type": "string" + "type": "string", + "default": "test" } }, { @@ -610,8 +610,8 @@ "description": "Test", "required": false, "schema": { - "default": "test", - "type": "string" + "type": "string", + "default": "test" } }, { @@ -662,8 +662,8 @@ "description": "Test", "required": false, "schema": { - "default": "test", - "type": "string" + "type": "string", + "default": "test" } }, { @@ -720,8 +720,8 @@ "description": "Test", "required": false, "schema": { - "default": "test", - "type": "string" + "type": "string", + "default": "test" } }, { @@ -784,8 +784,8 @@ "description": "Test", "required": false, "schema": { - "default": "test", - "type": "string" + "type": "string", + "default": "test" } }, { @@ -828,8 +828,8 @@ "description": "Test", "required": false, "schema": { - "default": "test", - "type": "string" + "type": "string", + "default": "test" } }, { @@ -885,8 +885,8 @@ "description": "Test", "required": false, "schema": { - "default": "test", - "type": "string" + "type": "string", + "default": "test" } }, { @@ -937,8 +937,8 @@ "description": "Test", "required": false, "schema": { - "default": "test", - "type": "string" + "type": "string", + "default": "test" } }, { @@ -1049,6 +1049,9 @@ }, "LettersEnum": { "type": "string", + "description": "A small assortment of letters?", + "deprecated": true, + "default": "A", "enum": [ "A", "B", @@ -1128,6 +1131,9 @@ "$ref": "#/components/schemas/LettersEnum" } }, + "enumWithRef": { + "$ref": "#/components/schemas/LettersEnum" + }, "tag": { "description": "tag", "allOf": [ @@ -1151,7 +1157,8 @@ "options", "enumWithDescription", "enum", - "enumArr" + "enumArr", + "enumWithRef" ] }, "Cat": { @@ -1223,6 +1230,9 @@ "C" ] } + }, + "enumWithRef": { + "$ref": "#/components/schemas/LettersEnum" } }, "required": [ @@ -1234,7 +1244,8 @@ "urls", "_options", "enum", - "enumArr" + "enumArr", + "enumWithRef" ] }, "Letter": { diff --git a/e2e/express.e2e-spec.ts b/e2e/express.e2e-spec.ts index e2c6c1c16..5a3f11677 100644 --- a/e2e/express.e2e-spec.ts +++ b/e2e/express.e2e-spec.ts @@ -46,7 +46,7 @@ describe('Express Swagger', () => { const doc = JSON.stringify(document, null, 2); try { - let api = await SwaggerParser.validate(document as any); + const api = await SwaggerParser.validate(document as any); console.log( 'API name: %s, Version: %s', api.info.title, diff --git a/e2e/fastify.e2e-spec.ts b/e2e/fastify.e2e-spec.ts index 237eb4589..fabb58ab6 100644 --- a/e2e/fastify.e2e-spec.ts +++ b/e2e/fastify.e2e-spec.ts @@ -46,7 +46,7 @@ describe('Fastify Swagger', () => { const doc = JSON.stringify(document, null, 2); try { - let api = await SwaggerParser.validate(document as any); + const api = await SwaggerParser.validate(document as any); console.log( 'API name: %s, Version: %s', api.info.title, diff --git a/e2e/src/cats/classes/cat.class.ts b/e2e/src/cats/classes/cat.class.ts index b135a4a69..ff568d549 100644 --- a/e2e/src/cats/classes/cat.class.ts +++ b/e2e/src/cats/classes/cat.class.ts @@ -53,4 +53,13 @@ export class Cat { isArray: true }) enumArr: LettersEnum; + + @ApiProperty({ + enum: LettersEnum, + enumName: 'LettersEnum', + description: 'A small assortment of letters?', + default: 'A', + deprecated: true, + }) + enumWithRef: LettersEnum } diff --git a/e2e/src/cats/dto/create-cat.dto.ts b/e2e/src/cats/dto/create-cat.dto.ts index a250cc604..185b8ca8d 100644 --- a/e2e/src/cats/dto/create-cat.dto.ts +++ b/e2e/src/cats/dto/create-cat.dto.ts @@ -61,6 +61,15 @@ export class CreateCatDto { }) readonly enumArr: LettersEnum; + @ApiProperty({ + enum: LettersEnum, + enumName: 'LettersEnum', + description: 'A small assortment of letters?', + default: 'A', + deprecated: true, + }) + readonly enumWithRef: LettersEnum + @ApiProperty({ description: 'tag', required: false }) readonly tag: TagDto; diff --git a/e2e/validate-schema.e2e-spec.ts b/e2e/validate-schema.e2e-spec.ts index 8f99f0195..198f2b06f 100644 --- a/e2e/validate-schema.e2e-spec.ts +++ b/e2e/validate-schema.e2e-spec.ts @@ -104,7 +104,7 @@ describe('Validate OpenAPI schema', () => { writeFileSync(join(__dirname, 'api-spec.json'), doc); try { - let api = await SwaggerParser.validate(document as any); + const api = await SwaggerParser.validate(document as any); console.log( 'API name: %s, Version: %s', api.info.title, diff --git a/lib/services/schema-object-factory.ts b/lib/services/schema-object-factory.ts index 9573248f6..8c72bd989 100644 --- a/lib/services/schema-object-factory.ts +++ b/lib/services/schema-object-factory.ts @@ -300,21 +300,25 @@ export class SchemaObjectFactory { const enumName = metadata.enumName; const $ref = getSchemaPath(enumName); - if (!(enumName in schemas)) { - const enumType: string = ( - metadata.isArray - ? metadata.items['type'] - : metadata.type - ) ?? 'string'; - - schemas[enumName] = { - type: enumType, - enum: - metadata.isArray && metadata.items - ? metadata.items['enum'] - : metadata.enum - }; - } + // Allow given fields to be part of the referenced enum schema + const additionalParams = ['description', 'deprecated', 'default'] + const additionalFields = additionalParams.reduce((acc, param) => + ({...acc, ...(metadata[param] && { [param]: metadata[param] })}), {}); + + const enumType: string = ( + metadata.isArray + ? metadata.items['type'] + : metadata.type + ) ?? 'string'; + + schemas[enumName] = { + type: enumType, + ...additionalFields, + enum: + metadata.isArray && metadata.items + ? metadata.items['enum'] + : metadata.enum + }; const _schemaObject = { ...metadata, @@ -324,7 +328,7 @@ export class SchemaObjectFactory { const refHost = metadata.isArray ? { items: { $ref } } : { $ref }; const paramObject = { ..._schemaObject, ...refHost }; - const pathsToOmit = ['enum', 'enumName']; + const pathsToOmit = ['enum', 'enumName', ...additionalParams]; if (!metadata.isArray) { pathsToOmit.push('type'); @@ -498,6 +502,7 @@ export class SchemaObjectFactory { schemas ); } + if (isString(typeRef)) { if (isEnumMetadata(metadata)) { return this.createEnumSchemaType(key, metadata, schemas);