mirror of
https://github.com/postmanlabs/openapi-to-postman.git
synced 2022-11-29 22:05:00 +03:00
Resolving properties as a reusable component
Resolve each property as a different schema instead of inline
This commit is contained in:
72
lib/30XUtils/componentsParentMatcher.js
Normal file
72
lib/30XUtils/componentsParentMatcher.js
Normal file
@@ -0,0 +1,72 @@
|
||||
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'
|
||||
];
|
||||
|
||||
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 (PROPERTY_DEFINITION.includes(trace[index + 2])) {
|
||||
trace[index + 1] = 'schemas';
|
||||
}
|
||||
traceToKey.push(item);
|
||||
if (COMPONENTS_KEYS_30.includes(item)) {
|
||||
matchFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return matchFound ?
|
||||
traceToKey.reverse() :
|
||||
[];
|
||||
},
|
||||
COMPONENTS_KEYS_30
|
||||
};
|
||||
@@ -6,10 +6,12 @@ const {
|
||||
removeLocalReferenceFromPath,
|
||||
localPointer,
|
||||
jsonPointerLevelSeparator,
|
||||
isLocalRef
|
||||
isLocalRef,
|
||||
jsonPointerDecodeAndReplace
|
||||
} = require('./jsonPointer'),
|
||||
traverseUtility = require('traverse'),
|
||||
parse = require('./parse.js');
|
||||
parse = require('./parse.js'),
|
||||
{ ParseError } = require('./common/ParseError');
|
||||
|
||||
let path = require('path'),
|
||||
pathBrowserify = require('path-browserify'),
|
||||
@@ -40,6 +42,18 @@ function comparePaths(path1, path2) {
|
||||
return path1 === path2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a node content or throw ParseError if there's any error
|
||||
* @param {string} fileContent The content from the current node
|
||||
* @returns {object} The parsed content
|
||||
*/
|
||||
function parseFileOrThrow(fileContent) {
|
||||
const result = parse.getOasObject(fileContent);
|
||||
if (result.result === false) {
|
||||
throw new ParseError(result.reason);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the path relative to parent
|
||||
@@ -136,7 +150,9 @@ function getContentFromTrace(content, partial) {
|
||||
return content;
|
||||
}
|
||||
partial = partial[0] === jsonPointerLevelSeparator ? partial.substring(1) : partial;
|
||||
const trace = partial.split(jsonPointerLevelSeparator);
|
||||
const trace = partial.split(jsonPointerLevelSeparator).map((item) => {
|
||||
return jsonPointerDecodeAndReplace(item);
|
||||
});
|
||||
let currentValue = content;
|
||||
currentValue = deref._getEscaped(content, trace, undefined);
|
||||
return currentValue;
|
||||
@@ -196,8 +212,8 @@ function getTraceFromParentKeyInComponents(nodeContext, property) {
|
||||
[key, ...parentKeys],
|
||||
nodeTrace = getRootFileTrace(nodeParentsKey),
|
||||
[file, local] = property.split(localPointer),
|
||||
[keyTraceInComponents, inComponents] = getKeyInComponents(nodeTrace, file, local);
|
||||
return [keyTraceInComponents, inComponents];
|
||||
keyTraceInComponents = getKeyInComponents(nodeTrace, file, local);
|
||||
return keyTraceInComponents;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,7 +243,7 @@ function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename) {
|
||||
);
|
||||
if (hasReferenceTypeKey) {
|
||||
const tempRef = calculatePath(parentFilename, property.$ref),
|
||||
[nodeTrace] = getTraceFromParentKeyInComponents(this, tempRef),
|
||||
nodeTrace = getTraceFromParentKeyInComponents(this, tempRef),
|
||||
referenceInDocument = getJsonPointerRelationToRoot(
|
||||
jsonPointerEncodeAndReplace,
|
||||
tempRef,
|
||||
@@ -281,7 +297,7 @@ function getNodeContentAndReferences (currentNode, allData, specRoot) {
|
||||
nodeContent = currentNode.parsed.oasObject;
|
||||
}
|
||||
else {
|
||||
nodeContent = parse.getOasObject(currentNode.content).oasObject;
|
||||
nodeContent = parseFileOrThrow(currentNode.content).oasObject;
|
||||
}
|
||||
|
||||
const { referencesInNode, nodeReferenceDirectory } = getReferences(
|
||||
@@ -321,6 +337,17 @@ function getNodeContentAndReferences (currentNode, allData, specRoot) {
|
||||
* @returns {object} The components object related to the file
|
||||
*/
|
||||
function generateComponentsObject (documentContext, rootContent, refTypeResolver, components) {
|
||||
let notInLine = Object.entries(documentContext.globalReferences).filter(([, value]) => {
|
||||
return value.keyInComponents.length !== 0;
|
||||
});
|
||||
notInLine.forEach(([key, value]) => {
|
||||
let [, partial] = key.split('#');
|
||||
setValueInComponents(
|
||||
value.keyInComponents,
|
||||
components,
|
||||
getContentFromTrace(documentContext.nodeContents[key], partial)
|
||||
);
|
||||
});
|
||||
[rootContent, components].forEach((contentData) => {
|
||||
traverseUtility(contentData).forEach(function (property) {
|
||||
if (property) {
|
||||
@@ -375,6 +402,22 @@ function generateComponentsObject (documentContext, rootContent, refTypeResolver
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the components object wrapper
|
||||
* @param {object} parsedOasObject The parsed root
|
||||
* @param {string} version - The current version
|
||||
* @returns {object} The components object wrapper
|
||||
*/
|
||||
function generateComponentsWrapper(parsedOasObject) {
|
||||
let components = {};
|
||||
|
||||
if (parsedOasObject.hasOwnProperty('components')) {
|
||||
components = parsedOasObject.components;
|
||||
}
|
||||
|
||||
return components;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Takes in an spec root file and an array of data files
|
||||
@@ -396,14 +439,18 @@ module.exports = {
|
||||
rootContextData = algorithm.traverseAndBundle(specRoot, (currentNode) => {
|
||||
return getNodeContentAndReferences(currentNode, allData, specRoot);
|
||||
});
|
||||
if (specRoot.parsed.oasObject.hasOwnProperty('components')) {
|
||||
components = specRoot.parsed.oasObject.components;
|
||||
}
|
||||
generateComponentsObject(rootContextData, rootContextData.nodeContents[specRoot.fileName], isExtRef, components);
|
||||
components = generateComponentsWrapper(specRoot.parsed.oasObject);
|
||||
generateComponentsObject(
|
||||
rootContextData,
|
||||
rootContextData.nodeContents[specRoot.fileName],
|
||||
isExtRef,
|
||||
components
|
||||
);
|
||||
return {
|
||||
fileContent: rootContextData.nodeContents[specRoot.fileName],
|
||||
components
|
||||
};
|
||||
},
|
||||
getReferences
|
||||
getReferences,
|
||||
parseFileOrThrow
|
||||
};
|
||||
|
||||
@@ -6,26 +6,7 @@ const slashes = /\//g,
|
||||
escapedTilde = /~0/g,
|
||||
jsonPointerLevelSeparator = '/',
|
||||
escapedTildeString = '~0',
|
||||
COMPONENTS_KEYS = [
|
||||
'schemas',
|
||||
'responses',
|
||||
'parameters',
|
||||
'examples',
|
||||
'requestBodies',
|
||||
'headers',
|
||||
'securitySchemes',
|
||||
'links',
|
||||
'callbacks'
|
||||
],
|
||||
SCHEMA_PARENT_KEYS_IN_DOC = [
|
||||
'allOf',
|
||||
'oneOf',
|
||||
'anyOf',
|
||||
'not',
|
||||
'additionalProperties',
|
||||
'items',
|
||||
'schema'
|
||||
];
|
||||
{ getKeyInComponents30 } = require('./30XUtils/componentsParentMatcher');
|
||||
|
||||
/**
|
||||
* Encodes a filepath name so it can be a json pointer
|
||||
@@ -52,49 +33,14 @@ function jsonPointerDecodeAndReplace(filePathName) {
|
||||
* @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} version - The current spec version
|
||||
* @returns {Array} - the calculated keys in an array representing each nesting property name
|
||||
*/
|
||||
function getKeyInComponents(traceFromParent, filePathName, localPath) {
|
||||
const localPart = localPath ? `${localPointer}${localPath}` : '';
|
||||
let res = traceFromParent,
|
||||
trace = [],
|
||||
traceToKey = [],
|
||||
matchFound = false,
|
||||
inComponents = false;
|
||||
|
||||
if (traceFromParent[0] === 'components') {
|
||||
inComponents = true;
|
||||
return [[], inComponents];
|
||||
}
|
||||
|
||||
res.push(jsonPointerDecodeAndReplace(`${filePathName}${localPart}`));
|
||||
trace = [...res].reverse();
|
||||
|
||||
for (let item of trace) {
|
||||
if (SCHEMA_PARENT_KEYS_IN_DOC.includes(item)) {
|
||||
item = 'schemas';
|
||||
}
|
||||
traceToKey.push(item);
|
||||
if (COMPONENTS_KEYS.includes(item)) {
|
||||
matchFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return [matchFound ?
|
||||
traceToKey.reverse() :
|
||||
[], inComponents];
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the local path of a pointer #/definitions/dog etc.
|
||||
* @param {string} jsonPointer the complet pointer
|
||||
* @returns {string} - the calculated key
|
||||
*/
|
||||
function getLocalPath(jsonPointer) {
|
||||
if (jsonPointer.includes(localPointer)) {
|
||||
return jsonPointer.split(localPointer)[1];
|
||||
}
|
||||
return '';
|
||||
let result;
|
||||
result = getKeyInComponents30(traceFromParent, filePathName, localPart, jsonPointerDecodeAndReplace);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,13 +48,14 @@ function getLocalPath(jsonPointer) {
|
||||
* @constructor
|
||||
* @param {Function} encodeFunction function to encode url
|
||||
* @param {string} traceFromParent the trace from parent.
|
||||
* @param {string} targetInRoot - The root element where we will point
|
||||
* @returns {string} - the concatenated json pointer
|
||||
*/
|
||||
function concatJsonPointer(encodeFunction, traceFromParent) {
|
||||
function concatJsonPointer(encodeFunction, traceFromParent, targetInRoot) {
|
||||
const traceFromParentAsString = traceFromParent.map((trace) => {
|
||||
return encodeFunction(trace);
|
||||
}).join('/');
|
||||
return localPointer + '/components' + jsonPointerLevelSeparator + traceFromParentAsString;
|
||||
return localPointer + targetInRoot + jsonPointerLevelSeparator + traceFromParentAsString;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,14 +64,15 @@ function concatJsonPointer(encodeFunction, traceFromParent) {
|
||||
* @param {Function} encodeFunction function to encode url
|
||||
* @param {string} refValue the type of component e.g. schemas, parameters, etc.
|
||||
* @param {string} traceFromKey the trace from the parent node.
|
||||
* @param {string} version - The version we are working on
|
||||
* @returns {string} - the concatenated json pointer
|
||||
*/
|
||||
function getJsonPointerRelationToRoot(encodeFunction, refValue, traceFromKey) {
|
||||
let targetInRoot = '/components';
|
||||
if (refValue.startsWith(localPointer)) {
|
||||
return refValue;
|
||||
}
|
||||
const localPath = getLocalPath(refValue);
|
||||
return concatJsonPointer(encodeFunction, traceFromKey, localPath);
|
||||
return concatJsonPointer(encodeFunction, traceFromKey, targetInRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -92,7 +92,7 @@ const { formatDataPath, checkIsCorrectType, isKnownType } = require('./common/sc
|
||||
{ getRelatedFiles } = require('./relatedFiles'),
|
||||
{ compareVersion } = require('./common/versionUtils.js'),
|
||||
parse = require('./parse'),
|
||||
{ getBundleContentAndComponents } = require('./bundle.js'),
|
||||
{ getBundleContentAndComponents, parseFileOrThrow } = require('./bundle.js'),
|
||||
MULTI_FILE_API_TYPE_ALLOWED_VALUE = 'multiFile';
|
||||
/* eslint-enable */
|
||||
|
||||
@@ -4884,7 +4884,7 @@ module.exports = {
|
||||
mapProcessRelatedFiles(rootFiles, inputData, origin, version, format, toBundle = false) {
|
||||
let bundleFormat = format,
|
||||
parsedRootFiles = rootFiles.map((rootFile) => {
|
||||
let parsedContent = this.parseFileOrThrow(rootFile.content);
|
||||
let parsedContent = parseFileOrThrow(rootFile.content);
|
||||
return { fileName: rootFile.fileName, content: rootFile.content, parsed: parsedContent };
|
||||
}).filter((rootWithParsedContent) => {
|
||||
bundleFormat = bundleFormat ? bundleFormat : rootWithParsedContent.parsed.inputFormat;
|
||||
@@ -4968,13 +4968,5 @@ module.exports = {
|
||||
throw new Error('"Path" of the data element should be provided');
|
||||
}
|
||||
},
|
||||
|
||||
parseFileOrThrow(fileContent) {
|
||||
const result = parse.getOasObject(fileContent);
|
||||
if (result.result === false) {
|
||||
throw new ParseError(result.reason);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
MULTI_FILE_API_TYPE_ALLOWED_VALUE
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user