diff --git a/demo/openapi.yaml b/demo/openapi.yaml
index 74c16b70f2..e486189008 100644
--- a/demo/openapi.yaml
+++ b/demo/openapi.yaml
@@ -1,4 +1,4 @@
-openapi: 3.0.0
+openapi: 3.1.0
servers:
- url: //petstore.swagger.io/v2
description: Default server
@@ -42,6 +42,7 @@ info:
version: 1.0.0
title: Swagger Petstore
+ summary: My lovely API
termsOfService: 'http://swagger.io/terms/'
contact:
name: API Support
@@ -53,6 +54,7 @@ info:
license:
name: Apache 2.0
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
+ identifier: Apache 2.0
externalDocs:
description: Find out how to create Github repo for your OpenAPI spec.
url: 'https://github.com/Rebilly/generator-openapi-repo'
@@ -893,6 +895,38 @@ paths:
default:
description: successful operation
components:
+ pathItems:
+ catsWebhook:
+ put:
+ summary: Get a cat details after update
+ description: Get a cat details after update
+ operationId: updatedCat
+ tags:
+ - pet
+ requestBody:
+ description: Information about cat in the system
+ content:
+ multipart/form-data:
+ schema:
+ $ref: "#/components/schemas/Cat"
+ responses:
+ '200':
+ description: update Cat details
+ post:
+ summary: Create new cat
+ description: Info about new cat
+ operationId: createdCat
+ tags:
+ - pet
+ requestBody:
+ description: Information about cat in the system
+ content:
+ multipart/form-data:
+ schema:
+ $ref: "#/components/schemas/Cat"
+ responses:
+ '200':
+ description: create Cat details
schemas:
ApiResponse:
type: object
@@ -1040,7 +1074,8 @@ components:
example: Guru
photoUrls:
description: The list of URL to a cute photos featuring pet
- type: array
+ type: [string, integer, 'null', array]
+ minItems: 1
maxItems: 20
xml:
name: photoUrl
@@ -1054,7 +1089,8 @@ components:
tags:
description: Tags attached to the pet
type: array
- minItems: 1
+ exclusiveMaximum: 100
+ exclusiveMinimum: 0
xml:
name: tag
wrapped: true
@@ -1067,6 +1103,7 @@ components:
- available
- pending
- sold
+ default: pending
petType:
description: Type of a pet
type: string
@@ -1187,13 +1224,13 @@ components:
shipDate: '2018-10-19T16:46:45Z'
status: placed
complete: false
-x-webhooks:
+webhooks:
newPet:
post:
summary: New pet
description: Information about a new pet in the systems
operationId: newPet
- tags:
+ tags:
- pet
requestBody:
content:
@@ -1202,4 +1239,8 @@ x-webhooks:
$ref: "#/components/schemas/Pet"
responses:
"200":
- description: Return a 200 status to indicate that the data was received successfully
\ No newline at end of file
+ description: Return a 200 status to indicate that the data was received successfully
+ myWebhook:
+ $ref: '#/components/pathItems/catsWebhook'
+ description: Overriding description
+ summary: Overriding summary
\ No newline at end of file
diff --git a/e2e/integration/menu.e2e.ts b/e2e/integration/menu.e2e.ts
index e1b053d125..41ecd79cea 100644
--- a/e2e/integration/menu.e2e.ts
+++ b/e2e/integration/menu.e2e.ts
@@ -6,7 +6,7 @@ describe('Menu', () => {
it('should have valid items count', () => {
cy.get('.menu-content')
.find('li')
- .should('have.length', 34);
+ .should('have.length', 36);
});
it('should sync active menu items while scroll', () => {
diff --git a/src/components/Fields/FieldDetails.tsx b/src/components/Fields/FieldDetails.tsx
index be102622ca..9ac6cea235 100644
--- a/src/components/Fields/FieldDetails.tsx
+++ b/src/components/Fields/FieldDetails.tsx
@@ -110,7 +110,7 @@ export class FieldDetails extends React.PureComponent
)}
{(renderDiscriminatorSwitch && renderDiscriminatorSwitch(this.props)) || null}
- {field.const && () || null}
+ {field.const && () || null}
);
}
diff --git a/src/services/MenuBuilder.ts b/src/services/MenuBuilder.ts
index 7a750d65d8..7322dab00d 100644
--- a/src/services/MenuBuilder.ts
+++ b/src/services/MenuBuilder.ts
@@ -6,7 +6,6 @@ import {
Referenced,
OpenAPIServer,
OpenAPIPaths,
- OpenAPIPath,
} from '../types';
import {
isOperationName,
@@ -235,12 +234,11 @@ export class MenuBuilder {
for (const pathName of Object.keys(paths)) {
const path = paths[pathName];
const operations = Object.keys(path).filter(isOperationName);
- for (let operationName of operations) {
- let operationInfo = path[operationName];
+ for (const operationName of operations) {
+ const operationInfo = path[operationName];
if (path.$ref) {
- const resolvedPath = parser.deref(path || {})
- operationName = Object.keys(resolvedPath)[0]
- operationInfo = resolvedPath[operationName]
+ const resolvedPaths = parser.deref(path as OpenAPIPaths);
+ getTags(parser, { [operationName]: resolvedPaths }, isWebhook);
}
let operationTags = operationInfo?.tags;
diff --git a/src/services/__tests__/fixtures/3.1/pathItems.json b/src/services/__tests__/fixtures/3.1/pathItems.json
new file mode 100644
index 0000000000..87888a1b91
--- /dev/null
+++ b/src/services/__tests__/fixtures/3.1/pathItems.json
@@ -0,0 +1,66 @@
+{
+ "openapi": "3.1.0",
+ "info": {
+ "version": "1.0.0",
+ "title": "Swagger Petstore"
+ },
+ "webhooks": {
+ "myWebhook": {
+ "$ref": "#/components/pathItems/catsWebhook",
+ "description": "Overriding description",
+ "summary": "Overriding summary"
+ }
+ },
+ "components": {
+ "pathItems": {
+ "catsWebhook": {
+ "put": {
+ "summary": "Get a cat details after update",
+ "description": "Get a cat details after update",
+ "operationId": "updatedCat",
+ "tags": [
+ "pet"
+ ],
+ "requestBody": {
+ "description": "Information about cat in the system",
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "update Cat details"
+ }
+ }
+ },
+ "post": {
+ "summary": "Create new cat",
+ "description": "Info about new cat",
+ "operationId": "createdCat",
+ "tags": [
+ "pet"
+ ],
+ "requestBody": {
+ "description": "Information about cat in the system",
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Pet"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "create Cat details"
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/services/__tests__/models/ApiInfo.test.ts b/src/services/__tests__/models/ApiInfo.test.ts
index 457937ecfd..5db4252751 100644
--- a/src/services/__tests__/models/ApiInfo.test.ts
+++ b/src/services/__tests__/models/ApiInfo.test.ts
@@ -46,5 +46,21 @@ describe('Models', () => {
const info = new ApiInfoModel(parser);
expect(info.summary).toEqual('Test summary\nsome text\n## Heading\n test');
});
+
+ test('should correctly populate license identifier', () => {
+ parser.spec = {
+ openapi: '3.1.0',
+ info: {
+ license: {
+ name: 'MIT',
+ identifier: 'MIT',
+ url: 'https://opensource.org/licenses/MIT'
+ }
+ },
+ } as any;
+
+ const { license = { identifier: null } } = new ApiInfoModel(parser);
+ expect(license.identifier).toEqual('MIT');
+ });
});
});
diff --git a/src/services/__tests__/models/MenuBuilder.test.ts b/src/services/__tests__/models/MenuBuilder.test.ts
new file mode 100644
index 0000000000..a6ab4776c7
--- /dev/null
+++ b/src/services/__tests__/models/MenuBuilder.test.ts
@@ -0,0 +1,25 @@
+/* eslint-disable @typescript-eslint/no-var-requires */
+import { MenuBuilder } from '../../MenuBuilder';
+import { OpenAPIParser } from '../../OpenAPIParser';
+
+import { RedocNormalizedOptions } from '../../RedocNormalizedOptions';
+
+const opts = new RedocNormalizedOptions({});
+
+describe('Models', () => {
+ describe('MenuBuilder', () => {
+ let parser;
+
+ test('discriminator with one field', () => {
+ const spec = require('../fixtures/3.1/pathItems.json');
+ parser = new OpenAPIParser(spec, undefined, opts);
+ const contentItems = MenuBuilder.buildStructure(parser, opts);
+ expect(contentItems).toHaveLength(2);
+ expect(contentItems[0].items).toHaveLength(2);
+ expect(contentItems[0].id).toEqual('tag/pet');
+ expect(contentItems[0].name).toEqual('pet');
+ expect(contentItems[0].type).toEqual('tag');
+
+ });
+ });
+});
diff --git a/src/services/models/Webhook.ts b/src/services/models/Webhook.ts
index a1be7d3911..5512293518 100644
--- a/src/services/models/Webhook.ts
+++ b/src/services/models/Webhook.ts
@@ -14,16 +14,18 @@ export class WebhookModel {
) {
const webhooks = parser.deref(infoOrRef || {});
parser.exitRef(infoOrRef);
+ this.initWebhooks(parser, webhooks, options);
+ }
+ initWebhooks(parser: OpenAPIParser, webhooks: OpenAPIPath, options: RedocNormalizedOptions) {
for (const webhookName of Object.keys(webhooks)) {
const webhook = webhooks[webhookName];
const operations = Object.keys(webhook).filter(isOperationName);
- for (let operationName of operations) {
- let operationInfo = webhook[operationName];
+ for (const operationName of operations) {
+ const operationInfo = webhook[operationName];
if (webhook.$ref) {
const resolvedWebhook = parser.deref(webhook || {});
- operationName = Object.keys(resolvedWebhook)[0];
- operationInfo = resolvedWebhook[operationName];
+ this.initWebhooks(parser, { [operationName]: resolvedWebhook }, options);
}
if (!operationInfo) continue;
diff --git a/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap b/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap
index e7c967e6e8..ebf6792ded 100644
--- a/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap
+++ b/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap
@@ -13,6 +13,56 @@ Object {
},
},
},
+ "pathItems": Object {
+ "catsWebhook": Object {
+ "post": Object {
+ "description": "Info about new cat",
+ "operationId": "createdCat",
+ "requestBody": Object {
+ "content": Object {
+ "multipart/form-data": Object {
+ "schema": Object {
+ "$ref": "#/components/schemas/Cat",
+ },
+ },
+ },
+ "description": "Information about cat in the system",
+ },
+ "responses": Object {
+ "200": Object {
+ "description": "create Cat details",
+ },
+ },
+ "summary": "Create new cat",
+ "tags": Array [
+ "pet",
+ ],
+ },
+ "put": Object {
+ "description": "Get a cat details after update",
+ "operationId": "updatedCat",
+ "requestBody": Object {
+ "content": Object {
+ "multipart/form-data": Object {
+ "schema": Object {
+ "$ref": "#/components/schemas/Cat",
+ },
+ },
+ },
+ "description": "Information about cat in the system",
+ },
+ "responses": Object {
+ "200": Object {
+ "description": "update Cat details",
+ },
+ },
+ "summary": "Get a cat details after update",
+ "tags": Array [
+ "pet",
+ ],
+ },
+ },
+ },
"requestBodies": Object {
"Pet": Object {
"content": Object {
@@ -292,13 +342,20 @@ Object {
"type": "string",
},
"maxItems": 20,
- "type": "array",
+ "minItems": 1,
+ "type": Array [
+ "string",
+ "integer",
+ "null",
+ "array",
+ ],
"xml": Object {
"name": "photoUrl",
"wrapped": true,
},
},
"status": Object {
+ "default": "pending",
"description": "Pet status in the store",
"enum": Array [
"available",
@@ -309,10 +366,11 @@ Object {
},
"tags": Object {
"description": "Tags attached to the pet",
+ "exclusiveMaximum": 100,
+ "exclusiveMinimum": 0,
"items": Object {
"$ref": "#/components/schemas/Tag",
},
- "minItems": 1,
"type": "array",
"xml": Object {
"name": "tag",
@@ -485,9 +543,11 @@ and standard method from web, mobile and desktop applications.
",
"license": Object {
+ "identifier": "Apache 2.0",
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html",
},
+ "summary": "My lovely API",
"termsOfService": "http://swagger.io/terms/",
"title": "Swagger Petstore",
"version": "1.0.0",
@@ -496,7 +556,7 @@ and standard method from web, mobile and desktop applications.
"url": "https://redocly.github.io/redoc/petstore-logo.png",
},
},
- "openapi": "3.0.0",
+ "openapi": "3.1.0",
"paths": Object {
"/pet": Object {
"parameters": Array [
@@ -1745,29 +1805,12 @@ culpa qui officia deserunt mollit anim id est laborum.
"x-displayName": "The Order Model",
},
],
- "x-tagGroups": Array [
- Object {
- "name": "General",
- "tags": Array [
- "pet",
- "store",
- ],
- },
- Object {
- "name": "User Management",
- "tags": Array [
- "user",
- ],
+ "webhooks": Object {
+ "myWebhook": Object {
+ "$ref": "#/components/pathItems/catsWebhook",
+ "description": "Overriding description",
+ "summary": "Overriding summary",
},
- Object {
- "name": "Models",
- "tags": Array [
- "pet_model",
- "store_model",
- ],
- },
- ],
- "x-webhooks": Object {
"newPet": Object {
"post": Object {
"description": "Information about a new pet in the systems",
@@ -1793,6 +1836,28 @@ culpa qui officia deserunt mollit anim id est laborum.
},
},
},
+ "x-tagGroups": Array [
+ Object {
+ "name": "General",
+ "tags": Array [
+ "pet",
+ "store",
+ ],
+ },
+ Object {
+ "name": "User Management",
+ "tags": Array [
+ "user",
+ ],
+ },
+ Object {
+ "name": "Models",
+ "tags": Array [
+ "pet_model",
+ "store_model",
+ ],
+ },
+ ],
}
`;