mirror of
https://github.com/postmanlabs/openapi-to-postman.git
synced 2022-11-29 22:05:00 +03:00
ignore invalid nodes
ignore invalid nodes
This commit is contained in:
1
bundled.json
Normal file
1
bundled.json
Normal file
@@ -0,0 +1 @@
|
||||
"{\"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\",\"parameters\":\"...\",\"responses\":{\"200\":{\"description\":\"A single user.\",\"content\":{\"application/json\":{\"schema\":{\"$ref\":\"#/components/schemas/User\"}}}},\"404\":{\"$ref\":\"#/components/responses/NotFound\"}}}},\"/users\":{\"get\":{\"summary\":\"Get all users\",\"responses\":{\"200\":{\"description\":\"A list of users.\",\"content\":{\"application/json\":{\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/components/schemas/User\"}}}}}}}}},\"components\":{\"responses\":{\"$ref\":\"./responses.yaml\"},\"schemas\":{\"Monster\":{\"type\":\"object\",\"properties\":{\"id\":{\"type\":\"integer\"},\"clientName\":{\"type\":\"string\"}}},\"User\":{\"type\":\"object\",\"properties\":{\"id\":{\"type\":\"integer\"},\"userName\":{\"type\":\"string\"}}},\"Toy\":{\"type\":\"object\",\"properties\":{\"id\":{\"type\":\"integer\"},\"toyName\":{\"type\":\"string\"}}}}}}"
|
||||
@@ -46,6 +46,16 @@ function parseFileOrThrow(fileContent) {
|
||||
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
|
||||
* @param {string} parentFileName - parent file name of the current node
|
||||
@@ -270,13 +280,15 @@ function handleLocalCollisions(trace, initialMainKeys) {
|
||||
* @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 {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
|
||||
*/
|
||||
function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename, version, rootMainKeys,
|
||||
commonPathFromData) {
|
||||
commonPathFromData, allData) {
|
||||
let referencesInNode = [],
|
||||
nodeReferenceDirectory = {},
|
||||
mainKeys = {};
|
||||
|
||||
traverseUtility(currentNode).forEach(function (property) {
|
||||
if (property) {
|
||||
let hasReferenceTypeKey;
|
||||
@@ -307,11 +319,21 @@ function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename, ve
|
||||
return item !== undefined;
|
||||
}), this.key];
|
||||
let newValue,
|
||||
[, local] = tempRef.split(localPointer);
|
||||
[, local] = tempRef.split(localPointer),
|
||||
nodeFromData,
|
||||
refHasContent = false,
|
||||
parseResult;
|
||||
|
||||
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 });
|
||||
|
||||
nodeReferenceDirectory[tempRef] = {
|
||||
@@ -321,7 +343,8 @@ function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename, ve
|
||||
reference: referenceInDocument,
|
||||
traceToParent,
|
||||
parentNodeKey: parentFilename,
|
||||
mainKeyInTrace: nodeTrace[nodeTrace.length - 1]
|
||||
mainKeyInTrace: nodeTrace[nodeTrace.length - 1],
|
||||
refHasContent
|
||||
};
|
||||
|
||||
mainKeys[componentKey] = tempRef;
|
||||
@@ -349,13 +372,18 @@ function getReferences (currentNode, isOutOfRoot, pathSolver, parentFilename, ve
|
||||
function getNodeContentAndReferences (currentNode, allData, specRoot, version, rootMainKeys, commonPathFromData) {
|
||||
let graphAdj = [],
|
||||
missingNodes = [],
|
||||
nodeContent;
|
||||
nodeContent,
|
||||
parseResult;
|
||||
|
||||
if (currentNode.parsed) {
|
||||
nodeContent = currentNode.parsed.oasObject;
|
||||
}
|
||||
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(
|
||||
@@ -365,7 +393,8 @@ function getNodeContentAndReferences (currentNode, allData, specRoot, version, r
|
||||
currentNode.fileName,
|
||||
version,
|
||||
rootMainKeys,
|
||||
commonPathFromData
|
||||
commonPathFromData,
|
||||
allData
|
||||
);
|
||||
|
||||
referencesInNode.forEach((reference) => {
|
||||
@@ -404,12 +433,14 @@ function generateComponentsObject (documentContext, rootContent, refTypeResolver
|
||||
});
|
||||
notInLine.forEach(([key, value]) => {
|
||||
let [, partial] = key.split(localPointer);
|
||||
setValueInComponents(
|
||||
value.keyInComponents,
|
||||
components,
|
||||
getContentFromTrace(documentContext.nodeContents[key], partial),
|
||||
version
|
||||
);
|
||||
if (documentContext.globalReferences[key].refHasContent) {
|
||||
setValueInComponents(
|
||||
value.keyInComponents,
|
||||
components,
|
||||
getContentFromTrace(documentContext.nodeContents[key], partial),
|
||||
version
|
||||
);
|
||||
}
|
||||
});
|
||||
[rootContent, components].forEach((contentData) => {
|
||||
traverseUtility(contentData).forEach(function (property) {
|
||||
@@ -429,12 +460,17 @@ function generateComponentsObject (documentContext, rootContent, refTypeResolver
|
||||
return missingNode.path === nodeRef;
|
||||
});
|
||||
if (isMissingNode) {
|
||||
refData.nodeContent = {
|
||||
[tempRef]: 'This related node was not found in provided data'
|
||||
};
|
||||
refData.inline = true;
|
||||
// refData.nodeContent = {
|
||||
// [tempRef]: 'This related node was not found in provided data'
|
||||
// };
|
||||
refData.nodeContent = refData.node;
|
||||
// refData.inline = true;
|
||||
this.update(refData.node);
|
||||
refData.local = false;
|
||||
}
|
||||
if (!refData) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
refData.nodeContent = documentContext.nodeContents[nodeRef];
|
||||
refData.inline = refData.keyInComponents.length === 0;
|
||||
@@ -451,14 +487,18 @@ function generateComponentsObject (documentContext, rootContent, refTypeResolver
|
||||
if (refData.inline) {
|
||||
refData.node = refData.nodeContent;
|
||||
}
|
||||
this.update(refData.node);
|
||||
if (!isMissingNode) {
|
||||
this.update(refData.node);
|
||||
}
|
||||
if (!refData.inline) {
|
||||
setValueInComponents(
|
||||
refData.keyInComponents,
|
||||
components,
|
||||
refData.nodeContent,
|
||||
version
|
||||
);
|
||||
if (documentContext.globalReferences[tempRef].refHasContent) {
|
||||
setValueInComponents(
|
||||
refData.keyInComponents,
|
||||
components,
|
||||
refData.nodeContent,
|
||||
version
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4848,7 +4848,9 @@ module.exports = {
|
||||
mapBundleOutput(format, parsedRootFiles) {
|
||||
return (contentAndComponents) => {
|
||||
let bundledFile = contentAndComponents.fileContent;
|
||||
bundledFile.components = contentAndComponents.components;
|
||||
if (!_.isEmpty(contentAndComponents.components)) {
|
||||
bundledFile.components = contentAndComponents.components;
|
||||
}
|
||||
if (!format) {
|
||||
let rootFormat = parsedRootFiles.find((inputRoot) => {
|
||||
return inputRoot.fileName === contentAndComponents.fileName;
|
||||
|
||||
@@ -644,11 +644,9 @@ class SchemaPack {
|
||||
path = pathBrowserify;
|
||||
OasResolverOptions.browser = true;
|
||||
}
|
||||
// if ('content' in input.data[0]) {
|
||||
input.data.forEach((file) => {
|
||||
files[path.resolve(file.fileName)] = file.content ? file.content : '';
|
||||
});
|
||||
// }
|
||||
adaptedInput = schemaUtils.mapDetectRootFilesInputToGetRootFilesInput(input);
|
||||
adaptedInput.origin = input.origin;
|
||||
rootFiles = parse.getRootFiles(adaptedInput, concreteUtils.inputValidation, this.computedOptions, files,
|
||||
|
||||
@@ -703,6 +703,8 @@ describe('bundle files method - 3.0', function () {
|
||||
|
||||
expect(res).to.not.be.empty;
|
||||
expect(res.result).to.be.true;
|
||||
fs.writeFileSync('bundled.json', JSON.stringify(res.output.data[0].bundledContent));
|
||||
|
||||
expect(JSON.stringify(JSON.parse(res.output.data[0].bundledContent), null, 2)).to.be.equal(expected);
|
||||
});
|
||||
|
||||
@@ -1938,43 +1940,6 @@ describe('bundle files method - 3.0', function () {
|
||||
});
|
||||
|
||||
|
||||
it('should ignore reference when is empty content', async function() {
|
||||
let input =
|
||||
{
|
||||
type: 'multiFile',
|
||||
specificationVersion: '3.0',
|
||||
bundleFormat: 'JSON',
|
||||
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\''
|
||||
}
|
||||
]
|
||||
};
|
||||
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');
|
||||
});
|
||||
|
||||
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'),
|
||||
@@ -2107,6 +2072,157 @@ describe('bundle files method - 3.0', function () {
|
||||
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 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);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2163,7 +2279,8 @@ describe('getReferences method when node does not have any reference', function(
|
||||
'the/parent/filename',
|
||||
'3.0',
|
||||
{},
|
||||
''
|
||||
'',
|
||||
[]
|
||||
);
|
||||
expect(result.nodeReferenceDirectory).to.be.an('object');
|
||||
expect(Object.keys(result.nodeReferenceDirectory).length).to.equal(1);
|
||||
|
||||
Reference in New Issue
Block a user