Add dfs algorithm

Add dfs algorithm
This commit is contained in:
Luis Tejeda
2022-04-20 18:19:16 -05:00
committed by Erik Mendoza
parent 0b03a26d1c
commit 2fefe62dc1
8 changed files with 255 additions and 1 deletions

View File

@@ -37,6 +37,11 @@ module.exports = {
return schema.detectRootFiles();
},
detectRelatedFiles: async function(input) {
var schema = new SchemaPack(input);
return schema.detectRelatedFiles();
},
// new API
SchemaPack
};

26
lib/dfs.js Normal file
View File

@@ -0,0 +1,26 @@
class DFS {
traverse(node, getAdjacent) {
let traverseOrder = [],
stack = [],
missing = [],
visited = new Set();
stack.push(node);
while (stack.length > 0) {
node = stack.pop();
if (!visited.has(node)) {
traverseOrder.push(node);
visited.add(node);
let { graphAdj, missingNodes } = getAdjacent(node);
missing.push(...missingNodes);
for (let j = 0; j < graphAdj.length; j++) {
stack.push(graphAdj[j]);
}
}
}
return { traverseOrder, missing };
}
}
module.exports = {
DFS
};

26
lib/relatedFiles.js Normal file
View File

@@ -0,0 +1,26 @@
const { DFS } = require('./dfs');
/**
* Maps the output from get root files to detect root files
* @param {object} output - output schema
* @param {string} version - specified version of the process
* @returns {object} - Detect root files result object
*/
function getReferences () {
// obtener los refs => '../common/Error.yaml' //relative to root path
// obtener el file de data por path (puede que aqui sea absoluto)
// si no existe agregarlo a missing
// obtener el objeto
// agregarlo a un array (de nodos adjacentes)
//
return { graphAdj: [], missingNodes: [] };
}
module.exports = {
getRelatedFiles: function (specRoot) {
let algorithm = new DFS(),
orderTraversed = algorithm.traverse(specRoot, getReferences);
return orderTraversed;
}
};

View File

@@ -87,7 +87,8 @@ const { formatDataPath, checkIsCorrectType, isKnownType,
],
crypto = require('crypto'),
DEFAULT_SCHEMA_UTILS = require('./30XUtils/schemaUtils30X');
DEFAULT_SCHEMA_UTILS = require('./30XUtils/schemaUtils30X'),
{ getRelatedFiles } = require('./relatedFiles');
/* eslint-enable */
// See https://github.com/json-schema-faker/json-schema-faker/tree/master/docs#available-options
@@ -4842,6 +4843,35 @@ module.exports = {
data: adaptedData
}
};
},
mapRootFiles(rootFiles) {
let data = rootFiles.map((root) => {
let relatedFiles = getRelatedFiles();
return { rootFile: { path: root.path }, relatedFiles: relatedFiles };
});
return data;
},
processRelatedFiles(inputRelatedFiles) {
let version = inputRelatedFiles.specificationVersion ? inputRelatedFiles.specificationVersion : '3.0.0',
res = {
result: true,
output: {
type: 'relatedFiles',
specification: {
type: 'OpenAPI',
version: version
},
data: [
]
}
};
if (inputRelatedFiles.rootFiles && inputRelatedFiles.rootFiles.length > 0) {
res.output.data = this.mapRootFiles(inputRelatedFiles.rootFiles, version);
}
return res;
}
};

View File

