mirror of
https://github.com/postmanlabs/openapi-to-postman.git
synced 2022-11-29 22:05:00 +03:00
Merge pull request #563 from postmanlabs/feature/bundleCollisionHandling3020
Feature/bundle collision handling3020
This commit is contained in:
110
lib/bundle.js
110
lib/bundle.js
@@ -6,11 +6,13 @@ const {
|
||||
localPointer,
|
||||
jsonPointerLevelSeparator,
|
||||
isLocalRef,
|
||||
jsonPointerDecodeAndReplace
|
||||
jsonPointerDecodeAndReplace,
|
||||
generateObjectName
|
||||
} = require('./jsonPointer'),
|
||||
traverseUtility = require('traverse'),
|
||||
parse = require('./parse.js'),
|
||||
{ ParseError } = require('./common/ParseError');
|
||||
{ ParseError } = require('./common/ParseError'),
|
||||
crypto = require('crypto');
|
||||
|
||||
let path = require('path'),
|
||||
pathBrowserify = require('path-browserify'),
|
||||
@@ -182,14 +184,44 @@ function setValueInComponents(keyInComponents, components, value, componentsKeys
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the has of a provided key and join its first 4 numbers at the end of the current key by a _
|
||||
* @param {string} currentKey The key we will hash
|
||||
* @returns {string} A key with a hashed part joined by _
|
||||
*/
|
||||
function createComponentHashedKey(currentKey) {
|
||||
let hashPart = crypto.createHash('sha1')
|
||||
.update(currentKey)
|
||||
.digest('base64')
|
||||
.substring(0, 4),
|
||||
newKey = generateObjectName(currentKey, hashPart);
|
||||
return newKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a not repeated mainKey for the component
|
||||
* @param {string} tempRef - The reference to the node we are processing
|
||||
* @param {array} mainKeys - A list of previous generated mainKeys
|
||||
* @returns {string} A generated mainKey from the provided tempRef
|
||||
*/
|
||||
function createComponentMainKey(tempRef, mainKeys) {
|
||||
let newKey = generateObjectName(tempRef),
|
||||
mainKey = mainKeys[newKey];
|
||||
if (mainKey && mainKey !== tempRef) {
|
||||
newKey = createComponentHashedKey(tempRef);
|
||||
}
|
||||
return newKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a trace from the current node's root to the place where we find a $ref
|
||||
* @param {object} nodeContext - The current node we are processing
|
||||
* @param {object} property - The current property that contains the $ref
|
||||
* @param {object} tempRef - The tempRef from the $ref
|
||||
* @param {object} mainKeys - The dictionary of the previous keys generated
|
||||
* @param {string} version - The current version of the spec
|
||||
* @returns {array} The trace to the place where the $ref appears
|
||||
*/
|
||||
function getTraceFromParentKeyInComponents(nodeContext, property, version) {
|
||||
function getTraceFromParentKeyInComponents(nodeContext, tempRef, mainKeys, version) {
|
||||
const parents = [...nodeContext.parents].reverse(),
|
||||
isArrayKeyRegexp = new RegExp('^\\d$', 'g'),
|
||||
key = nodeContext.key,
|
||||
@@ -201,11 +233,31 @@ function getTraceFromParentKeyInComponents(nodeContext, property, version) {
|
||||
parentKeys :
|
||||
[key, ...parentKeys],
|
||||
nodeTrace = getRootFileTrace(nodeParentsKey),
|
||||
[file, local] = property.split(localPointer),
|
||||
keyTraceInComponents = getKeyInComponents(nodeTrace, file, local, version);
|
||||
componentKey = createComponentMainKey(tempRef, mainKeys),
|
||||
keyTraceInComponents = getKeyInComponents(nodeTrace, componentKey, version);
|
||||
return keyTraceInComponents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the generated trace if there is a collision with a key that exists in root components object
|
||||
* @param {array} trace The generated trace
|
||||
* @param {object} initialMainKeys the main keys in local components object if it exists
|
||||
* @returns {array} A modified trace if there is any collision with local reusable objects
|
||||
*/
|
||||
function handleLocalCollisions(trace, initialMainKeys) {
|
||||
if (trace.length === 0) {
|
||||
return trace;
|
||||
}
|
||||
const componentType = trace[trace.length - 2],
|
||||
initialKeysOfType = initialMainKeys[componentType],
|
||||
generatedKeyIndex = trace.length - 1;
|
||||
|
||||
if (initialKeysOfType && initialKeysOfType.includes(trace[generatedKeyIndex])) {
|
||||
trace[generatedKeyIndex] = createComponentHashedKey(trace[generatedKeyIndex]);
|
||||
}
|
||||
return trace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the $refs from an object
|
||||
* @param {object} currentNode - current node in process
|
||||
@@ -213,11 +265,13 @@ function getTraceFromParentKeyInComponents(nodeContext, property, version) {
|
||||
* @param {Function} pathSolver - function to resolve the Path
|
||||
* @param {string} parentFilename - The parent's filename
|
||||
* @param {object} version - The version of the spec we are bundling
|
||||
* @param {object} rootMainKeys - A dictionary with the component keys in local components object and its mainKeys
|
||||
* @returns {object} - The references in current node and the new content from the node
|
||||
*/
|
||||
function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename, version) {
|
||||
function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename, version, rootMainKeys) {
|
||||
let referencesInNode = [],
|
||||
nodeReferenceDirectory = {};
|
||||
nodeReferenceDirectory = {},
|
||||
mainKeys = {};
|
||||
traverseUtility(currentNode).forEach(function (property) {
|
||||
if (property) {
|
||||
let hasReferenceTypeKey;
|
||||
@@ -232,7 +286,11 @@ function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename, ve
|
||||
);
|
||||
if (hasReferenceTypeKey) {
|
||||
const tempRef = calculatePath(parentFilename, property.$ref),
|
||||
nodeTrace = getTraceFromParentKeyInComponents(this, tempRef, version),
|
||||
nodeTrace = handleLocalCollisions(
|
||||
getTraceFromParentKeyInComponents(this, tempRef, mainKeys, version),
|
||||
rootMainKeys
|
||||
),
|
||||
componentKey = nodeTrace[nodeTrace.length - 1],
|
||||
referenceInDocument = getJsonPointerRelationToRoot(
|
||||
tempRef,
|
||||
nodeTrace,
|
||||
@@ -257,9 +315,12 @@ function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename, ve
|
||||
node: newValue,
|
||||
reference: referenceInDocument,
|
||||
traceToParent,
|
||||
parentNodeKey: parentFilename
|
||||
parentNodeKey: parentFilename,
|
||||
mainKeyInTrace: nodeTrace[nodeTrace.length - 1]
|
||||
};
|
||||
|
||||
mainKeys[componentKey] = tempRef;
|
||||
|
||||
if (!added(property.$ref, referencesInNode)) {
|
||||
referencesInNode.push({ path: pathSolver(property), keyInComponents: nodeTrace, newValue: this.node });
|
||||
}
|
||||
@@ -276,9 +337,10 @@ function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename, ve
|
||||
* @param {Array} allData - array of { path, content} objects
|
||||
* @param {object} specRoot - root file information
|
||||
* @param {string} version - The current version
|
||||
* @param {object} rootMainKeys - A dictionary with the local reusable components keys and its mainKeys
|
||||
* @returns {object} - Detect root files result object
|
||||
*/
|
||||
function getNodeContentAndReferences (currentNode, allData, specRoot, version) {
|
||||
function getNodeContentAndReferences (currentNode, allData, specRoot, version, rootMainKeys) {
|
||||
let graphAdj = [],
|
||||
missingNodes = [],
|
||||
nodeContent;
|
||||
@@ -295,7 +357,8 @@ function getNodeContentAndReferences (currentNode, allData, specRoot, version) {
|
||||
currentNode.fileName !== specRoot.fileName,
|
||||
removeLocalReferenceFromPath,
|
||||
currentNode.fileName,
|
||||
version
|
||||
version,
|
||||
rootMainKeys
|
||||
);
|
||||
|
||||
referencesInNode.forEach((reference) => {
|
||||
@@ -420,6 +483,25 @@ function generateComponentsWrapper(parsedOasObject, version) {
|
||||
return components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a dictionary with the resusable component keys and their mainKeys in document before the bundle
|
||||
* @param {object} components - The wrapper with the root reusable components before the bundle
|
||||
* @param {string} version - The spec version
|
||||
* @returns {object} - A directory with the local components keys related with their mainKeys
|
||||
*/
|
||||
function getMainKeysFromComponents(components, version) {
|
||||
const {
|
||||
COMPONENTS_KEYS
|
||||
} = getBundleRulesDataByVersion(version);
|
||||
let componentsDictionary = {};
|
||||
COMPONENTS_KEYS.forEach((key) => {
|
||||
if (components[key]) {
|
||||
componentsDictionary[key] = Object.keys(components[key]);
|
||||
}
|
||||
});
|
||||
return componentsDictionary;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Takes in an spec root file and an array of data files
|
||||
@@ -435,11 +517,13 @@ module.exports = {
|
||||
if (origin === BROWSER) {
|
||||
path = pathBrowserify;
|
||||
}
|
||||
const initialComponents = generateComponentsWrapper(specRoot.parsed.oasObject, version),
|
||||
initialMainKeys = getMainKeysFromComponents(initialComponents, version);
|
||||
let algorithm = new DFS(),
|
||||
components = {},
|
||||
rootContextData;
|
||||
rootContextData = algorithm.traverseAndBundle(specRoot, (currentNode) => {
|
||||
return getNodeContentAndReferences(currentNode, allData, specRoot, version);
|
||||
return getNodeContentAndReferences(currentNode, allData, specRoot, version, initialMainKeys);
|
||||
});
|
||||
components = generateComponentsWrapper(specRoot.parsed.oasObject, version);
|
||||
generateComponentsObject(
|
||||
|
||||
@@ -22,17 +22,6 @@ function jsonPointerEncodeAndReplace(filePathName) {
|
||||
return encodeURIComponent(filePathName.replace(tildes, escapedTildeString).replace(slashes, escapedSlashString));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a path and return a valid key name in openapi spec
|
||||
* @param {string} filePathName - The filePath from the ref called
|
||||
* @returns {string} A valid in openapi object name
|
||||
*/
|
||||
function generateObjectName(filePathName) {
|
||||
let validName = filePathName.replace(/\//g, '_').replace(/#/g, '-');
|
||||
validName = validName.replace(/[^a-zA-Z0-9\.\-_]/g, '');
|
||||
return validName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a json pointer
|
||||
* replaces ~0 and ~1 for tildes and slashes
|
||||
@@ -43,27 +32,40 @@ function jsonPointerDecodeAndReplace(filePathName) {
|
||||
return decodeURIComponent(filePathName.replace(escapedSlash, jsonPointerLevelSeparator).replace(escapedTilde, '~'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a path and return a valid key name in openapi spec
|
||||
* @param {string} filePathName - The filePath from the ref called
|
||||
* @param {string} hash - A calculated hash to join with the resultant generatedName
|
||||
* @returns {string} A valid in openapi object name
|
||||
*/
|
||||
function generateObjectName(filePathName, hash = '') {
|
||||
let decodedRef = jsonPointerDecodeAndReplace(filePathName),
|
||||
validName = decodedRef.replace(/\//g, '_').replace(/#/g, '-'),
|
||||
hashPart = hash ? `_${hash}` : '';
|
||||
validName = `${validName.replace(/[^a-zA-Z0-9\.\-_]/g, '')}${hashPart}`;
|
||||
return validName;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the key that the object in components will have could be nested
|
||||
* @param {string} traceFromParent the node trace from root.
|
||||
* @param {string} filePathName the filePathName of the file
|
||||
* @param {string} localPath the local path that the pointer will reach
|
||||
* @param {string} mainKey - The generated mainKey for the components
|
||||
* @param {string} version - The current spec version
|
||||
* @returns {Array} - the calculated keys in an array representing each nesting property name
|
||||
*/
|
||||
function getKeyInComponents(traceFromParent, filePathName, localPath, version) {
|
||||
const localPart = localPath ? `${localPointer}${localPath}` : '',
|
||||
{
|
||||
CONTAINERS,
|
||||
DEFINITIONS,
|
||||
COMPONENTS_KEYS,
|
||||
INLINE,
|
||||
ROOT_CONTAINERS_KEYS
|
||||
} = getBundleRulesDataByVersion(version);
|
||||
function getKeyInComponents(traceFromParent, mainKey, version) {
|
||||
// const localPart = localPath ? `${localPointer}${localPath}` : '',
|
||||
const {
|
||||
CONTAINERS,
|
||||
DEFINITIONS,
|
||||
COMPONENTS_KEYS,
|
||||
INLINE,
|
||||
ROOT_CONTAINERS_KEYS
|
||||
} = getBundleRulesDataByVersion(version);
|
||||
let result,
|
||||
trace = [
|
||||
...traceFromParent,
|
||||
jsonPointerDecodeAndReplace(`${filePathName}${localPart}`)
|
||||
jsonPointerDecodeAndReplace(mainKey)
|
||||
].reverse(),
|
||||
traceToKey = [],
|
||||
matchFound = false,
|
||||
@@ -91,7 +93,7 @@ function getKeyInComponents(traceFromParent, filePathName, localPath, version) {
|
||||
result = matchFound ?
|
||||
traceToKey.reverse() :
|
||||
[];
|
||||
return result.map(generateObjectName);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
{
|
||||
"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"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://api.example.com/v1",
|
||||
"description": "Optional server description, e.g. Main (production) server"
|
||||
},
|
||||
{
|
||||
"url": "http://staging-api.example.com",
|
||||
"description": "Optional server description, e.g. Internal staging server for testing"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/users/{userId}": {
|
||||
"get": {
|
||||
"summary": "Get a user by ID",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A single user.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/_schemas___user.yaml"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/weird": {
|
||||
"get": {
|
||||
"summary": "Get a user by ID",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A single user.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/_schemas___user.yaml_RQm8"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/other": {
|
||||
"get": {
|
||||
"summary": "Get a user by ID",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A single user.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/_schemas___user.yaml_mvS0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"_schemas___user.yaml": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"userName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"_schemas___user.yaml_RQm8": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"otherCollisionedId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"someData": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"_schemas___user.yaml_mvS0": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aCollisionedItem": {
|
||||
"type": "integer"
|
||||
},
|
||||
"userName": {
|
||||
"type": "string"
|
||||
},
|
||||
"randomString": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
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
|
||||
|
||||
servers:
|
||||
- url: http://api.example.com/v1
|
||||
description: Optional server description, e.g. Main (production) server
|
||||
- url: http://staging-api.example.com
|
||||
description: Optional server description, e.g. Internal staging server for testing
|
||||
|
||||
paths:
|
||||
/users/{userId}:
|
||||
get:
|
||||
summary: Get a user by ID
|
||||
responses:
|
||||
200:
|
||||
description: A single user.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas__/user.yaml"
|
||||
/users/weird:
|
||||
get:
|
||||
summary: Get a user by ID
|
||||
responses:
|
||||
200:
|
||||
description: A single user.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas_/_user.yaml"
|
||||
/users/other:
|
||||
get:
|
||||
summary: Get a user by ID
|
||||
responses:
|
||||
200:
|
||||
description: A single user.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/__user.yaml"
|
||||
@@ -0,0 +1,8 @@
|
||||
type: object
|
||||
properties:
|
||||
aCollisionedItem:
|
||||
type: integer
|
||||
userName:
|
||||
type: string
|
||||
randomString:
|
||||
type: string
|
||||
@@ -0,0 +1,6 @@
|
||||
type: object
|
||||
properties:
|
||||
otherCollisionedId:
|
||||
type: integer
|
||||
someData:
|
||||
type: string
|
||||
@@ -0,0 +1,6 @@
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
userName:
|
||||
type: string
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"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"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://api.example.com/v1",
|
||||
"description": "Optional server description, e.g. Main (production) server"
|
||||
},
|
||||
{
|
||||
"url": "http://staging-api.example.com",
|
||||
"description": "Optional server description, e.g. Internal staging server for testing"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/users/{userId}": {
|
||||
"get": {
|
||||
"summary": "Get a user by ID",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A single user.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/_schemas_user.yaml_zfNS"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/other": {
|
||||
"get": {
|
||||
"summary": "Get a user by ID",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A single user.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/_schemas_user.yaml"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"_schemas_user.yaml": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"componentInRootId": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"_schemas_user.yaml_zfNS": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aCollisionedItem": {
|
||||
"type": "integer"
|
||||
},
|
||||
"userName": {
|
||||
"type": "string"
|
||||
},
|
||||
"randomString": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
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
|
||||
|
||||
servers:
|
||||
- url: http://api.example.com/v1
|
||||
description: Optional server description, e.g. Main (production) server
|
||||
- url: http://staging-api.example.com
|
||||
description: Optional server description, e.g. Internal staging server for testing
|
||||
|
||||
paths:
|
||||
/users/{userId}:
|
||||
get:
|
||||
summary: Get a user by ID
|
||||
responses:
|
||||
200:
|
||||
description: A single user.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/user.yaml"
|
||||
/users/other:
|
||||
get:
|
||||
summary: Get a user by ID
|
||||
responses:
|
||||
200:
|
||||
description: A single user.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/_schemas_user.yaml"
|
||||
components:
|
||||
schemas:
|
||||
"_schemas_user.yaml":
|
||||
type: object
|
||||
properties:
|
||||
componentInRootId:
|
||||
type: string
|
||||
@@ -0,0 +1,8 @@
|
||||
type: object
|
||||
properties:
|
||||
aCollisionedItem:
|
||||
type: integer
|
||||
userName:
|
||||
type: string
|
||||
randomString:
|
||||
type: string
|
||||
@@ -0,0 +1,109 @@
|
||||
{
|
||||
"swagger": 2,
|
||||
"info": {
|
||||
"title": "Sample API",
|
||||
"description": "Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.",
|
||||
"version": "0.1.9"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://api.example.com/v1",
|
||||
"description": "Optional server description, e.g. Main (production) server"
|
||||
},
|
||||
{
|
||||
"url": "http://staging-api.example.com",
|
||||
"description": "Optional server description, e.g. Internal staging server for testing"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/users/{userId}": {
|
||||
"get": {
|
||||
"summary": "Get a user by ID",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A single user.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/definitions/_schemas___user.yaml"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/weird": {
|
||||
"get": {
|
||||
"summary": "Get a user by ID",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A single user.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/definitions/_schemas___user.yaml_RQm8"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/other": {
|
||||
"get": {
|
||||
"summary": "Get a user by ID",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A single user.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/definitions/_schemas___user.yaml_mvS0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"_schemas___user.yaml": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"userName": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"_schemas___user.yaml_RQm8": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"otherCollisionedId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"someData": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"_schemas___user.yaml_mvS0": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aCollisionedItem": {
|
||||
"type": "integer"
|
||||
},
|
||||
"userName": {
|
||||
"type": "string"
|
||||
},
|
||||
"randomString": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
swagger: 2.0
|
||||
info:
|
||||
title: Sample API
|
||||
description: Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.
|
||||
version: 0.1.9
|
||||
|
||||
servers:
|
||||
- url: http://api.example.com/v1
|
||||
description: Optional server description, e.g. Main (production) server
|
||||
- url: http://staging-api.example.com
|
||||
description: Optional server description, e.g. Internal staging server for testing
|
||||
|
||||
paths:
|
||||
/users/{userId}:
|
||||
get:
|
||||
summary: Get a user by ID
|
||||
responses:
|
||||
200:
|
||||
description: A single user.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas__/user.yaml"
|
||||
/users/weird:
|
||||
get:
|
||||
summary: Get a user by ID
|
||||
responses:
|
||||
200:
|
||||
description: A single user.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas_/_user.yaml"
|
||||
/users/other:
|
||||
get:
|
||||
summary: Get a user by ID
|
||||
responses:
|
||||
200:
|
||||
description: A single user.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/__user.yaml"
|
||||
@@ -0,0 +1,8 @@
|
||||
type: object
|
||||
properties:
|
||||
aCollisionedItem:
|
||||
type: integer
|
||||
userName:
|
||||
type: string
|
||||
randomString:
|
||||
type: string
|
||||
@@ -0,0 +1,6 @@
|
||||
type: object
|
||||
properties:
|
||||
otherCollisionedId:
|
||||
type: integer
|
||||
someData:
|
||||
type: string
|
||||
@@ -0,0 +1,6 @@
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
userName:
|
||||
type: string
|
||||
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"swagger": 2,
|
||||
"info": {
|
||||
"title": "Sample API",
|
||||
"description": "Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.",
|
||||
"version": "0.1.9"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://api.example.com/v1",
|
||||
"description": "Optional server description, e.g. Main (production) server"
|
||||
},
|
||||
{
|
||||
"url": "http://staging-api.example.com",
|
||||
"description": "Optional server description, e.g. Internal staging server for testing"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/users/{userId}": {
|
||||
"get": {
|
||||
"summary": "Get a user by ID",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A single user.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/definitions/_schemas_user.yaml_zfNS"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/other": {
|
||||
"get": {
|
||||
"summary": "Get a user by ID",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A single user.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/definitions/_schemas_user.yaml"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"_schemas_user.yaml": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"componentInRootId": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"_schemas_user.yaml_zfNS": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aCollisionedItem": {
|
||||
"type": "integer"
|
||||
},
|
||||
"userName": {
|
||||
"type": "string"
|
||||
},
|
||||
"randomString": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
swagger: 2.0
|
||||
info:
|
||||
title: Sample API
|
||||
description: Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.
|
||||
version: 0.1.9
|
||||
|
||||
servers:
|
||||
- url: http://api.example.com/v1
|
||||
description: Optional server description, e.g. Main (production) server
|
||||
- url: http://staging-api.example.com
|
||||
description: Optional server description, e.g. Internal staging server for testing
|
||||
|
||||
paths:
|
||||
/users/{userId}:
|
||||
get:
|
||||
summary: Get a user by ID
|
||||
responses:
|
||||
200:
|
||||
description: A single user.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "./schemas/user.yaml"
|
||||
/users/other:
|
||||
get:
|
||||
summary: Get a user by ID
|
||||
responses:
|
||||
200:
|
||||
description: A single user.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/definitions/_schemas_user.yaml"
|
||||
definitions:
|
||||
"_schemas_user.yaml":
|
||||
type: object
|
||||
properties:
|
||||
componentInRootId:
|
||||
type: string
|
||||
@@ -0,0 +1,8 @@
|
||||
type: object
|
||||
properties:
|
||||
aCollisionedItem:
|
||||
type: integer
|
||||
userName:
|
||||
type: string
|
||||
randomString:
|
||||
type: string
|
||||
@@ -37,7 +37,9 @@ let expect = require('chai').expect,
|
||||
additionalProperties = path.join(__dirname, BUNDLES_FOLDER + '/additionalProperties'),
|
||||
compositeOneOf = path.join(__dirname, BUNDLES_FOLDER + '/composite_oneOf'),
|
||||
compositeNot = path.join(__dirname, BUNDLES_FOLDER + '/composite_not'),
|
||||
compositeAnyOf = path.join(__dirname, BUNDLES_FOLDER + '/composite_anyOf');
|
||||
compositeAnyOf = path.join(__dirname, BUNDLES_FOLDER + '/composite_anyOf'),
|
||||
schemaCollision = path.join(__dirname, BUNDLES_FOLDER + '/schema_collision_from_responses'),
|
||||
schemaCollisionWRootComponent = path.join(__dirname, BUNDLES_FOLDER + '/schema_collision_w_root_components');
|
||||
|
||||
describe('bundle files method - 3.0', function () {
|
||||
it('Should return bundled file as json - schema_from_response', async function () {
|
||||
@@ -1924,6 +1926,82 @@ describe('bundle files method - 3.0', function () {
|
||||
expect(error.message).to.equal('The provided version "Anything" is not valid');
|
||||
}
|
||||
});
|
||||
|
||||
it('Should return bundled file as json - schema_collision_from_responses', async function () {
|
||||
let contentRootFile = fs.readFileSync(schemaCollision + '/root.yaml', 'utf8'),
|
||||
user = fs.readFileSync(schemaCollision + '/schemas_/_user.yaml', 'utf8'),
|
||||
user1 = fs.readFileSync(schemaCollision + '/schemas/__user.yaml', 'utf8'),
|
||||
user2 = fs.readFileSync(schemaCollision + '/schemas__/user.yaml', 'utf8'),
|
||||
expected = fs.readFileSync(schemaCollision + '/expected.json', 'utf8'),
|
||||
input = {
|
||||
type: 'multiFile',
|
||||
specificationVersion: '3.0',
|
||||
rootFiles: [
|
||||
{
|
||||
path: '/root.yaml'
|
||||
}
|
||||
],
|
||||
data: [
|
||||
{
|
||||
path: '/root.yaml',
|
||||
content: contentRootFile
|
||||
},
|
||||
{
|
||||
path: '/schemas__/user.yaml',
|
||||
content: user2
|
||||
},
|
||||
{
|
||||
path: '/schemas_/_user.yaml',
|
||||
content: user
|
||||
},
|
||||
{
|
||||
path: '/schemas/__user.yaml',
|
||||
content: user1
|
||||
}
|
||||
],
|
||||
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);
|
||||
});
|
||||
|
||||
it('Should return bundled file as json - schema_collision_w_root_components', async function () {
|
||||
let contentRootFile = fs.readFileSync(schemaCollisionWRootComponent + '/root.yaml', 'utf8'),
|
||||
user = fs.readFileSync(schemaCollisionWRootComponent + '/schemas/user.yaml', 'utf8'),
|
||||
expected = fs.readFileSync(schemaCollisionWRootComponent + '/expected.json', 'utf8'),
|
||||
input = {
|
||||
type: 'multiFile',
|
||||
specificationVersion: '3.0',
|
||||
rootFiles: [
|
||||
{
|
||||
path: '/root.yaml'
|
||||
}
|
||||
],
|
||||
data: [
|
||||
{
|
||||
path: '/root.yaml',
|
||||
content: contentRootFile
|
||||
},
|
||||
{
|
||||
path: '/schemas/user.yaml',
|
||||
content: user
|
||||
}
|
||||
],
|
||||
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() {
|
||||
@@ -1940,7 +2018,8 @@ describe('getReferences method when node does not have any reference', function(
|
||||
userNode.oasObject,
|
||||
nodeIsRoot,
|
||||
removeLocalReferenceFromPath,
|
||||
'the/parent/filename'
|
||||
'the/parent/filename',
|
||||
{}
|
||||
);
|
||||
|
||||
expect(result.referencesInNode).to.be.an('array').with.length(0);
|
||||
@@ -1971,7 +2050,8 @@ describe('getReferences method when node does not have any reference', function(
|
||||
userNode.oasObject,
|
||||
nodeIsRoot,
|
||||
removeLocalReferenceFromPath,
|
||||
'the/parent/filename'
|
||||
'the/parent/filename',
|
||||
{}
|
||||
);
|
||||
expect(result.nodeReferenceDirectory).to.be.an('object');
|
||||
expect(Object.keys(result.nodeReferenceDirectory).length).to.equal(1);
|
||||
|
||||
@@ -23,7 +23,11 @@ let expect = require('chai').expect,
|
||||
SWAGGER_PETSTORE_FOLDER = path.join(__dirname, '../data/swaggerMultifile/petstore-separate-yaml'),
|
||||
additionalProperties20 = path.join(__dirname, SWAGGER_MULTIFILE_FOLDER + '/additionalProperties'),
|
||||
referencedSecuritySchemes20 = path.join(__dirname, SWAGGER_MULTIFILE_FOLDER + '/referenced_security_schemes'),
|
||||
referencedResponse20 = path.join(__dirname, SWAGGER_MULTIFILE_FOLDER + '/referenced_response');
|
||||
referencedResponse20 = path.join(__dirname, SWAGGER_MULTIFILE_FOLDER + '/referenced_response'),
|
||||
schemaCollision = path.join(__dirname, SWAGGER_MULTIFILE_FOLDER +
|
||||
'/schema_collision_from_responses'),
|
||||
schemaCollisionWRootComponent = path.join(__dirname, SWAGGER_MULTIFILE_FOLDER +
|
||||
'/schema_collision_w_root_components');
|
||||
|
||||
describe('bundle files method - 2.0', function() {
|
||||
it('Should return bundled result from - nestedProperties20', async function() {
|
||||
@@ -826,4 +830,80 @@ describe('bundle files method - 2.0', function() {
|
||||
expect(res.result).to.be.true;
|
||||
expect(JSON.stringify(JSON.parse(res.output.data[0].bundledContent), null, 2)).to.be.equal(expected);
|
||||
});
|
||||
|
||||
it('Should return bundled file as json - schema_collision_from_responses', async function () {
|
||||
let contentRootFile = fs.readFileSync(schemaCollision + '/root.yaml', 'utf8'),
|
||||
user = fs.readFileSync(schemaCollision + '/schemas_/_user.yaml', 'utf8'),
|
||||
user1 = fs.readFileSync(schemaCollision + '/schemas/__user.yaml', 'utf8'),
|
||||
user2 = fs.readFileSync(schemaCollision + '/schemas__/user.yaml', 'utf8'),
|
||||
expected = fs.readFileSync(schemaCollision + '/expected.json', 'utf8'),
|
||||
input = {
|
||||
type: 'multiFile',
|
||||
specificationVersion: '2.0',
|
||||
rootFiles: [
|
||||
{
|
||||
path: '/root.yaml'
|
||||
}
|
||||
],
|
||||
data: [
|
||||
{
|
||||
path: '/root.yaml',
|
||||
content: contentRootFile
|
||||
},
|
||||
{
|
||||
path: '/schemas__/user.yaml',
|
||||
content: user2
|
||||
},
|
||||
{
|
||||
path: '/schemas_/_user.yaml',
|
||||
content: user
|
||||
},
|
||||
{
|
||||
path: '/schemas/__user.yaml',
|
||||
content: user1
|
||||
}
|
||||
],
|
||||
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);
|
||||
});
|
||||
|
||||
it('Should return bundled file as json - schema_collision_w_root_components', async function () {
|
||||
let contentRootFile = fs.readFileSync(schemaCollisionWRootComponent + '/root.yaml', 'utf8'),
|
||||
user = fs.readFileSync(schemaCollisionWRootComponent + '/schemas/user.yaml', 'utf8'),
|
||||
expected = fs.readFileSync(schemaCollisionWRootComponent + '/expected.json', 'utf8'),
|
||||
input = {
|
||||
type: 'multiFile',
|
||||
specificationVersion: '2.0',
|
||||
rootFiles: [
|
||||
{
|
||||
path: '/root.yaml'
|
||||
}
|
||||
],
|
||||
data: [
|
||||
{
|
||||
path: '/root.yaml',
|
||||
content: contentRootFile
|
||||
},
|
||||
{
|
||||
path: '/schemas/user.yaml',
|
||||
content: user
|
||||
}
|
||||
],
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,43 +20,12 @@ describe('getKeyInComponents function', function () {
|
||||
expect(result).to.be.an('array').with.length(0);
|
||||
});
|
||||
|
||||
it('should return ["schemas", "_folder_pet.yaml"] when the filename scaped slash', function () {
|
||||
const result = getKeyInComponents(['path', 'schemas'], '~1folder~1pet.yaml');
|
||||
it('should return ["schemas", "_folder_pet.yaml"] when the filename _folder_pet.yaml', function () {
|
||||
const result = getKeyInComponents(['path', 'schemas'], '_folder_pet.yaml');
|
||||
expect(result).to.be.an('array').with.length(2);
|
||||
expect(result[0]).to.equal('schemas');
|
||||
expect(result[1]).to.equal('_folder_pet.yaml');
|
||||
});
|
||||
|
||||
it('should return ["schemas", "_folder_pet.yaml"] when the filename contains any slash', function () {
|
||||
const result = getKeyInComponents(['path', 'schemas'], '/folder/pet.yaml');
|
||||
expect(result).to.be.an('array').with.length(2);
|
||||
expect(result[0]).to.equal('schemas');
|
||||
expect(result[1]).to.equal('_folder_pet.yaml');
|
||||
});
|
||||
|
||||
it('should return ["schemas", "_folder_pet.yaml-_Name"] when the filename contains any sacped slash' +
|
||||
'and a local part using a scaped sharp', function () {
|
||||
const result = getKeyInComponents(['path', 'schemas'], '~1folder~1pet.yaml%23~1Name');
|
||||
expect(result).to.be.an('array').with.length(2);
|
||||
expect(result[0]).to.equal('schemas');
|
||||
expect(result[1]).to.equal('_folder_pet.yaml-_Name');
|
||||
});
|
||||
|
||||
it('should return ["schemas", "_folder_pet.yaml-_Name"] when the filename contains any slash' +
|
||||
'and a local part using a sharp', function () {
|
||||
const result = getKeyInComponents(['path', 'schemas'], '/folder/pet.yaml#/Name');
|
||||
expect(result).to.be.an('array').with.length(2);
|
||||
expect(result[0]).to.equal('schemas');
|
||||
expect(result[1]).to.equal('_folder_pet.yaml-_Name');
|
||||
});
|
||||
|
||||
it('should return ["schemas", "_foldertest_pet.yaml-_Name"] when the filename contains any slash' +
|
||||
'and a local part using a sharp and another not valid character', function () {
|
||||
const result = getKeyInComponents(['path', 'schemas'], '/folder@test/pet@.yaml#/Name');
|
||||
expect(result).to.be.an('array').with.length(2);
|
||||
expect(result[0]).to.equal('schemas');
|
||||
expect(result[1]).to.equal('_foldertest_pet.yaml-_Name');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getJsonPointerRelationToRoot function', function () {
|
||||
|
||||
Reference in New Issue
Block a user