From 16d1ea9ab04b49ef78a7eb28881e60caaea096b0 Mon Sep 17 00:00:00 2001 From: Artur Kraft Date: Sat, 9 Mar 2024 16:41:37 +0100 Subject: [PATCH 1/4] add params and queries to routes --- test/explorer/swagger-explorer.spec.ts | 56 +++++++++++++------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/test/explorer/swagger-explorer.spec.ts b/test/explorer/swagger-explorer.spec.ts index 2870f7923..123e1b90d 100644 --- a/test/explorer/swagger-explorer.spec.ts +++ b/test/explorer/swagger-explorer.spec.ts @@ -938,7 +938,7 @@ describe('SwaggerExplorer', () => { }) @ApiQuery({ name: 'order', enum: QueryEnum }) @ApiQuery({ name: 'page', enum: ['d', 'e', 'f'], isArray: true }) - find(): Promise { + find(@Param('objectId') objectId: ParamEnum): Promise { return Promise.resolve([]); } } @@ -952,7 +952,7 @@ describe('SwaggerExplorer', () => { }) @ApiQuery({ name: 'order', enum: QueryEnum }) @ApiQuery({ name: 'page', enum: ['d', 'e', 'f'] }) - find(): Promise { + find(@Param('objectId') objectId: ParamEnum, @Query('order') order: QueryEnum, @Query('page') page: 'd' | 'e' | 'f'): Promise { return Promise.resolve([]); } } @@ -972,7 +972,7 @@ describe('SwaggerExplorer', () => { enumName: 'QueryEnum', isArray: true }) - findBar(): Promise { + findBar(@Param('objectId') objectId: ParamEnum, @Query('order') order: QueryEnum, @Query('page') page: QueryEnum[]): Promise { return Promise.resolve(null); } } @@ -985,7 +985,7 @@ describe('SwaggerExplorer', () => { enum: [1, 2, 3], enumName: 'NumberEnum' }) - findBar(): Promise { + findBar(@Param('objectId') objectId: number): Promise { return Promise.resolve(null); } } @@ -1010,6 +1010,15 @@ describe('SwaggerExplorer', () => { '/globalPrefix/v3/modulePath/foos/{objectId}' ); expect(routes[0].root!.parameters).toEqual([ + { + in: 'path', + name: 'objectId', + required: true, + schema: { + type: 'string', + enum: ['a', 'b', 'c'] + } + }, { in: 'query', name: 'page', @@ -1030,15 +1039,6 @@ describe('SwaggerExplorer', () => { type: 'number', enum: [1, 2, 3] } - }, - { - in: 'path', - name: 'objectId', - required: true, - schema: { - type: 'string', - enum: ['a', 'b', 'c'] - } } ]); }); @@ -1056,12 +1056,12 @@ describe('SwaggerExplorer', () => { expect(routes[0].root!.parameters).toEqual([ { - in: 'query', - name: 'page', + in: 'path', + name: 'objectId', required: true, schema: { type: 'string', - enum: ['d', 'e', 'f'] + enum: ['a', 'b', 'c'] } }, { @@ -1074,12 +1074,12 @@ describe('SwaggerExplorer', () => { } }, { - in: 'path', - name: 'objectId', + in: 'query', + name: 'page', required: true, schema: { type: 'string', - enum: ['a', 'b', 'c'] + enum: ['d', 'e', 'f'] } } ]); @@ -1099,14 +1099,11 @@ describe('SwaggerExplorer', () => { expect(routes[0].root!.parameters).toEqual([ { - in: 'query', - name: 'page', + in: 'path', + name: 'objectId', required: true, schema: { - type: 'array', - items: { - $ref: '#/components/schemas/QueryEnum' - } + $ref: '#/components/schemas/ParamEnum' } }, { @@ -1118,11 +1115,14 @@ describe('SwaggerExplorer', () => { } }, { - in: 'path', - name: 'objectId', + in: 'query', + name: 'page', required: true, schema: { - $ref: '#/components/schemas/ParamEnum' + type: 'array', + items: { + $ref: '#/components/schemas/QueryEnum' + } } } ]); From 7230915e627a7a96110ec3dd8ee6d84bc70bb54f Mon Sep 17 00:00:00 2001 From: Artur Kraft Date: Sat, 9 Mar 2024 16:41:50 +0100 Subject: [PATCH 2/4] if enum is of type array, use the item type --- lib/services/schema-object-factory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/schema-object-factory.ts b/lib/services/schema-object-factory.ts index 8c72bd989..2abd16eca 100644 --- a/lib/services/schema-object-factory.ts +++ b/lib/services/schema-object-factory.ts @@ -273,7 +273,7 @@ export class SchemaObjectFactory { : undefined; schemas[enumName] = { - type: param.schema?.['type'] ?? 'string', + type: (param.isArray ? param.schema?.['items']?.['type'] : param.schema?.['type']) ?? 'string', enum: _enum }; } From 11f6ac584040257dc2e208ed5911ea57e3a47eed Mon Sep 17 00:00:00 2001 From: Artur Kraft Date: Sat, 9 Mar 2024 16:42:09 +0100 Subject: [PATCH 3/4] add tests for enum schema types --- test/services/schema-object-factory.spec.ts | 43 ++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/test/services/schema-object-factory.spec.ts b/test/services/schema-object-factory.spec.ts index 2a7546734..d1923400f 100644 --- a/test/services/schema-object-factory.spec.ts +++ b/test/services/schema-object-factory.spec.ts @@ -1,9 +1,10 @@ import { ApiExtension, ApiProperty } from '../../lib/decorators'; -import { SchemasObject } from '../../lib/interfaces/open-api-spec.interface'; +import { BaseParameterObject, SchemasObject } from '../../lib/interfaces/open-api-spec.interface'; import { ModelPropertiesAccessor } from '../../lib/services/model-properties-accessor'; import { SchemaObjectFactory } from '../../lib/services/schema-object-factory'; import { SwaggerTypesMapper } from '../../lib/services/swagger-types-mapper'; import { CreateUserDto } from './fixtures/create-user.dto'; +import { ParamWithTypeMetadata } from '../../lib/services/parameter-metadata-accessor'; describe('SchemaObjectFactory', () => { let modelPropertiesAccessor: ModelPropertiesAccessor; @@ -328,4 +329,44 @@ describe('SchemaObjectFactory', () => { expect(schemas).toEqual({ MyEnum: { enum: [1, 2, 3], type: 'number' } }); }); }); + + describe('createEnumParam', () => { + it('should create an enum schema definition', () => { + const params: ParamWithTypeMetadata & BaseParameterObject = { + required: true, + isArray: false, + enumName: 'MyEnum', + enum: ['a', 'b', 'c'] + } + const schemas = {}; + schemaObjectFactory.createEnumParam(params, schemas) + + expect(schemas['MyEnum']).toEqual({ + enum: ['a', 'b', 'c'], + type: 'string' + }) + }) + + it('should create an enum schema definition for an array', () => { + const params: ParamWithTypeMetadata & BaseParameterObject = { + required: true, + isArray: true, + enumName: 'MyEnum', + schema: { + type: 'array', + items: { + type: 'string', + enum: ['a', 'b', 'c'] + } + } + } + const schemas = {}; + schemaObjectFactory.createEnumParam(params, schemas) + + expect(schemas['MyEnum']).toEqual({ + enum: ['a', 'b', 'c'], + type: 'string' + }) + }) + }) }); From 5ab17a90bb5ae70fe03344ec93d0b1bd6eec2e42 Mon Sep 17 00:00:00 2001 From: Artur Kraft Date: Sat, 9 Mar 2024 16:43:23 +0100 Subject: [PATCH 4/4] prettier --- lib/services/schema-object-factory.ts | 54 +++++++++++++-------- test/services/schema-object-factory.spec.ts | 23 +++++---- 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/lib/services/schema-object-factory.ts b/lib/services/schema-object-factory.ts index 2abd16eca..a5bb2be78 100644 --- a/lib/services/schema-object-factory.ts +++ b/lib/services/schema-object-factory.ts @@ -167,14 +167,24 @@ export class SchemaObjectFactory { const schemaCombinators = ['oneOf', 'anyOf', 'allOf']; let keyOfCombinators = ''; - if (schemaCombinators.some((_key) => { keyOfCombinators = _key; return _key in property; })) { - if (((property as SchemaObjectMetadata)?.type === 'array' || (property as SchemaObjectMetadata).isArray) && keyOfCombinators) { - (property as SchemaObjectMetadata).items = {}; - (property as SchemaObjectMetadata).items[keyOfCombinators] = property[keyOfCombinators]; - delete property[keyOfCombinators]; - } else { - delete (property as SchemaObjectMetadata).type; - } + if ( + schemaCombinators.some((_key) => { + keyOfCombinators = _key; + return _key in property; + }) + ) { + if ( + ((property as SchemaObjectMetadata)?.type === 'array' || + (property as SchemaObjectMetadata).isArray) && + keyOfCombinators + ) { + (property as SchemaObjectMetadata).items = {}; + (property as SchemaObjectMetadata).items[keyOfCombinators] = + property[keyOfCombinators]; + delete property[keyOfCombinators]; + } else { + delete (property as SchemaObjectMetadata).type; + } } return property as ParameterObject; }); @@ -203,7 +213,8 @@ export class SchemaObjectFactory { if (!propertiesWithType) { return ''; } - const extensionProperties = Reflect.getMetadata(DECORATORS.API_EXTENSION, type) || {}; + const extensionProperties = + Reflect.getMetadata(DECORATORS.API_EXTENSION, type) || {}; const typeDefinition: SchemaObject = { type: 'object', properties: mapValues(keyBy(propertiesWithType, 'name'), (property) => @@ -273,7 +284,10 @@ export class SchemaObjectFactory { : undefined; schemas[enumName] = { - type: (param.isArray ? param.schema?.['items']?.['type'] : param.schema?.['type']) ?? 'string', + type: + (param.isArray + ? param.schema?.['items']?.['type'] + : param.schema?.['type']) ?? 'string', enum: _enum }; } @@ -301,15 +315,17 @@ export class SchemaObjectFactory { const $ref = getSchemaPath(enumName); // 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'; + 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, diff --git a/test/services/schema-object-factory.spec.ts b/test/services/schema-object-factory.spec.ts index d1923400f..3f4514bcb 100644 --- a/test/services/schema-object-factory.spec.ts +++ b/test/services/schema-object-factory.spec.ts @@ -1,5 +1,8 @@ import { ApiExtension, ApiProperty } from '../../lib/decorators'; -import { BaseParameterObject, SchemasObject } from '../../lib/interfaces/open-api-spec.interface'; +import { + BaseParameterObject, + SchemasObject +} from '../../lib/interfaces/open-api-spec.interface'; import { ModelPropertiesAccessor } from '../../lib/services/model-properties-accessor'; import { SchemaObjectFactory } from '../../lib/services/schema-object-factory'; import { SwaggerTypesMapper } from '../../lib/services/swagger-types-mapper'; @@ -337,15 +340,15 @@ describe('SchemaObjectFactory', () => { isArray: false, enumName: 'MyEnum', enum: ['a', 'b', 'c'] - } + }; const schemas = {}; - schemaObjectFactory.createEnumParam(params, schemas) + schemaObjectFactory.createEnumParam(params, schemas); expect(schemas['MyEnum']).toEqual({ enum: ['a', 'b', 'c'], type: 'string' - }) - }) + }); + }); it('should create an enum schema definition for an array', () => { const params: ParamWithTypeMetadata & BaseParameterObject = { @@ -359,14 +362,14 @@ describe('SchemaObjectFactory', () => { enum: ['a', 'b', 'c'] } } - } + }; const schemas = {}; - schemaObjectFactory.createEnumParam(params, schemas) + schemaObjectFactory.createEnumParam(params, schemas); expect(schemas['MyEnum']).toEqual({ enum: ['a', 'b', 'c'], type: 'string' - }) - }) - }) + }); + }); + }); });