@@ -652,6 +652,24 @@ class SchemaPack {
res = schemaUtils.mapGetRootFilesOutputToDetectRootFilesOutput(rootFiles, input.specificationVersion);
return res;
}
/**
*
* @description Takes in a folder and identifies the root files in that folder
* if there are different specification's versions will return only the ones that
* corresponds to the field specificationVersion
*
* @returns {object} root files information found in the input
*/
async detectRelatedFiles() {
const input = this.input;
if (!input.rootFiles || input.rootFiles.length === 0) {
let rootFiles = await this.detectRootFiles(input);
input.rootFiles = rootFiles.output.data;
return schemaUtils.processRelatedFiles(input);
}
return schemaUtils.processRelatedFiles(input);
}
}
module.exports = {

80
test/unit/DFS.test.js Normal file
View File

@@ -0,0 +1,80 @@
let expect = require('chai').expect,
{ DFS } = require('./../../lib/dfs');
describe('DFS Algorithm ', function () {
it('should return non repeated nodes', function () {
let algorithm = new DFS(),
d = {
name: 'd',
children: []
},
c = {
name: 'c',
children: []
},
b = {
name: 'b',
children: [c]
},
root = {
name: 'a',
children: [d, c, b]
},
{ traverseOrder, missing } = algorithm.traverse(root, (node) => {
return { graphAdj: node.children, missingNodes: [] };
});
expect(traverseOrder.length).to.equal(4);
expect(traverseOrder[0].name).to.equal('a');
expect(traverseOrder[1].name).to.equal('b');
expect(traverseOrder[2].name).to.equal('c');
expect(traverseOrder[3].name).to.equal('d');
expect(missing.length).to.equal(0);
});
it('should return non repeated nodes and missing nodes', function () {
let algorithm = new DFS(),
d = {
name: 'd',
children: []
},
c = {
name: 'c',
children: []
},
b = {
name: 'b',
children: ['c']
},
root = {
name: 'a',
children: ['d', 'c', 'b', 'e']
},
allData = [root, b, c, d],
{ traverseOrder, missing } = algorithm.traverse(root, (node) => {
let missing = [],
foundArray = [];
node.children.forEach((child) => {
let found = allData.find((item) => {
return child === item.name;
});
if (found) {
foundArray.push(found);
}
else {
missing.push(child);
}
});
return { graphAdj: foundArray, missingNodes: missing };
});
expect(traverseOrder.length).to.equal(4);
expect(traverseOrder[0].name).to.equal('a');
expect(traverseOrder[1].name).to.equal('b');
expect(traverseOrder[2].name).to.equal('c');
expect(traverseOrder[3].name).to.equal('d');
expect(missing.length).to.equal(1);
expect(missing[0]).to.equal('e');
});
});

View File

@@ -0,0 +1,59 @@
var expect = require('chai').expect,
Converter = require('../../index.js'),
fs = require('fs'),
path = require('path'),
VALID_OPENAPI_PATH = '../data/valid_openapi',
// VALID_OPENAPI_31_PATH = '../data/valid_openapi31X',
PET_STORE_SEPARATED = '../data/petstore separate yaml/spec',
// PET_STORE_SEPARATED_JSON = '../data/petstore-separate/spec',
validPetstore = path.join(__dirname, VALID_OPENAPI_PATH + '/petstore.yaml'),
// noauth = path.join(__dirname, VALID_OPENAPI_PATH + '/noauth.yaml'),
// petstoreSeparated = path.join(__dirname, PET_STORE_SEPARATED + '/swagger.yaml'),
petstoreSeparatedPet = path.join(__dirname, PET_STORE_SEPARATED + '/Pet.yaml');
// petstoreSeparatedJson = path.join(__dirname, PET_STORE_SEPARATED_JSON + '/swagger.json'),
// petstoreSeparatedPetJson = path.join(__dirname, PET_STORE_SEPARATED_JSON + '/Pet.json'),
// validHopService31x = path.join(__dirname, VALID_OPENAPI_31_PATH + '/yaml/hopService.yaml');
describe('detectRoot method', function() {
it('should return empty data when there is no root in the entry', async function() {
let contentFile = fs.readFileSync(petstoreSeparatedPet, 'utf8'),
input = {
type: 'folder',
specificationVersion: '3.0',
rootFiles: [
],
data: [
{
path: '/Pet.yaml',
content: contentFile
}
]
};
const res = await Converter.detectRelatedFiles(input);
expect(res).to.not.be.empty;
expect(res.result).to.be.true;
expect(res.output.data.length).to.equal(0);
});
it('should locate root and return empty data when there is no ref', async function() {
let contentFile = fs.readFileSync(validPetstore, 'utf8'),
input = {
type: 'folder',
specificationVersion: '3.0',
rootFiles: [
],
data: [
{
path: '/petstore.yaml',
content: contentFile
}
]
};
const res = await Converter.detectRelatedFiles(input);
expect(res).to.not.be.empty;
expect(res.result).to.be.true;
expect(res.output.data[0].rootFile.path).to.equal('/petstore.yaml');
});
});

View File

@@ -0,0 +1,10 @@
// let expect = require('chai').expect,
let { getRelatedFiles } = require('./../../lib/relatedFiles');
describe('Get header family function ', function () {
it('should check for custom type JSON header', function () {
getRelatedFiles();
});
});