diff --git a/src/services/OpenAPIParser.ts b/src/services/OpenAPIParser.ts index a28dc837..08142d58 100644 --- a/src/services/OpenAPIParser.ts +++ b/src/services/OpenAPIParser.ts @@ -132,11 +132,21 @@ export class OpenAPIParser { if ( mergeAsAllOf && keys.some( - k => !['description', 'title', 'externalDocs', 'x-refsStack', 'x-parentRefs'].includes(k), + k => + ![ + 'description', + 'title', + 'externalDocs', + 'x-refsStack', + 'x-parentRefs', + 'readOnly', + 'writeOnly', + ].includes(k), ) ) { + const { description, title, readOnly, writeOnly, ...restSchema } = rest as OpenAPISchema; return { - allOf: [resolved, rest], + allOf: [{ description, title, readOnly, writeOnly }, resolved, restSchema], } as T; } else { // small optimization diff --git a/src/services/__tests__/models/Response.test.ts b/src/services/__tests__/models/Response.test.ts index 26ec21b7..67f79003 100644 --- a/src/services/__tests__/models/Response.test.ts +++ b/src/services/__tests__/models/Response.test.ts @@ -1,3 +1,6 @@ +import { parseYaml } from '@redocly/openapi-core'; +import { outdent } from 'outdent'; + import { ResponseModel } from '../../models/Response'; import { OpenAPIParser } from '../../OpenAPIParser'; import { RedocNormalizedOptions } from '../../RedocNormalizedOptions'; @@ -53,5 +56,81 @@ describe('Models', () => { expect(Object.keys(resp.extensions).length).toEqual(1); expect(resp.extensions['x-example']).toEqual({ a: 1 }); }); + + test('should get correct sibling in responses for openapi 3.1', () => { + const spec = parseYaml(outdent` + openapi: 3.1.0 + paths: + /test: + get: + operationId: test + responses: + '200': + description: Overridden description + $ref: "#/components/responses/Successful" + components: + responses: + Successful: + description: successful operation + content: + application/json: + schema: + type: object + properties: + successful: + type: boolean + `) as any; + + parser = new OpenAPIParser(spec, undefined, opts); + const code = '200'; + const responseModel = new ResponseModel({ + parser: parser, + code: code, + defaultAsError: false, + infoOrRef: spec.paths['/test'].get.responses[code], + options: opts, + isEvent: false, + }); + + expect(responseModel.summary).toBe('Overridden description'); + }); + + test('should not override description in responses for openapi 3.0', () => { + const spec = parseYaml(outdent` + openapi: 3.0.0 + paths: + /test: + get: + operationId: test + responses: + '200': + description: Overridden description + $ref: "#/components/responses/Successful" + components: + responses: + Successful: + description: successful operation + content: + application/json: + schema: + type: object + properties: + successful: + type: boolean + `) as any; + + parser = new OpenAPIParser(spec, undefined, opts); + const code = '200'; + const responseModel = new ResponseModel({ + parser: parser, + code: code, + defaultAsError: false, + infoOrRef: spec.paths['/test'].get.responses[code], + options: opts, + isEvent: false, + }); + + expect(responseModel.summary).toBe('successful operation'); + }); }); }); diff --git a/src/services/__tests__/models/Schema.test.ts b/src/services/__tests__/models/Schema.test.ts index cf3ddaa1..558c2c1b 100644 --- a/src/services/__tests__/models/Schema.test.ts +++ b/src/services/__tests__/models/Schema.test.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-var-requires */ import { parseYaml } from '@redocly/openapi-core'; import { outdent } from 'outdent'; +import { MediaTypeModel } from '../../models'; import { SchemaModel } from '../../models/Schema'; import { OpenAPIParser } from '../../OpenAPIParser'; import { RedocNormalizedOptions } from '../../RedocNormalizedOptions'; @@ -481,5 +482,85 @@ describe('Models', () => { `); }); }); + + test('should get correct sibling inside schema type for openapi 3.1', () => { + const spec = parseYaml(outdent` + openapi: 3.1.0 + paths: + /test: + get: + operationId: test + responses: + '200': + content: + application/json: + schema: + type: object + properties: + testAttr: + description: Overridden description + type: string + $ref: '#/components/schemas/Test' + components: + schemas: + Test: + type: object + description: Refed description + `) as any; + + parser = new OpenAPIParser(spec, undefined, opts); + const name = 'application/json'; + const mediaType = new MediaTypeModel( + parser, + name, + true, + spec.paths['/test'].get.responses['200'].content[name], + opts, + ); + + expect(printSchema(mediaType?.schema as any)).toMatchInlineSnapshot( + `"testAttr: (Overridden description)"`, + ); + }); + + test('should not override schema in openapi 3.0', () => { + const spec = parseYaml(outdent` + openapi: 3.0.0 + paths: + /test: + get: + operationId: test + responses: + '200': + content: + application/json: + schema: + type: object + properties: + testAttr: + type: string + description: Overridden description + $ref: '#/components/schemas/Test' + components: + schemas: + Test: + type: object + description: Refed description + `) as any; + + parser = new OpenAPIParser(spec, undefined, opts); + const name = 'application/json'; + const mediaType = new MediaTypeModel( + parser, + name, + true, + spec.paths['/test'].get.responses['200'].content[name], + opts, + ); + + expect(printSchema(mediaType?.schema as any)).toMatchInlineSnapshot( + `"testAttr: (Refed description)"`, + ); + }); }); });