Skip to content

Commit

Permalink
fix: swagger one of with type (#2640)
Browse files Browse the repository at this point in the history
* fix: swagger one of with type

* fix: base type
  • Loading branch information
czy88840616 authored Jan 11, 2023
1 parent 66b2560 commit 93679ad
Show file tree
Hide file tree
Showing 5 changed files with 273 additions and 7 deletions.
2 changes: 1 addition & 1 deletion packages/swagger/src/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ export interface SchemaObject {
example?: any;
examples?: any[] | Record<string, any>;
deprecated?: boolean;
type?: string;
type?: string | (new (...args) => any) | (() => new (...args) => any);
allOf?: (SchemaObject | ReferenceObject)[];
oneOf?: (SchemaObject | ReferenceObject)[];
anyOf?: (SchemaObject | ReferenceObject)[];
Expand Down
139 changes: 135 additions & 4 deletions packages/swagger/src/swaggerExplorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,117 @@ export class SwaggerExplorer {
}
}
}

protected parseSubPropertyType(metadata: any) {
let typeMeta;
if (metadata?.enum) {
typeMeta = {
type: metadata?.type,
enum: metadata?.enum,
default: metadata?.default,
};

if (metadata?.description) {
typeMeta.description = metadata?.description;
}
return typeMeta;
}

if (metadata?.items?.enum) {
typeMeta = {
type: metadata?.type,
items: metadata?.items,
default: metadata?.default,
};

if (metadata?.description) {
typeMeta.description = metadata?.description;
}
return typeMeta;
}

let isArray = false;
let currentType = parseTypeSchema(metadata?.type);

delete metadata?.type;

if (currentType === 'array') {
isArray = true;
currentType = parseTypeSchema(metadata?.items?.type);

delete metadata?.items.type;
}

if (metadata?.oneOf) {
typeMeta = {
oneOf: [],
};
metadata?.oneOf.forEach((item: any) => {
typeMeta.push(this.parseSubPropertyType(item));
});
delete metadata?.oneOf;
}

if (Types.isClass(currentType)) {
this.parseClzz(currentType);

if (isArray) {
typeMeta = {
type: 'array',
items: {
$ref: '#/components/schemas/' + currentType?.name,
},
};
} else {
typeMeta = {
$ref: '#/components/schemas/' + currentType?.name,
};
}

delete metadata.items;
} else {
if (isArray) {
// 没有配置类型则认为自己配置了 items 内容
if (!currentType) {
if (metadata?.items?.['$ref']) {
metadata.items['$ref'] = parseTypeSchema(metadata.items['$ref']);
}

typeMeta = {
type: 'array',
items: metadata?.items,
};
} else {
typeMeta = {
type: 'array',
items: {
type: convertSchemaType(currentType?.name || currentType),
},
};
}

delete metadata.items;
} else {
typeMeta = {
type: currentType,
format: metadata?.format,
};

// Date 类型支持
if (typeMeta.type === 'Date') {
typeMeta.type = 'string';
if (!typeMeta.format) {
typeMeta.format = 'date';
}
}

delete metadata.format;
}
}

return Object.assign(typeMeta, metadata);
}

