mirror of
https://github.com/postmanlabs/openapi-to-postman.git
synced 2022-11-29 22:05:00 +03:00
Merge pull request #585 from postmanlabs/fix/componentsObjectReferenced20
Support root components referenced from external files
This commit is contained in:
@@ -247,7 +247,14 @@ function getTraceFromParentKeyInComponents(nodeContext, tempRef, mainKeys, versi
|
||||
[key, ...parentKeys],
|
||||
nodeTrace = getRootFileTrace(nodeParentsKey),
|
||||
componentKey = createComponentMainKey(tempRef, mainKeys),
|
||||
keyTraceInComponents = getKeyInComponents(nodeTrace, componentKey, version, commonPathFromData);
|
||||
parentNodeKey = nodeContext.parent.key,
|
||||
keyTraceInComponents = getKeyInComponents(
|
||||
nodeTrace,
|
||||
componentKey,
|
||||
version,
|
||||
commonPathFromData,
|
||||
parentNodeKey
|
||||
);
|
||||
return keyTraceInComponents;
|
||||
}
|
||||
|
||||
@@ -518,10 +525,14 @@ function generateComponentsObject (documentContext, rootContent, refTypeResolver
|
||||
* Generates the components object wrapper
|
||||
* @param {object} parsedOasObject The parsed root
|
||||
* @param {string} version - The current version
|
||||
* @param {object} nodesContent - The nodes content
|
||||
* @returns {object} The components object wrapper
|
||||
*/
|
||||
function generateComponentsWrapper(parsedOasObject, version) {
|
||||
let components = {};
|
||||
function generateComponentsWrapper(parsedOasObject, version, nodesContent = {}) {
|
||||
let components = _.isNil(parsedOasObject.components) ?
|
||||
{} :
|
||||
parsedOasObject.components,
|
||||
componentsAreReferenced = components.$ref !== undefined && !_.isEmpty(nodesContent);
|
||||
|
||||
if (isSwagger(version)) {
|
||||
getBundleRulesDataByVersion(version).COMPONENTS_KEYS.forEach((property) => {
|
||||
@@ -531,7 +542,10 @@ function generateComponentsWrapper(parsedOasObject, version) {
|
||||
});
|
||||
}
|
||||
else if (parsedOasObject.hasOwnProperty('components')) {
|
||||
components = parsedOasObject.components;
|
||||
if (componentsAreReferenced) {
|
||||
components = _.merge(parsedOasObject.components, nodesContent[components.$ref]);
|
||||
delete components.$ref;
|
||||
}
|
||||
}
|
||||
|
||||
return components;
|
||||
@@ -604,7 +618,11 @@ module.exports = {
|
||||
rootContextData = algorithm.traverseAndBundle(specRoot, (currentNode) => {
|
||||
return getNodeContentAndReferences(currentNode, allData, specRoot, version, initialMainKeys, commonPathFromData);
|
||||
});
|
||||
components = generateComponentsWrapper(specRoot.parsed.oasObject, version);
|
||||
components = generateComponentsWrapper(
|
||||
specRoot.parsed.oasObject,
|
||||
version,
|
||||
rootContextData.nodeContents
|
||||
);
|
||||
generateComponentsObject(
|
||||
rootContextData,
|
||||
rootContextData.nodeContents[specRoot.fileName],
|
||||
|
||||
@@ -52,9 +52,10 @@ function generateObjectName(filePathName, hash = '') {
|
||||
* @param {string} mainKey - The generated mainKey for the components
|
||||
* @param {string} version - The current spec version
|
||||
* @param {string} commonPathFromData - The common path in the file's paths
|
||||
* @param {string} parentNodeKey - The key from the parent element of the trace
|
||||
* @returns {Array} - the calculated keys in an array representing each nesting property name
|
||||
*/
|
||||
function getKeyInComponents(traceFromParent, mainKey, version, commonPathFromData) {
|
||||
function getKeyInComponents(traceFromParent, mainKey, version, commonPathFromData, parentNodeKey = undefined) {
|
||||
const {
|
||||
CONTAINERS,
|
||||
DEFINITIONS,
|
||||
@@ -70,9 +71,11 @@ function getKeyInComponents(traceFromParent, mainKey, version, commonPathFromDat
|
||||
].reverse(),
|
||||
traceToKey = [],
|
||||
matchFound = false,
|
||||
isRootAndReusableItemsContainer = ROOT_CONTAINERS_KEYS.includes(traceFromParent[0]);
|
||||
hasNotParent = parentNodeKey === undefined,
|
||||
isRootAndReusableItemsContainer = ROOT_CONTAINERS_KEYS.includes(traceFromParent[0]),
|
||||
isAComponentKeyReferenced = COMPONENTS_KEYS.includes(traceFromParent[0]) && hasNotParent;
|
||||
|
||||
if (isRootAndReusableItemsContainer) {
|
||||
if (isRootAndReusableItemsContainer || isAComponentKeyReferenced) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
responses:
|
||||
$ref: './responses.yaml'
|
||||
schemas:
|
||||
$ref: './schemas.yaml'
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "Sample API",
|
||||
"description": "Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.",
|
||||
"version": "0.1.9"
|
||||
},
|
||||
"paths": {
|
||||
"/hello": {
|
||||
"get": {
|
||||
"description": "Returns all pets alesuada ac...",
|
||||
"operationId": "findPets",
|
||||
"responses": {
|
||||
"$ref": "#/components/responses/responseA"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"address": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responseA": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/_schemaA.yaml"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responseB": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fromB": {
|
||||
"type": "string"
|
||||
},
|
||||
"addressFromB": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"_schemaA.yaml": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fromA": {
|
||||
"type": "string"
|
||||
},
|
||||
"addressFromA": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schemaB": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
address:
|
||||
type: string
|
||||
"responseA":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: './schemaA.yaml'
|
||||
"responseB":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
fromB:
|
||||
type: string
|
||||
addressFromB:
|
||||
type: string
|
||||
15
test/data/toBundleExamples/referenced_components/root.yaml
Normal file
15
test/data/toBundleExamples/referenced_components/root.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Sample API
|
||||
description: Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.
|
||||
version: 0.1.9
|
||||
paths:
|
||||
/hello:
|
||||
get:
|
||||
description: Returns all pets alesuada ac...
|
||||
operationId: findPets
|
||||
responses:
|
||||
$ref: '#/components/responses/responseA'
|
||||
|
||||
components:
|
||||
$ref: './components.yaml'
|
||||
@@ -0,0 +1,6 @@
|
||||
type: object
|
||||
properties:
|
||||
fromA:
|
||||
type: string
|
||||
addressFromA:
|
||||
type: string
|
||||
@@ -0,0 +1,2 @@
|
||||
schemaB:
|
||||
type: integer
|
||||
@@ -0,0 +1,22 @@
|
||||
Pet:
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
name:
|
||||
type: string
|
||||
tag:
|
||||
type: string
|
||||
Error:
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
format: int32
|
||||
message:
|
||||
type: string
|
||||
@@ -0,0 +1,141 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"version": "1.0.0",
|
||||
"title": "Swagger Petstore",
|
||||
"description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
|
||||
"termsOfService": "http://swagger.io/terms/",
|
||||
"contact": {
|
||||
"name": "Swagger API Team",
|
||||
"email": "apiteam@swagger.io",
|
||||
"url": "http://swagger.io"
|
||||
},
|
||||
"license": {
|
||||
"name": "Apache 2.0",
|
||||
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"/pets": {
|
||||
"get": {
|
||||
"description": "Returns all pets alesuada ac...",
|
||||
"operationId": "findPets",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "pet response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"required": [
|
||||
"code",
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "unexpected error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"required": [
|
||||
"code",
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"Pet": {
|
||||
"required": [
|
||||
"id",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"tag": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Error": {
|
||||
"required": [
|
||||
"code",
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"type": "oauth2",
|
||||
"authorizationUrl": "http://swagger.io/api/oauth/dialog",
|
||||
"flow": "implicit",
|
||||
"scopes": {
|
||||
"write:pets": "modify pets in your account",
|
||||
"read:pets": "read your pets"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
"x-bx-tag": "authorization",
|
||||
"x-bx-priority": true
|
||||
},
|
||||
{
|
||||
"name": "Bx Sign",
|
||||
"x-bx-tag": "sign_requests"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A simple string response",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "A simple string response from 400 code",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
version: 1.0.0
|
||||
title: Swagger Petstore
|
||||
description: A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification
|
||||
termsOfService: http://swagger.io/terms/
|
||||
contact:
|
||||
name: Swagger API Team
|
||||
email: apiteam@swagger.io
|
||||
url: http://swagger.io
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://www.apache.org/licenses/LICENSE-2.0.html
|
||||
@@ -0,0 +1,31 @@
|
||||
description: Returns all pets alesuada ac...
|
||||
operationId: findPets
|
||||
responses:
|
||||
"200":
|
||||
description: pet response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
format: int32
|
||||
message:
|
||||
type: string
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
format: int32
|
||||
message:
|
||||
type: string
|
||||
@@ -0,0 +1,3 @@
|
||||
/pets:
|
||||
get:
|
||||
"$ref": "./path.yaml"
|
||||
@@ -0,0 +1,8 @@
|
||||
'200':
|
||||
description: A simple string response
|
||||
schema:
|
||||
type: string
|
||||
'400':
|
||||
description: A simple string response from 400 code
|
||||
schema:
|
||||
type: string
|
||||
@@ -0,0 +1,13 @@
|
||||
swagger: '2.0'
|
||||
info:
|
||||
$ref: './info.yaml'
|
||||
paths:
|
||||
"$ref": "./paths/paths.yaml"
|
||||
definitions:
|
||||
$ref: './definitions.yaml'
|
||||
securityDefinitions:
|
||||
$ref: './securitySchemes.yaml'
|
||||
tags:
|
||||
$ref: './tags.yaml'
|
||||
responses:
|
||||
$ref: './responses.yaml'
|
||||
@@ -0,0 +1,6 @@
|
||||
type: oauth2
|
||||
authorizationUrl: http://swagger.io/api/oauth/dialog
|
||||
flow: implicit
|
||||
scopes:
|
||||
write:pets: modify pets in your account
|
||||
read:pets: read your pets
|
||||
@@ -0,0 +1,6 @@
|
||||
- name: Authorization
|
||||
x-bx-tag: authorization
|
||||
x-bx-priority: true
|
||||
|
||||
- name: Bx Sign
|
||||
x-bx-tag: sign_requests
|
||||
@@ -43,6 +43,7 @@ let expect = require('chai').expect,
|
||||
schemaCollisionWRootComponent = path.join(__dirname, BUNDLES_FOLDER + '/schema_collision_w_root_components'),
|
||||
nestedExamplesAsValue = path.join(__dirname, BUNDLES_FOLDER + '/nested_examples_as_value'),
|
||||
referencedProperties = path.join(__dirname, BUNDLES_FOLDER + '/referenced_properties'),
|
||||
referencedComponents = path.join(__dirname, BUNDLES_FOLDER + '/referenced_components'),
|
||||
referencedPath = path.join(__dirname, BUNDLES_FOLDER + '/referenced_path');
|
||||
|
||||
describe('bundle files method - 3.0', function () {
|
||||
@@ -2402,6 +2403,54 @@ describe('bundle files method - 3.0', function () {
|
||||
expect(res.result).to.be.true;
|
||||
expect(res.output.data[0].referenceMap).to.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('Should return bundled file - referenced-components', async function () {
|
||||
let contentRootFile = fs.readFileSync(referencedComponents + '/root.yaml', 'utf8'),
|
||||
components = fs.readFileSync(referencedComponents + '/components.yaml', 'utf8'),
|
||||
responses = fs.readFileSync(referencedComponents + '/responses.yaml', 'utf8'),
|
||||
schemas = fs.readFileSync(referencedComponents + '/schemas.yaml', 'utf8'),
|
||||
schemaA = fs.readFileSync(referencedComponents + '/schemaA.yaml', 'utf8'),
|
||||
expected = fs.readFileSync(referencedComponents + '/expected.json', 'utf8'),
|
||||
input = {
|
||||
type: 'multiFile',
|
||||
specificationVersion: '3.0',
|
||||
rootFiles: [
|
||||
{
|
||||
path: '/root.yaml'
|
||||
}
|
||||
],
|
||||
data: [
|
||||
{
|
||||
path: '/root.yaml',
|
||||
content: contentRootFile
|
||||
},
|
||||
{
|
||||
path: '/components.yaml',
|
||||
content: components
|
||||
},
|
||||
{
|
||||
path: '/responses.yaml',
|
||||
content: responses
|
||||
},
|
||||
{
|
||||
path: '/schemas.yaml',
|
||||
content: schemas
|
||||
},
|
||||
{
|
||||
path: '/schemaA.yaml',
|
||||
content: schemaA
|
||||
}
|
||||
],
|
||||
options: {},
|
||||
bundleFormat: 'JSON'
|
||||
};
|
||||
const res = await Converter.bundle(input);
|
||||
|
||||
expect(res).to.not.be.empty;
|
||||
expect(res.result).to.be.true;
|
||||
expect(res.output.specification.version).to.equal('3.0');
|
||||
expect(JSON.stringify(JSON.parse(res.output.data[0].bundledContent), null, 2)).to.be.equal(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getReferences method when node does not have any reference', function() {
|
||||
|
||||
@@ -27,7 +27,9 @@ let expect = require('chai').expect,
|
||||
schemaCollision = path.join(__dirname, SWAGGER_MULTIFILE_FOLDER +
|
||||
'/schema_collision_from_responses'),
|
||||
schemaCollisionWRootComponent = path.join(__dirname, SWAGGER_MULTIFILE_FOLDER +
|
||||
'/schema_collision_w_root_components');
|
||||
'/schema_collision_w_root_components'),
|
||||
referencedRootComponents = path.join(__dirname, SWAGGER_MULTIFILE_FOLDER +
|
||||
'/referenced_root_components');
|
||||
|
||||
describe('bundle files method - 2.0', function() {
|
||||
it('Should return bundled result from - nestedProperties20', async function() {
|
||||
@@ -906,4 +908,67 @@ describe('bundle files method - 2.0', function() {
|
||||
expect(res.output.specification.version).to.equal('2.0');
|
||||
expect(JSON.stringify(JSON.parse(res.output.data[0].bundledContent), null, 2)).to.be.equal(expected);
|
||||
});
|
||||
|
||||
it('Should return bundled file as json - referenced_root_components', async function () {
|
||||
let contentRootFile = fs.readFileSync(referencedRootComponents + '/root.yaml', 'utf8'),
|
||||
definitions = fs.readFileSync(referencedRootComponents + '/definitions.yaml', 'utf8'),
|
||||
info = fs.readFileSync(referencedRootComponents + '/info.yaml', 'utf8'),
|
||||
responses = fs.readFileSync(referencedRootComponents + '/responses.yaml', 'utf8'),
|
||||
securitySchemes = fs.readFileSync(referencedRootComponents + '/securitySchemes.yaml', 'utf8'),
|
||||
tags = fs.readFileSync(referencedRootComponents + '/tags.yaml', 'utf8'),
|
||||
paths = fs.readFileSync(referencedRootComponents + '/paths/paths.yaml', 'utf8'),
|
||||
singlePath = fs.readFileSync(referencedRootComponents + '/paths/path.yaml', 'utf8'),
|
||||
expected = fs.readFileSync(referencedRootComponents + '/expected.json', 'utf8'),
|
||||
input = {
|
||||
type: 'multiFile',
|
||||
specificationVersion: '2.0',
|
||||
rootFiles: [
|
||||
{
|
||||
path: '/root.yaml'
|
||||
}
|
||||
],
|
||||
data: [
|
||||
{
|
||||
path: '/root.yaml',
|
||||
content: contentRootFile
|
||||
},
|
||||
{
|
||||
path: '/definitions.yaml',
|
||||
content: definitions
|
||||
},
|
||||
{
|
||||
path: '/info.yaml',
|
||||
content: info
|
||||
},
|
||||
{
|
||||
path: '/responses.yaml',
|
||||
content: responses
|
||||
},
|
||||
{
|
||||
path: '/securitySchemes.yaml',
|
||||
content: securitySchemes
|
||||
},
|
||||
{
|
||||
path: '/tags.yaml',
|
||||
content: tags
|
||||
},
|
||||
{
|
||||
path: '/paths/paths.yaml',
|
||||
content: paths
|
||||
},
|
||||
{
|
||||
path: '/paths/path.yaml',
|
||||
content: singlePath
|
||||
}
|
||||
],
|
||||
options: {},
|
||||
bundleFormat: 'JSON'
|
||||
};
|
||||
const res = await Converter.bundle(input);
|
||||
|
||||
expect(res).to.not.be.empty;
|
||||
expect(res.result).to.be.true;
|
||||
expect(res.output.specification.version).to.equal('2.0');
|
||||
expect(JSON.stringify(JSON.parse(res.output.data[0].bundledContent), null, 2)).to.be.equal(expected);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user