mirror of
https://github.com/postmanlabs/openapi-to-postman.git
synced 2022-11-29 22:05:00 +03:00
homologate from multifile
This commit is contained in:
@@ -46,6 +46,16 @@ function parseFileOrThrow(fileContent) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 parseFile(fileContent) {
|
||||||
|
const result = parse.getOasObject(fileContent);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the path relative to parent
|
* Calculates the path relative to parent
|
||||||
* @param {string} parentFileName - parent file name of the current node
|
* @param {string} parentFileName - parent file name of the current node
|
||||||
@@ -269,13 +279,15 @@ function handleLocalCollisions(trace, initialMainKeys) {
|
|||||||
* @param {object} version - The version of the spec we are bundling
|
* @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
|
* @param {object} rootMainKeys - A dictionary with the component keys in local components object and its mainKeys
|
||||||
* @param {string} commonPathFromData - The common path in the file's paths
|
* @param {string} commonPathFromData - The common path in the file's paths
|
||||||
|
* @param {Array} allData - array of { path, content} objects
|
||||||
* @returns {object} - The references in current node and the new content from the node
|
* @returns {object} - The references in current node and the new content from the node
|
||||||
*/
|
*/
|
||||||
function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename, version, rootMainKeys,
|
function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename, version, rootMainKeys,
|
||||||
commonPathFromData) {
|
commonPathFromData, allData) {
|
||||||
let referencesInNode = [],
|
let referencesInNode = [],
|
||||||
nodeReferenceDirectory = {},
|
nodeReferenceDirectory = {},
|
||||||
mainKeys = {};
|
mainKeys = {};
|
||||||
|
|
||||||
traverseUtility(currentNode).forEach(function (property) {
|
traverseUtility(currentNode).forEach(function (property) {
|
||||||
if (property) {
|
if (property) {
|
||||||
let hasReferenceTypeKey;
|
let hasReferenceTypeKey;
|
||||||
@@ -306,10 +318,21 @@ function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename, ve
|
|||||||
return item !== undefined;
|
return item !== undefined;
|
||||||
}), this.key];
|
}), this.key];
|
||||||
let newValue,
|
let newValue,
|
||||||
[, local] = tempRef.split(localPointer);
|
[, local] = tempRef.split(localPointer),
|
||||||
|
nodeFromData,
|
||||||
|
refHasContent = false,
|
||||||
|
parseResult;
|
||||||
|
|
||||||
newValue = Object.assign({}, this.node);
|
newValue = Object.assign({}, this.node);
|
||||||
newValue.$ref = referenceInDocument;
|
nodeFromData = findNodeFromPath(tempRef, allData);
|
||||||
|
if (nodeFromData && nodeFromData.content) {
|
||||||
|
parseResult = parseFile(nodeFromData.content);
|
||||||
|
if (parseResult.result) {
|
||||||
|
newValue.$ref = referenceInDocument;
|
||||||
|
refHasContent = true;
|
||||||
|
nodeFromData.parsed = parseResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.update({ $ref: tempRef });
|
this.update({ $ref: tempRef });
|
||||||
|
|
||||||
@@ -320,7 +343,8 @@ function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename, ve
|
|||||||
reference: referenceInDocument,
|
reference: referenceInDocument,
|
||||||
traceToParent,
|
traceToParent,
|
||||||
parentNodeKey: parentFilename,
|
parentNodeKey: parentFilename,
|
||||||
mainKeyInTrace: nodeTrace[nodeTrace.length - 1]
|
mainKeyInTrace: nodeTrace[nodeTrace.length - 1],
|
||||||
|
refHasContent
|
||||||
};
|
};
|
||||||
|
|
||||||
mainKeys[componentKey] = tempRef;
|
mainKeys[componentKey] = tempRef;
|
||||||
@@ -348,13 +372,18 @@ function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename, ve
|
|||||||
function getNodeContentAndReferences (currentNode, allData, specRoot, version, rootMainKeys, commonPathFromData) {
|
function getNodeContentAndReferences (currentNode, allData, specRoot, version, rootMainKeys, commonPathFromData) {
|
||||||
let graphAdj = [],
|
let graphAdj = [],
|
||||||
missingNodes = [],
|
missingNodes = [],
|
||||||
nodeContent;
|
nodeContent,
|
||||||
|
parseResult;
|
||||||
|
|
||||||
if (currentNode.parsed) {
|
if (currentNode.parsed) {
|
||||||
nodeContent = currentNode.parsed.oasObject;
|
nodeContent = currentNode.parsed.oasObject;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
nodeContent = parseFileOrThrow(currentNode.content).oasObject;
|
parseResult = parseFile(currentNode.content);
|
||||||
|
if (parseResult.result === false) {
|
||||||
|
return { graphAdj, missingNodes, undefined, nodeReferenceDirectory: {}, nodeName: currentNode.fileName };
|
||||||
|
}
|
||||||
|
nodeContent = parseResult.oasObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { referencesInNode, nodeReferenceDirectory } = getReferences(
|
const { referencesInNode, nodeReferenceDirectory } = getReferences(
|
||||||
@@ -364,7 +393,8 @@ function getNodeContentAndReferences (currentNode, allData, specRoot, version, r
|
|||||||
currentNode.fileName,
|
currentNode.fileName,
|
||||||
version,
|
version,
|
||||||
rootMainKeys,
|
rootMainKeys,
|
||||||
commonPathFromData
|
commonPathFromData,
|
||||||
|
allData
|
||||||
);
|
);
|
||||||
|
|
||||||
referencesInNode.forEach((reference) => {
|
referencesInNode.forEach((reference) => {
|
||||||
@@ -404,12 +434,14 @@ function generateComponentsObject (documentContext, rootContent, refTypeResolver
|
|||||||
const { COMPONENTS_KEYS } = getBundleRulesDataByVersion(version);
|
const { COMPONENTS_KEYS } = getBundleRulesDataByVersion(version);
|
||||||
notInLine.forEach(([key, value]) => {
|
notInLine.forEach(([key, value]) => {
|
||||||
let [, partial] = key.split(localPointer);
|
let [, partial] = key.split(localPointer);
|
||||||
setValueInComponents(
|
if (documentContext.globalReferences[key].refHasContent) {
|
||||||
value.keyInComponents,
|
setValueInComponents(
|
||||||
components,
|
value.keyInComponents,
|
||||||
getContentFromTrace(documentContext.nodeContents[key], partial),
|
components,
|
||||||
COMPONENTS_KEYS
|
getContentFromTrace(documentContext.nodeContents[key], partial),
|
||||||
);
|
COMPONENTS_KEYS
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
[rootContent, components].forEach((contentData) => {
|
[rootContent, components].forEach((contentData) => {
|
||||||
traverseUtility(contentData).forEach(function (property) {
|
traverseUtility(contentData).forEach(function (property) {
|
||||||
@@ -429,12 +461,12 @@ function generateComponentsObject (documentContext, rootContent, refTypeResolver
|
|||||||
return missingNode.path === nodeRef;
|
return missingNode.path === nodeRef;
|
||||||
});
|
});
|
||||||
if (isMissingNode) {
|
if (isMissingNode) {
|
||||||
refData.nodeContent = {
|
refData.nodeContent = refData.node;
|
||||||
[tempRef]: 'This related node was not found in provided data'
|
|
||||||
};
|
|
||||||
refData.inline = true;
|
|
||||||
refData.local = false;
|
refData.local = false;
|
||||||
}
|
}
|
||||||
|
else if (!refData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
refData.nodeContent = documentContext.nodeContents[nodeRef];
|
refData.nodeContent = documentContext.nodeContents[nodeRef];
|
||||||
refData.inline = refData.keyInComponents.length === 0;
|
refData.inline = refData.keyInComponents.length === 0;
|
||||||
@@ -453,12 +485,14 @@ function generateComponentsObject (documentContext, rootContent, refTypeResolver
|
|||||||
}
|
}
|
||||||
this.update(refData.node);
|
this.update(refData.node);
|
||||||
if (!refData.inline) {
|
if (!refData.inline) {
|
||||||
setValueInComponents(
|
if (documentContext.globalReferences[tempRef].refHasContent) {
|
||||||
refData.keyInComponents,
|
setValueInComponents(
|
||||||
components,
|
refData.keyInComponents,
|
||||||
refData.nodeContent,
|
components,
|
||||||
COMPONENTS_KEYS
|
refData.nodeContent,
|
||||||
);
|
version
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,9 +96,11 @@ module.exports = {
|
|||||||
* @param {Object} options computed process options
|
* @param {Object} options computed process options
|
||||||
* @param {Object} files Files map
|
* @param {Object} files Files map
|
||||||
* @param {string} specificationVersion the string of the desired version
|
* @param {string} specificationVersion the string of the desired version
|
||||||
|
* @param {boolean} allowReadingFS wheter to allow reading content from file system
|
||||||
* @return {String} rootFile
|
* @return {String} rootFile
|
||||||
*/
|
*/
|
||||||
getRootFiles: function (input, inputValidation, options, files = {}, specificationVersion) {
|
getRootFiles: function (input, inputValidation, options, files = {}, specificationVersion,
|
||||||
|
allowReadingFS = true) {
|
||||||
let rootFilesArray = [],
|
let rootFilesArray = [],
|
||||||
filesPathArray = input.data,
|
filesPathArray = input.data,
|
||||||
origin = input.origin || '';
|
origin = input.origin || '';
|
||||||
@@ -114,7 +116,7 @@ module.exports = {
|
|||||||
if (!_.isEmpty(files)) {
|
if (!_.isEmpty(files)) {
|
||||||
file = files[path.resolve(filePath.fileName)];
|
file = files[path.resolve(filePath.fileName)];
|
||||||
}
|
}
|
||||||
else {
|
else if (allowReadingFS) {
|
||||||
file = fs.readFileSync(filePath.fileName, 'utf8');
|
file = fs.readFileSync(filePath.fileName, 'utf8');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4854,7 +4854,7 @@ module.exports = {
|
|||||||
bundledFile[key] = value;
|
bundledFile[key] = value;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else if (!_.isEmpty(contentAndComponents.components)) {
|
||||||
bundledFile.components = contentAndComponents.components;
|
bundledFile.components = contentAndComponents.components;
|
||||||
}
|
}
|
||||||
if (!format) {
|
if (!format) {
|
||||||
|
|||||||
@@ -643,15 +643,13 @@ class SchemaPack {
|
|||||||
path = pathBrowserify;
|
path = pathBrowserify;
|
||||||
OasResolverOptions.browser = true;
|
OasResolverOptions.browser = true;
|
||||||
}
|
}
|
||||||
if ('content' in input.data[0]) {
|
input.data.forEach((file) => {
|
||||||
input.data.forEach((file) => {
|
files[path.resolve(file.fileName)] = file.content ? file.content : '';
|
||||||
files[path.resolve(file.fileName)] = file.content ? file.content : '';
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
adaptedInput = schemaUtils.mapDetectRootFilesInputToGetRootFilesInput(input);
|
adaptedInput = schemaUtils.mapDetectRootFilesInputToGetRootFilesInput(input);
|
||||||
adaptedInput.origin = input.origin;
|
adaptedInput.origin = input.origin;
|
||||||
rootFiles = parse.getRootFiles(adaptedInput, concreteUtils.inputValidation, this.computedOptions, files,
|
rootFiles = parse.getRootFiles(adaptedInput, concreteUtils.inputValidation, this.computedOptions, files,
|
||||||
input.specificationVersion);
|
input.specificationVersion, false);
|
||||||
res = schemaUtils.mapGetRootFilesOutputToDetectRootFilesOutput(rootFiles, input.specificationVersion);
|
res = schemaUtils.mapGetRootFilesOutputToDetectRootFilesOutput(rootFiles, input.specificationVersion);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
"responses": {
|
"responses": {
|
||||||
"/responses.yaml": "This related node was not found in provided data"
|
"$ref": "./responses.yaml"
|
||||||
},
|
},
|
||||||
"schemas": {
|
"schemas": {
|
||||||
"Monster": {
|
"Monster": {
|
||||||
@@ -98,4 +98,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -657,8 +657,8 @@ describe('bundle files method - 3.0', function () {
|
|||||||
expect(JSON.stringify(JSON.parse(res.output.data[0].bundledContent), null, 2)).to.be.equal(expected);
|
expect(JSON.stringify(JSON.parse(res.output.data[0].bundledContent), null, 2)).to.be.equal(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should return a "/missing/node/path": NotProvided' +
|
it('Should return the not handled reference ($ref: ./responses.yaml) ' +
|
||||||
' in the place of a not providen node - local_references', async function () {
|
'in the place of a not provided node - local_references', async function () {
|
||||||
let contentRootFile = fs.readFileSync(localRefFolder + '/root.yaml', 'utf8'),
|
let contentRootFile = fs.readFileSync(localRefFolder + '/root.yaml', 'utf8'),
|
||||||
schemasIndex = fs.readFileSync(localRefFolder + '/schemas/index.yaml', 'utf8'),
|
schemasIndex = fs.readFileSync(localRefFolder + '/schemas/index.yaml', 'utf8'),
|
||||||
schemasClient = fs.readFileSync(localRefFolder + '/schemas/client.yaml', 'utf8'),
|
schemasClient = fs.readFileSync(localRefFolder + '/schemas/client.yaml', 'utf8'),
|
||||||
@@ -2060,6 +2060,156 @@ describe('bundle files method - 3.0', function () {
|
|||||||
expect(res.output.specification.version).to.equal('3.0');
|
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);
|
expect(JSON.stringify(JSON.parse(res.output.data[0].bundledContent), null, 2)).to.be.equal(expected);
|
||||||
});
|
});
|
||||||
|
it('should ignore reference when is empty content and no root is sent', async function () {
|
||||||
|
let input =
|
||||||
|
{
|
||||||
|
type: 'multiFile',
|
||||||
|
specificationVersion: '3.0',
|
||||||
|
bundleFormat: 'YAML',
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
path: 'hello.yaml',
|
||||||
|
content: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'openapi.yaml',
|
||||||
|
content: 'openapi: 3.0.0\n' +
|
||||||
|
'info:\n' +
|
||||||
|
' title: hello world\n' +
|
||||||
|
' version: 0.1.1\n' +
|
||||||
|
'paths:\n' +
|
||||||
|
' /hello:\n' +
|
||||||
|
' get:\n' +
|
||||||
|
' summary: get the hello\n' +
|
||||||
|
' responses:\n' +
|
||||||
|
' \'200\':\n' +
|
||||||
|
' description: sample des\n' +
|
||||||
|
' content:\n' +
|
||||||
|
' application/json:\n' +
|
||||||
|
' schema:\n' +
|
||||||
|
' $ref: ./hello.yaml\n'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
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(res.output.data[0].bundledContent).to.be.equal(input.data[1].content);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ignore reference when is empty content', async function () {
|
||||||
|
let input =
|
||||||
|
{
|
||||||
|
type: 'multiFile',
|
||||||
|
specificationVersion: '3.0',
|
||||||
|
bundleFormat: 'YAML',
|
||||||
|
rootFiles: [{ path: 'openapi.yaml' }],
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
path: 'hello.yaml',
|
||||||
|
content: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'openapi.yaml',
|
||||||
|
content: 'openapi: 3.0.0\n' +
|
||||||
|
'info:\n' +
|
||||||
|
' title: hello world\n' +
|
||||||
|
' version: 0.1.1\n' +
|
||||||
|
'paths:\n' +
|
||||||
|
' /hello:\n' +
|
||||||
|
' get:\n' +
|
||||||
|
' summary: get the hello\n' +
|
||||||
|
' responses:\n' +
|
||||||
|
' \'200\':\n' +
|
||||||
|
' description: sample des\n' +
|
||||||
|
' content:\n' +
|
||||||
|
' application/json:\n' +
|
||||||
|
' schema:\n' +
|
||||||
|
' $ref: ./hello.yaml\n'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
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(res.output.data[0].bundledContent).to.be.equal(input.data[1].content);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ignore reference when is invalid content', async function () {
|
||||||
|
let input =
|
||||||
|
{
|
||||||
|
type: 'multiFile',
|
||||||
|
specificationVersion: '3.0',
|
||||||
|
bundleFormat: 'YAML',
|
||||||
|
rootFiles: [{ path: 'openapi.yaml' }],
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
path: 'hello.yaml',
|
||||||
|
content: 'asd'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'openapi.yaml',
|
||||||
|
content: 'openapi: 3.0.0\n' +
|
||||||
|
'info:\n' +
|
||||||
|
' title: hello world\n' +
|
||||||
|
' version: 0.1.1\n' +
|
||||||
|
'paths:\n' +
|
||||||
|
' /hello:\n' +
|
||||||
|
' get:\n' +
|
||||||
|
' summary: get the hello\n' +
|
||||||
|
' responses:\n' +
|
||||||
|
' \'200\':\n' +
|
||||||
|
' description: sample des\n' +
|
||||||
|
' content:\n' +
|
||||||
|
' application/json:\n' +
|
||||||
|
' schema:\n' +
|
||||||
|
' $ref: ./hello.yaml\n'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
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(res.output.data[0].bundledContent).to.be.equal(input.data[1].content);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ignore reference when is invalid', async function () {
|
||||||
|
let input =
|
||||||
|
{
|
||||||
|
type: 'multiFile',
|
||||||
|
specificationVersion: '3.0',
|
||||||
|
bundleFormat: 'YAML',
|
||||||
|
rootFiles: [{ path: 'openapi.yaml' }],
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
path: 'openapi.yaml',
|
||||||
|
content: 'openapi: 3.0.0\n' +
|
||||||
|
'info:\n' +
|
||||||
|
' title: hello world\n' +
|
||||||
|
' version: 0.1.1\n' +
|
||||||
|
'paths:\n' +
|
||||||
|
' /hello:\n' +
|
||||||
|
' get:\n' +
|
||||||
|
' summary: get the hello\n' +
|
||||||
|
' responses:\n' +
|
||||||
|
' \'200\':\n' +
|
||||||
|
' description: sample des\n' +
|
||||||
|
' content:\n' +
|
||||||
|
' application/json:\n' +
|
||||||
|
' schema:\n' +
|
||||||
|
' $ref: ./hello.yaml\n'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
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(res.output.data[0].bundledContent).to.be.equal(input.data[0].content);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getReferences method when node does not have any reference', function() {
|
describe('getReferences method when node does not have any reference', function() {
|
||||||
@@ -2111,7 +2261,8 @@ describe('getReferences method when node does not have any reference', function(
|
|||||||
'the/parent/filename',
|
'the/parent/filename',
|
||||||
'3.0',
|
'3.0',
|
||||||
{},
|
{},
|
||||||
''
|
'',
|
||||||
|
[]
|
||||||
);
|
);
|
||||||
expect(result.nodeReferenceDirectory).to.be.an('object');
|
expect(result.nodeReferenceDirectory).to.be.an('object');
|
||||||
expect(Object.keys(result.nodeReferenceDirectory).length).to.equal(1);
|
expect(Object.keys(result.nodeReferenceDirectory).length).to.equal(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user