mirror of
https://github.com/postmanlabs/openapi-to-postman.git
synced 2022-11-29 22:05:00 +03:00
Merge pull request #556 from postmanlabs/chore/RefactoringBundleRulesResolver3031
Refactor rule resolver 3.0 and 3.1
This commit is contained in:
@@ -1,102 +0,0 @@
|
||||
const COMPONENTS_KEYS_30 = [
|
||||
'schemas',
|
||||
'responses',
|
||||
'parameters',
|
||||
'examples',
|
||||
'requestBodies',
|
||||
'headers',
|
||||
'securitySchemes',
|
||||
'links',
|
||||
'callbacks'
|
||||
],
|
||||
SCHEMA_CONTAINERS = [
|
||||
'allOf',
|
||||
'oneOf',
|
||||
'anyOf',
|
||||
'not',
|
||||
'additionalProperties',
|
||||
'items',
|
||||
'schema'
|
||||
],
|
||||
EXAMPLE_CONTAINERS = [
|
||||
'example'
|
||||
],
|
||||
PROPERTY_DEFINITION = [
|
||||
'properties'
|
||||
],
|
||||
RESPONSE_DEFINITION = [
|
||||
'responses'
|
||||
],
|
||||
REQUEST_BODY_CONTAINER = [
|
||||
'requestBody'
|
||||
],
|
||||
LINKS_CONTAINER = [
|
||||
'links'
|
||||
],
|
||||
HEADER_DEFINITION = [
|
||||
'headers'
|
||||
],
|
||||
CALLBACK_DEFINITION = [
|
||||
'callbacks'
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Generates the trace to the key that will wrap de component using 3.0 version
|
||||
* @param {array} traceFromParent - The trace from the parent key
|
||||
* @param {string} filePathName - The filePath name from the file
|
||||
* @param {string} localPart - The local path part
|
||||
* @param {function} jsonPointerDecodeAndReplace - Function to decode a json pointer
|
||||
* @returns {array} The trace to the container key
|
||||
*/
|
||||
getKeyInComponents30: function (traceFromParent, filePathName, localPart, jsonPointerDecodeAndReplace) {
|
||||
let res = traceFromParent,
|
||||
trace = [],
|
||||
traceToKey = [],
|
||||
matchFound = false,
|
||||
isInComponents = traceFromParent[0] === 'components';
|
||||
|
||||
if (isInComponents) {
|
||||
return [];
|
||||
}
|
||||
|
||||
res.push(jsonPointerDecodeAndReplace(`${filePathName}${localPart}`));
|
||||
trace = [...res].reverse();
|
||||
|
||||
for (let [index, item] of trace.entries()) {
|
||||
if (SCHEMA_CONTAINERS.includes(item)) {
|
||||
item = 'schemas';
|
||||
}
|
||||
if (EXAMPLE_CONTAINERS.includes(item)) {
|
||||
item = 'examples';
|
||||
}
|
||||
if (REQUEST_BODY_CONTAINER.includes(item)) {
|
||||
item = 'requestBodies';
|
||||
}
|
||||
if (LINKS_CONTAINER.includes(trace[index + 2])) {
|
||||
trace[index + 1] = 'links';
|
||||
}
|
||||
if (PROPERTY_DEFINITION.includes(trace[index + 2])) {
|
||||
trace[index + 1] = 'schemas';
|
||||
}
|
||||
traceToKey.push(item);
|
||||
if (COMPONENTS_KEYS_30.includes(item)) {
|
||||
matchFound = true;
|
||||
break;
|
||||
}
|
||||
if (RESPONSE_DEFINITION.includes(trace[index + 2])) {
|
||||
trace[index + 1] = 'responses';
|
||||
}
|
||||
if (HEADER_DEFINITION.includes(trace[index + 2])) {
|
||||
trace[index + 1] = 'headers';
|
||||
}
|
||||
if (CALLBACK_DEFINITION.includes(trace[index + 2])) {
|
||||
trace[index + 1] = 'callbacks';
|
||||
}
|
||||
}
|
||||
return matchFound ?
|
||||
traceToKey.reverse() :
|
||||
[];
|
||||
},
|
||||
COMPONENTS_KEYS_30
|
||||
};
|
||||
@@ -1,109 +0,0 @@
|
||||
const COMPONENTS_KEYS_31 = [
|
||||
'schemas',
|
||||
'responses',
|
||||
'parameters',
|
||||
'examples',
|
||||
'requestBodies',
|
||||
'headers',
|
||||
'securitySchemes',
|
||||
'links',
|
||||
'callbacks',
|
||||
'pathItems'
|
||||
],
|
||||
SCHEMA_CONTAINERS = [
|
||||
'allOf',
|
||||
'oneOf',
|
||||
'anyOf',
|
||||
'not',
|
||||
'additionalProperties',
|
||||
'items',
|
||||
'schema'
|
||||
],
|
||||
EXAMPLE_CONTAINERS = [
|
||||
'example'
|
||||
],
|
||||
PROPERTY_DEFINITION = [
|
||||
'properties'
|
||||
],
|
||||
RESPONSE_DEFINITION = [
|
||||
'responses'
|
||||
],
|
||||
REQUEST_BODY_CONTAINER = [
|
||||
'requestBody'
|
||||
],
|
||||
LINKS_CONTAINER = [
|
||||
'links'
|
||||
],
|
||||
HEADER_DEFINITION = [
|
||||
'headers'
|
||||
],
|
||||
CALLBACK_DEFINITION = [
|
||||
'callbacks'
|
||||
],
|
||||
PATH_ITEM_CONTAINER = [
|
||||
'paths'
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Generates the trace to the key that will wrap de component using 3.0 version
|
||||
* @param {array} traceFromParent - The trace from the parent key
|
||||
* @param {string} filePathName - The filePath name from the file
|
||||
* @param {string} localPart - The local path part
|
||||
* @param {function} jsonPointerDecodeAndReplace - Function to decode a json pointer
|
||||
* @returns {array} The trace to the container key
|
||||
*/
|
||||
getKeyInComponents31: function (traceFromParent, filePathName, localPart, jsonPointerDecodeAndReplace) {
|
||||
let res = traceFromParent,
|
||||
trace = [],
|
||||
traceToKey = [],
|
||||
matchFound = false,
|
||||
isInComponents = traceFromParent[0] === 'components';
|
||||
|
||||
if (isInComponents) {
|
||||
return [];
|
||||
}
|
||||
|
||||
res.push(jsonPointerDecodeAndReplace(`${filePathName}${localPart}`));
|
||||
trace = [...res].reverse();
|
||||
|
||||
for (let [index, item] of trace.entries()) {
|
||||
if (SCHEMA_CONTAINERS.includes(item)) {
|
||||
item = 'schemas';
|
||||
}
|
||||
if (EXAMPLE_CONTAINERS.includes(item)) {
|
||||
item = 'examples';
|
||||
}
|
||||
if (REQUEST_BODY_CONTAINER.includes(item)) {
|
||||
item = 'requestBodies';
|
||||
}
|
||||
if (LINKS_CONTAINER.includes(trace[index + 2])) {
|
||||
trace[index + 1] = 'links';
|
||||
}
|
||||
if (PATH_ITEM_CONTAINER.includes(trace[index + 2])) {
|
||||
trace[index + 1] = 'pathItems';
|
||||
}
|
||||
if (PROPERTY_DEFINITION.includes(trace[index + 2])) {
|
||||
trace[index + 1] = 'schemas';
|
||||
}
|
||||
traceToKey.push(item);
|
||||
if (COMPONENTS_KEYS_31.includes(item)) {
|
||||
matchFound = true;
|
||||
break;
|
||||
}
|
||||
if (RESPONSE_DEFINITION.includes(trace[index + 2])) {
|
||||
trace[index + 1] = 'responses';
|
||||
}
|
||||
if (HEADER_DEFINITION.includes(trace[index + 2])) {
|
||||
trace[index + 1] = 'headers';
|
||||
}
|
||||
if (CALLBACK_DEFINITION.includes(trace[index + 2])) {
|
||||
trace[index + 1] = 'callbacks';
|
||||
}
|
||||
}
|
||||
return matchFound ?
|
||||
traceToKey.reverse() :
|
||||
[];
|
||||
},
|
||||
COMPONENTS_KEYS_31
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
const { COMPONENTS_KEYS_30 } = require('./30XUtils/componentsParentMatcher'),
|
||||
{
|
||||
const {
|
||||
isExtRef,
|
||||
getKeyInComponents,
|
||||
getJsonPointerRelationToRoot,
|
||||
@@ -11,8 +10,8 @@ const { COMPONENTS_KEYS_30 } = require('./30XUtils/componentsParentMatcher'),
|
||||
} = require('./jsonPointer'),
|
||||
traverseUtility = require('traverse'),
|
||||
parse = require('./parse.js'),
|
||||
{ COMPONENTS_KEYS_31 } = require('./31XUtils/componentsParentMatcher'),
|
||||
{ ParseError } = require('./common/ParseError');
|
||||
const { getBundleRulesDataByVersion } = require('./common/versionUtils');
|
||||
|
||||
let path = require('path'),
|
||||
pathBrowserify = require('path-browserify'),
|
||||
@@ -156,7 +155,7 @@ function getContentFromTrace(content, partial) {
|
||||
* @returns {null} It modifies components global context
|
||||
*/
|
||||
function setValueInComponents(keyInComponents, components, value, version) {
|
||||
const COMPONENTS_KEYS = version === '3.1' ? COMPONENTS_KEYS_31 : COMPONENTS_KEYS_30;
|
||||
const { COMPONENTS_KEYS } = getBundleRulesDataByVersion(version);
|
||||
let currentPlace = components,
|
||||
target = keyInComponents[keyInComponents.length - 2],
|
||||
key = keyInComponents.length === 2 && COMPONENTS_KEYS.includes(keyInComponents[0]) ?
|
||||
|
||||
33
lib/bundleRules/resolvers.js
Normal file
33
lib/bundleRules/resolvers.js
Normal file
@@ -0,0 +1,33 @@
|
||||
module.exports = {
|
||||
/**
|
||||
* Resolve the scenario if the item is in second level
|
||||
* @param {array} trace The keyInComponents
|
||||
* @param {number} index the current index
|
||||
* @return {undefined}
|
||||
*/
|
||||
|
||||
resolveSecondLevelChild: function (trace, index, definitions) {
|
||||
const item = definitions[trace[index + 2]];
|
||||
if (item) {
|
||||
trace[index + 1] = item;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* If the provided item is included in any defined container it returns the container name
|
||||
* else it return the same item
|
||||
* @param {string} item The current item in the iteration
|
||||
* @returns {string} the name of container where item is included or the item if it's not included
|
||||
* in any container
|
||||
*/
|
||||
|
||||
resolveFirstLevelChild: function(item, containers) {
|
||||
for (let [key, containerItems] of Object.entries(containers)) {
|
||||
if (containerItems.includes(item)) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
};
|
||||
52
lib/bundleRules/spec30.js
Normal file
52
lib/bundleRules/spec30.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const SCHEMA_CONTAINERS = [
|
||||
'allOf',
|
||||
'oneOf',
|
||||
'anyOf',
|
||||
'not',
|
||||
'additionalProperties',
|
||||
'items',
|
||||
'schema'
|
||||
],
|
||||
EXAMPLE_CONTAINERS = [
|
||||
'example'
|
||||
],
|
||||
REQUEST_BODY_CONTAINER = [
|
||||
'requestBody'
|
||||
],
|
||||
CONTAINERS = {
|
||||
schemas: SCHEMA_CONTAINERS,
|
||||
examples: EXAMPLE_CONTAINERS,
|
||||
requestBodies: REQUEST_BODY_CONTAINER
|
||||
},
|
||||
DEFINITIONS = {
|
||||
headers: 'headers',
|
||||
responses: 'responses',
|
||||
callbacks: 'callbacks',
|
||||
properties: 'schemas',
|
||||
links: 'links'
|
||||
},
|
||||
INLINE = [],
|
||||
ROOT_CONTAINERS_KEYS = [
|
||||
'components'
|
||||
],
|
||||
COMPONENTS_KEYS = [
|
||||
'schemas',
|
||||
'responses',
|
||||
'parameters',
|
||||
'examples',
|
||||
'requestBodies',
|
||||
'headers',
|
||||
'securitySchemes',
|
||||
'links',
|
||||
'callbacks'
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
RULES_30: {
|
||||
CONTAINERS,
|
||||
DEFINITIONS,
|
||||
COMPONENTS_KEYS,
|
||||
INLINE,
|
||||
ROOT_CONTAINERS_KEYS
|
||||
}
|
||||
};
|
||||
54
lib/bundleRules/spec31.js
Normal file
54
lib/bundleRules/spec31.js
Normal file
@@ -0,0 +1,54 @@
|
||||
const SCHEMA_CONTAINERS = [
|
||||
'allOf',
|
||||
'oneOf',
|
||||
'anyOf',
|
||||
'not',
|
||||
'additionalProperties',
|
||||
'items',
|
||||
'schema'
|
||||
],
|
||||
EXAMPLE_CONTAINERS = [
|
||||
'example'
|
||||
],
|
||||
REQUEST_BODY_CONTAINER = [
|
||||
'requestBody'
|
||||
],
|
||||
CONTAINERS = {
|
||||
schemas: SCHEMA_CONTAINERS,
|
||||
examples: EXAMPLE_CONTAINERS,
|
||||
requestBodies: REQUEST_BODY_CONTAINER
|
||||
},
|
||||
DEFINITIONS = {
|
||||
headers: 'headers',
|
||||
responses: 'responses',
|
||||
callbacks: 'callbacks',
|
||||
properties: 'schemas',
|
||||
links: 'links',
|
||||
paths: 'pathItems'
|
||||
},
|
||||
INLINE = [],
|
||||
ROOT_CONTAINERS_KEYS = [
|
||||
'components'
|
||||
],
|
||||
COMPONENTS_KEYS = [
|
||||
'schemas',
|
||||
'responses',
|
||||
'parameters',
|
||||
'examples',
|
||||
'requestBodies',
|
||||
'headers',
|
||||
'securitySchemes',
|
||||
'links',
|
||||
'callbacks',
|
||||
'pathItems'
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
RULES_31: {
|
||||
CONTAINERS,
|
||||
DEFINITIONS,
|
||||
COMPONENTS_KEYS,
|
||||
INLINE,
|
||||
ROOT_CONTAINERS_KEYS
|
||||
}
|
||||
};
|
||||
@@ -6,7 +6,9 @@ const VERSION_30 = { key: 'openapi', version: '3.0' },
|
||||
DEFAULT_SPEC_VERSION = VERSION_30.version,
|
||||
SWAGGER_VERSION = VERSION_20.version,
|
||||
VERSION_3_1 = VERSION_31.version,
|
||||
fs = require('fs');
|
||||
fs = require('fs'),
|
||||
{ RULES_30 } = require('./../bundleRules/spec30'),
|
||||
{ RULES_31 } = require('./../bundleRules/spec31');
|
||||
|
||||
/**
|
||||
* gets the version key and the version and generates a regular expression that
|
||||
@@ -268,6 +270,21 @@ function validateSupportedVersion(version) {
|
||||
return isValid !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bundling rules to follow in the bundling process
|
||||
* @param {string} version The spec version we are bundling
|
||||
* @returns {object} The bundling rules related with the spec
|
||||
*/
|
||||
function getBundleRulesDataByVersion(version) {
|
||||
const is31 = compareVersion(version, VERSION_31.version);
|
||||
if (is31) {
|
||||
return RULES_31;
|
||||
}
|
||||
else {
|
||||
return RULES_30;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getSpecVersion,
|
||||
getConcreteSchemaUtils,
|
||||
@@ -277,5 +294,6 @@ module.exports = {
|
||||
getVersionRegexBySpecificationVersion,
|
||||
SWAGGER_VERSION,
|
||||
VERSION_3_1,
|
||||
validateSupportedVersion
|
||||
validateSupportedVersion,
|
||||
getBundleRulesDataByVersion
|
||||
};
|
||||
|
||||
@@ -6,9 +6,11 @@ const slashes = /\//g,
|
||||
escapedTilde = /~0/g,
|
||||
jsonPointerLevelSeparator = '/',
|
||||
escapedTildeString = '~0',
|
||||
{ getKeyInComponents30 } = require('./30XUtils/componentsParentMatcher'),
|
||||
{ getKeyInComponents31 } = require('./31XUtils/componentsParentMatcher'),
|
||||
{ VERSION_3_1 } = require('./common/versionUtils');
|
||||
{ getBundleRulesDataByVersion } = require('./common/versionUtils'),
|
||||
{
|
||||
resolveFirstLevelChild,
|
||||
resolveSecondLevelChild
|
||||
} = require('./bundleRules/resolvers');
|
||||
|
||||
/**
|
||||
* Encodes a filepath name so it can be a json pointer
|
||||
@@ -51,15 +53,44 @@ function jsonPointerDecodeAndReplace(filePathName) {
|
||||
*/
|
||||
function getKeyInComponents(traceFromParent, filePathName, localPath, version) {
|
||||
const localPart = localPath ? `${localPointer}${localPath}` : '',
|
||||
is31 = version === VERSION_3_1;
|
||||
let result;
|
||||
{
|
||||
CONTAINERS,
|
||||
DEFINITIONS,
|
||||
COMPONENTS_KEYS,
|
||||
INLINE,
|
||||
ROOT_CONTAINERS_KEYS
|
||||
} = getBundleRulesDataByVersion(version);
|
||||
let result,
|
||||
trace = [
|
||||
...traceFromParent,
|
||||
jsonPointerDecodeAndReplace(`${filePathName}${localPart}`)
|
||||
].reverse(),
|
||||
traceToKey = [],
|
||||
matchFound = false,
|
||||
isRootAndReusableItemsContainer = ROOT_CONTAINERS_KEYS.includes(traceFromParent[0]);
|
||||
|
||||
if (is31) {
|
||||
result = getKeyInComponents31(traceFromParent, filePathName, localPart, jsonPointerDecodeAndReplace);
|
||||
if (isRootAndReusableItemsContainer) {
|
||||
return [];
|
||||
}
|
||||
else {
|
||||
result = getKeyInComponents30(traceFromParent, filePathName, localPart, jsonPointerDecodeAndReplace);
|
||||
|
||||
for (let [index, item] of trace.entries()) {
|
||||
let itemShouldBeResolvedInline = INLINE.includes(item);
|
||||
|
||||
if (itemShouldBeResolvedInline) {
|
||||
matchFound = false;
|
||||
break;
|
||||
}
|
||||
item = resolveFirstLevelChild(item, CONTAINERS);
|
||||
resolveSecondLevelChild(trace, index, DEFINITIONS);
|
||||
traceToKey.push(item);
|
||||
if (COMPONENTS_KEYS.includes(item)) {
|
||||
matchFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = matchFound ?
|
||||
traceToKey.reverse() :
|
||||
[];
|
||||
return result.map(generateObjectName);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user