/**
* 解析类型的 ApiProperty
* @param clzz
Expand Down Expand Up @@ -689,11 +800,22 @@ export class SwaggerExplorer {

if (currentType === 'array') {
isArray = true;
currentType = metadata?.items?.type;
currentType = parseTypeSchema(metadata?.items?.type);

delete metadata?.items.type;
}

if (metadata?.oneOf) {
tt.properties[key] = {
oneOf: [],
};
metadata?.oneOf.forEach((meta: any) => {
tt.properties[key].oneOf.push(this.parseSubPropertyType(meta));
});
delete metadata?.oneOf;
return;
}

if (Types.isClass(currentType)) {
this.parseClzz(currentType);

Expand Down Expand Up @@ -900,8 +1022,17 @@ function getNotEmptyValue(...args) {
}

function parseTypeSchema(ref) {
if (typeof ref === 'function' && !Types.isClass(ref)) {
ref = ref();
switch (ref) {
case String:
return 'string';
case Number:
return 'number';
case Boolean:
return 'boolean';
default:
if (typeof ref === 'function' && !Types.isClass(ref)) {
ref = ref();
}
return ref;
}
return ref;
}
55 changes: 55 additions & 0 deletions packages/swagger/test/__snapshots__/parser.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,26 @@ exports[`/test/parser.test.ts should fix issue#2286 with array example 1`] = `
}
`;

exports[`/test/parser.test.ts should parse base type 1`] = `
{
"properties": {
"breeds": {
"description": "The name of the Catage",
"example": [
"1",
],
"items": {
"type": "string",
},
"nullable": true,
"type": "array",
"uniqueItems": true,
},
},
"type": "object",
}
`;

exports[`/test/parser.test.ts should parse ref schema with function 1`] = `
{
"properties": {
Expand Down Expand Up @@ -171,6 +191,41 @@ exports[`/test/parser.test.ts should parse type with function 2`] = `
}
`;

exports[`/test/parser.test.ts should test multi-type in property 1`] = `
{
"properties": {
"album": {
"oneOf": [
{
"$ref": "#/components/schemas/Album",
},
{
"items": {
"$ref": "#/components/schemas/Album",
},
"type": "array",
},
],
},
"name": {
"oneOf": [
{
"format": undefined,
"type": "string",
},
{
"items": {
"type": "string",
},
"type": "array",
},
],
},
},
"type": "object",
}
`;

exports[`/test/parser.test.ts should test ref path generate 1`] = `
{
"components": {
Expand Down
57 changes: 56 additions & 1 deletion packages/swagger/test/parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ describe('/test/parser.test.ts', function () {
name: string;

@ApiProperty({
type: Photo
type: Photo,
})
photo: Photo;
}
Expand All @@ -213,4 +213,59 @@ describe('/test/parser.test.ts', function () {
expect(explorer.parseClzz(Photo)).toMatchSnapshot();
expect(explorer.parseClzz(Album)).toMatchSnapshot();
});

it('should test multi-type in property', function () {
class Album {
@ApiProperty()
id: number;

@ApiProperty()
name: string;
}
class Photo {
@ApiProperty({
oneOf: [
{ type: 'string' },
{
type: 'array',
items: {
type: 'string'
}
}
]
})
name: string | string[];

@ApiProperty({
oneOf: [
{ type: Album},
{
type: 'array',
items: {
type: () => Album,
}
}
]
})
album: Album | Album[];
}
const explorer = new CustomSwaggerExplorer();
expect(explorer.parseClzz(Photo)).toMatchSnapshot();
});

it('should parse base type', function () {
class Cat {
@ApiProperty({
type: [String],
example: ['1'],
description: 'The name of the Catage',
nullable: true,
uniqueItems: true,
})
breeds: string[];
}

const explorer = new CustomSwaggerExplorer();
expect(explorer.parseClzz(Cat)).toMatchSnapshot();
});
});
27 changes: 26 additions & 1 deletion packages/validate/test/check.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Validate, Rule, RuleType } from '../src';
import { Validate, Rule, RuleType, getSchema, OmitDto } from '../src';
import { createLightApp, close } from '@midwayjs/mock';
import * as Joi from 'joi';
import * as Valid from '../src';
Expand Down Expand Up @@ -411,4 +411,29 @@ describe('/test/check.test.ts', () => {

await close(app);
});

it('test cascade with extends check', () => {

class SchoolDTO {
@Rule(RuleType.string().required())
name: string;
@Rule(RuleType.string())
address: string;
}

class NewSchoolDTO extends OmitDto(SchoolDTO, ['address']) {}

class UserDTO {
@Rule(RuleType.array().items(getSchema(NewSchoolDTO)))
schoolList: NewSchoolDTO[];
}

const schema = getSchema(UserDTO);
const result = schema.validate({
schoolList: [{
address: 'abc'
}]
});
console.log(result);
})
});

0 comments on commit 93679ad

Please sign in to comment.