From 532c30e88c4005fd16a4b5f0c6a451cbbbe83f5e Mon Sep 17 00:00:00 2001 From: Alex Varchuk Date: Fri, 28 May 2021 12:23:10 +0300 Subject: [PATCH] fix: improve code after review --- demo/index.tsx | 2 +- src/components/ApiInfo/ApiInfo.tsx | 2 +- src/services/models/Schema.ts | 13 +++++--- src/utils/__tests__/openapi.test.ts | 50 +++++++++++++++++++++++++++-- src/utils/openapi.ts | 28 ++++++++-------- 5 files changed, 71 insertions(+), 24 deletions(-) diff --git a/demo/index.tsx b/demo/index.tsx index e5e48c00..10abdd9c 100644 --- a/demo/index.tsx +++ b/demo/index.tsx @@ -9,7 +9,7 @@ const DEFAULT_SPEC = 'openapi.yaml'; const NEW_VERSION_SPEC = 'openapi-3-1.yaml'; const demos = [ - { value: NEW_VERSION_SPEC, label: 'OpenApi 3.1' }, + { value: NEW_VERSION_SPEC, label: 'Petstore OpenAPI 3.1' }, { value: 'https://api.apis.guru/v2/specs/instagram.com/1.0.0/swagger.yaml', label: 'Instagram' }, { value: 'https://api.apis.guru/v2/specs/googleapis.com/calendar/v3/openapi.yaml', diff --git a/src/components/ApiInfo/ApiInfo.tsx b/src/components/ApiInfo/ApiInfo.tsx index 26819db0..ae4b4b20 100644 --- a/src/components/ApiInfo/ApiInfo.tsx +++ b/src/components/ApiInfo/ApiInfo.tsx @@ -100,8 +100,8 @@ export class ApiInfo extends React.Component { )) || null} - + {externalDocs && } diff --git a/src/services/models/Schema.ts b/src/services/models/Schema.ts index 33d9f650..4d8a9665 100644 --- a/src/services/models/Schema.ts +++ b/src/services/models/Schema.ts @@ -105,7 +105,7 @@ export class SchemaModel { this.title = schema.title || (isNamedDefinition(this.pointer) && JsonPointer.baseName(this.pointer)) || ''; this.description = schema.description || ''; - this.type = (Array.isArray(schema.type) && schema.type) || (schema.type || detectType(schema)); + this.type = schema.type || detectType(schema); this.format = schema.format; this.enum = schema.enum || []; this.example = schema.example; @@ -122,11 +122,14 @@ export class SchemaModel { this.const = schema.const || ''; if (!!schema.nullable) { - if (Array.isArray(this.type)) this.type.push('null'); - else this.type = [this.type, 'null']; + if (Array.isArray(this.type) && !this.type.includes('null')) { + this.type = [...this.type, 'null']; + } } - this.displayType = Array.isArray(this.type) ? this.type.join(' or ') : this.type; + this.displayType = Array.isArray(this.type) + ? this.type.map(item => item === null ? 'null' : item).join(' or ') + : this.type; if (this.isCircular) { return; @@ -193,7 +196,7 @@ export class SchemaModel { const title = isNamedDefinition(variant.$ref) && !merged.title ? JsonPointer.baseName(variant.$ref) - : merged.title; + : (merged.const && JSON.stringify(merged.const)) || merged.title; const schema = new SchemaModel( parser, diff --git a/src/utils/__tests__/openapi.test.ts b/src/utils/__tests__/openapi.test.ts index 2045c49e..670ac42c 100644 --- a/src/utils/__tests__/openapi.test.ts +++ b/src/utils/__tests__/openapi.test.ts @@ -174,10 +174,56 @@ describe('Utils', () => { expect(isPrimitiveType(schema)).toEqual(false); }); - it('Should return false for array of strings', () => { + it('should return true for array contains object and schema hasn\'t properties', () => { const schema = { type: ['object', 'string'], }; + expect(isPrimitiveType(schema)).toEqual(true); + }); + + it('should return false for array contains object and schema has properties', () => { + const schema = { + type: ['object', 'string'], + properties: { + a: { + type: 'string', + }, + }, + }; + expect(isPrimitiveType(schema)).toEqual(false); + }); + + it('should return false for array contains array type and schema has items', () => { + const schema = { + type: ['array'], + items: { + type: 'object', + additionalProperties: true, + }, + }; + expect(isPrimitiveType(schema)).toEqual(false); + }); + + it('should return false for array contains object and array types and schema has items', () => { + const schema = { + type: ['array', 'object'], + items: { + type: 'object', + additionalProperties: true, + }, + }; + expect(isPrimitiveType(schema)).toEqual(false); + }); + + it('should return false for array contains object and array types and schema has properties', () => { + const schema = { + type: ['array', 'object'], + properties: { + a: { + type: 'string', + }, + }, + }; expect(isPrimitiveType(schema)).toEqual(false); }); @@ -185,7 +231,7 @@ describe('Utils', () => { const schema = { type: ['object', 'string', 'null'], }; - expect(isPrimitiveType(schema)).toEqual(false); + expect(isPrimitiveType(schema)).toEqual(true); }); it('Should return false for array with non-empty objects', () => { diff --git a/src/utils/openapi.ts b/src/utils/openapi.ts index 37dba679..f6d80f31 100644 --- a/src/utils/openapi.ts +++ b/src/utils/openapi.ts @@ -69,7 +69,7 @@ export function getOperationSummary(operation: ExtendedOpenAPIOperation): string operation.operationId || (operation.description && operation.description.substring(0, 50)) || operation.pathName || - '' + '' ); } @@ -116,22 +116,20 @@ export function isPrimitiveType(schema: OpenAPISchema, type: string | string[] | return false; } - if (type === 'object') { - return schema.properties !== undefined + let isPrimitive = true; + const isArray = Array.isArray(type); + + if (type === 'object' || (isArray && type?.includes('object'))) { + isPrimitive = schema.properties !== undefined ? Object.keys(schema.properties).length === 0 : schema.additionalProperties === undefined; } - if (type === 'array') { - if (schema.items === undefined) { - return true; - } - return false; + if (schema.items !== undefined && (type === 'array' || (isArray && type?.includes('array')))) { + isPrimitive = false; } - if (Array.isArray(type)) return false - - return true; + return isPrimitive; } export function isJsonLike(contentType: string): boolean { @@ -589,10 +587,10 @@ export function setSecuritySchemePrefix(prefix: string) { } export const shortenHTTPVerb = verb => - ({ - delete: 'del', - options: 'opts', - }[verb] || verb); +({ + delete: 'del', + options: 'opts', +}[verb] || verb); export function isRedocExtension(key: string): boolean { const redocExtensions = {