Javascript File tree Problem Testing issue - javascript

Here is a part of an application that creates a file tree data structure from JSON input. However, there are one or more bugs in this code. It seems that for some data sets this code creates an incorrect tree structure.
'use strict';
function FileTreeNode(nodeId, name, type) {
const children = [];
this.nodeId = nodeId;
this.name = name;
this.type = type;
this.parentNode = null;
this.setParent = function(parentNode) {
this.parentNode = parentNode;
};
this.addChild = function(node){
if (this.type !== 'DIRECTORY') {
throw "Cannot add child node to a non-directory node";
}
else{
children.push(node);
node.setParent(this);
}
};
this.getChildren = function() {
return children;
};
};
function FileTree() {
this.nodes = [];
this.getRootNodes = function() {
const result = [];
for (let i = 0; i < this.nodes.length; i++) {
if (!this.nodes[i].parentNode) {
result.push(this.nodes[i]);
}
}
return result;
};
this.findNodeById = function(nodeId) {
for (let i = 0; i < this.nodes.length; i++) {
if (this.nodes[i].nodeId === nodeId) {
return this.nodes[i];
}
}
return null;
};
this.createNode = function(nodeId, name, type, parentNode) {
const node = new FileTreeNode(nodeId, name, type);
if (parentNode != null) {
parentNode.addChild(node);
}
this.nodes.push(node);
}
};
export function createFileTree(input) {
const fileTree = new FileTree();
const nodenotFound = (inputNodeId,input)=>{
let result = input.filter((item) => item.id == inputNodeId);
// const fileTree2 = new FileTree();
let node=fileTree.createNode(result[0].id, result[0].name, result[0].type,fileTree.findNodeById(result[0].parentId));
return node;
}
for (const inputNode of input) {
var parentNode = null;
if(inputNode.parentId != undefined){
if(fileTree.findNodeById(inputNode.parentId)!=null){
parentNode = fileTree.findNodeById(inputNode.parentId)
}
else{
parentNode= nodenotFound(inputNode.parentId,input)
}
}
else{
parentNode=null
}
fileTree.createNode(inputNode.id, inputNode.name, inputNode.type, parentNode);
}
return fileTree;
}
and my test file is as follows
'use strict';
import { createFileTree } from '../src/app'
const getDataset = file =>
require(`../src/dataset/${file}`)
describe('fileTree', function () {
var traverseTreeAndFindNode = function(inputNode, nodes) {
if (!nodes) {
return undefined;
}
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node.nodeId === inputNode.id) {
return node;
}
var nodeFoundAtChildren = traverseTreeAndFindNode(inputNode, node.getChildren());
if (nodeFoundAtChildren) {
return nodeFoundAtChildren;
}
}
return undefined;
};
function testTreeNode (inputNode, foundNode) {
it('tree node ' + inputNode.id + ' should have correct data', function() {
expect(foundNode.nodeId).toEqual(inputNode.id);
expect(foundNode.name).toEqual(inputNode.name);
expect(foundNode.type).toEqual(inputNode.type);
});
it('tree node ' + inputNode.id + ' should have correct parent', function () {
if (inputNode.parentId) {
expect(foundNode.parentNode).not.toBeNull();
expect(foundNode.parentNode.nodeId).toEqual(inputNode.parentId);
} else {
expect(foundNode.parentNode).toBeNull();
}
});
}
function testTreeContentsWithDataSet(dataSet) {
describe('created from ' + dataSet + ' dataSet', function() {
var inputData = getDataset(dataSet);
var fileTree = createFileTree(inputData);
for (var i = 0; i < inputData.length; i++) {
var inputNode = inputData[i];
var foundNode = traverseTreeAndFindNode(inputNode, fileTree.getRootNodes());
testTreeNode(inputNode, foundNode);
}
it('should contain all nodes from dataset', function () {
for (var i = 0; i < inputData.length; i++) {
expect(traverseTreeAndFindNode(inputData[i], fileTree.getRootNodes())).toBeDefined();
}
});
});
}
testTreeContentsWithDataSet('simple-data.json');
testTreeContentsWithDataSet('data-for-bug.json');
});
There are two JSON files used in the testing.
1.simple-data.json
[
{
"id": 877234010,
"name": "project",
"type": "DIRECTORY"
},
{
"id": 877234002,
"name": "src",
"type": "DIRECTORY",
"parentId": 877234010
},
{
"id": 877234003,
"name": "app",
"type": "DIRECTORY",
"parentId": 877234002
},
{
"id": 877234004,
"name": "app.js",
"type": "FILE",
"parentId": 877234003
}
]
the second one is data-for-bug.json
[
{
"id": 7832454551,
"name": "usr",
"type": "DIRECTORY"
},
{
"id": 7832454554,
"name": "applications",
"type": "DIRECTORY",
"parentId": 7832454553
},
{
"id": 7832454555,
"name": "mimeinfo.cache",
"type": "FILE",
"parentId": 7832454554
},
{
"id": 7832454553,
"name": "share",
"type": "DIRECTORY",
"parentId": 7832454552
},
{
"id": 7832454552,
"name": "local",
"type": "DIRECTORY",
"parentId": 7832454551
}
]
The result of the test run is
Using Jasmine version: 3.5.0
Started
............F...F...
Failures:
1) fileTree created from data-for-bug.json dataSet tree node 7832454554 should have correct parent
Message:
Expected null not to be null.
Stack:
Error: Expected null not to be null.
at <Jasmine>
at UserContext.<anonymous> (C:\Users\hp\Downloads\devskiller-code-PTQG-EEWG-46UW-S1F\test\/app.spec.js:39:42)
at <Jasmine>
Message:
TypeError: Cannot read property 'nodeId' of null
Stack:
at <Jasmine>
at UserContext.<anonymous> (C:\Users\hp\Downloads\devskiller-code-PTQG-EEWG-46UW-S1F\test\/app.spec.js:40:37)
at <Jasmine>
at processImmediate (internal/timers.js:464:21)
2) fileTree created from data-for-bug.json dataSet tree node 7832454553 should have correct parent
Message:
Expected null not to be null.
Stack:
Error: Expected null not to be null.
at <Jasmine>
at UserContext.<anonymous> (C:\Users\hp\Downloads\devskiller-code-PTQG-EEWG-46UW-S1F\test\/app.spec.js:39:42)
at <Jasmine>
Message:
TypeError: Cannot read property 'nodeId' of null
Stack:
at <Jasmine>
at UserContext.<anonymous> (C:\Users\hp\Downloads\devskiller-code-PTQG-EEWG-46UW-S1F\test\/app.spec.js:40:37)
at <Jasmine>
at processImmediate (internal/timers.js:464:21)
20 specs, 2 failures
Finished in 0.117 seconds
I couldn't notice what is wrong with the code.pls help

Related

Expand flat object into hierarchical structure

I'm trying to find best approach to expand this flat structure
var input = [
{
"path":"/",
"size":1111
},
{
"path":"/test1",
"size":2222
},
{
"path":"/test1/folder2",
"size":3333
},
{
"path":"/test1/folder2",
"size":4444
},
{
"path":"/test7/folder1",
"size":5555
}
]
into this hierarchical structure
var expectedoutput = [{
"path": "/",
"size": 1111
},
{
"path": "/test1",
"size": 2222,
"items": [{
"path": "/test1/folder2",
"size": 3333,
},
{
"path": "/test1/folder2",
"size": 4444
}
]
},
{
"path": "/test7",
"items": [{
"path": "/test7/folder1",
"size": 5555
}]
}
]
Any ideas? please.
Not so bad approach, it work's but there is one scenario which it cannot handle
Scenario when parent node doesn't exists (should be created) i've commented this part.
Updated version with missing intermediate paths support
function expand_object(list) {
var map = {}, node, roots = [], i;
for (i = 0; i < list.length; i += 1) {
map[list[i].path] = i; // map
list[i].items = []; // place for children
}
for (i = 0; i < list.length; i += 1) {
node = list[i];
//find parent, example "path":"test1/folder2" parent= "test1"
var lastSlash = node.path.lastIndexOf('/');
if (lastSlash > 1) {
lastSlash = lastSlash == -1 ? node.path.length : lastSlash;
parentNode = node.path.substring(0, lastSlash);
}
else {
parentNode = "/";
}
if (parentNode !== "/") {
// creat missing nodes
if (!list[map[parentNode]]) {
list.push({ "name": parentNode ,"path": parentNode, "items": [] })
map[list[list.length-1].path] = list.length-1;
}
var c = list[map[parentNode]];
list[map[parentNode]].items.push(node);
} else {
roots.push(node);
}
}
return roots;
}
var input = [
{
"path":"/",
"size":1111
},
{
"path":"/",
"size":2222
},
{
"path":"/test1",
"size":2222
},
{
"path":"/test1/folder2",
"size":3333
},
{
"path":"/test1/folder2",
"size":4444
}
,
{ //Missing node
"path":"/test7/folder1",
"size":5555
}
]
console.log(expand_object(input));

Function to build a line to retrieve data from json

I'm writing a function that takes arguments and add them to form a line to look for data in a JSON file. I've defined a variable for the readFileSync and the add to it the arguments of the function to look for the data.
var jf = require('jsonfile'),
file = 'logins.json',
i = 1;
var jsonData = jf.readFileSync(file);
function getJSONData() {
var n = 1;
var com = '';
do {
if (arguments[n] !== undefined) {
com += `['${arguments[n]}']`;
}
n++;
} while (n < arguments.length);
return com;
}
var h = getJSONData(i, 'operator', 'id');
console.log(jsonData[i] + h);
This is my JSON:
[
{
"operator": {
"id": "avalle",
"pass": "Aa123456",
"something": "idk",
"account": [
{
"type": "asd",
"idk": "asd"
},
{
"type": "asd",
"idk": "asd"
}
]
}
},
{
"operator": {
"id": "oleal",
"pass": "Aa123456",
"something": "idk",
"account": [
{
"type": "asd",
"idk": "asd"
},
{
"type": "asd",
"idk": "asd"
}
]
}
}
]
I should get a line of jsonData[i]['param1']['param2'] that locates the data in the file.
Instead i get undefined or [object Object]['operador']['id']
If you want a property to be returned from the function you can make this change:
function getJSONData(jsonData) {
var n = 1;
var result = jsonData;
do {
if (result[arguments[n]]) {
result = result[arguments[n]]
} else {
console.error(`Property ${arguments[n]} does not exist on obj:`, result)
}
n++;
} while (n < arguments.length);
return result;
}
var h = getJSONData(jsonData[i], 'operator', 'id');
Otherwise you return a string from getJSONData that looks like "[prop1][prop2]" and it will not retrieve a property by trying to concat Object + string

How to get an JSON Object based in key using jquery

I'm using jsTree and have tree an structured JSON object.
[{
"id": 1,
"text": "TEXT_ONE",
"children": [
{
"id": 2,
"text": "TEXT_TWO",
"children": [
{
"id": 3,
"text": "TEXT_THREE",
"children": [
]
},
{
"id": 4,
"text": "TEXT_FOUR",
"children": [
]
}
]
},
{
"id": 5,
"text": "TEXT_FIVE",
"children": [
]
}
]
},
{
"id": 6,
"text": "TEXT_SIX",
"children": [ ]
}]
I want to get the the object based on the "id" of the object.
For example if i have a function getIdFromTree(3) it will return me the JSON object as following:
{
"id": 3,
"text": "TEXT_THREE",
"children": []
},
How I do that in Javascript/JQuery?
Try this
function getObjById (tree, id) {
if(tree.id === id) {
return tree;
}
if(tree.children) {
for(var i = 0, l = tree.children.length; i < l; i++) {
var returned = getObjById(tree.children[i], id);
if(returned) {
// so that the loop doesn't keep running even after you find the obj
return returned;
}
}
}
}
Call this as follows
getObjById({children: tree}, 3); // tree is the array object above.
function findById (tree, id) {
var result, i;
if (tree.id && tree.id === id) {
result = tree;
// Revalidate array list
} else if (tree.length) {
for (i = 0; i < tree.length; i++) {
result = findById(tree[i], id);
if (result) {
break;
}
}
// Check childrens
} else if (tree.children) {
result = findById(tree.children, id);
}
return result;
}
Use filter Methode off Array
data.filter(function (obj){ obj.id== 3});
try this.... Es6
function *getObjectById(data, id) {
if (!data) return;
for (let i = 0; i< data.length; i++){
let val = data[i];
if (val.id === id) yield val;
if (val.children) yield *getObjectById(val.children , id);
}
}
now
getObjectById(arrayOfObjects, id).next().value;
try this with most effective and efficient way..
function getObjById (tree, id) {
for(var i= 0;i<tree.length;i++)
{
if(tree[i].id===id)
{
return tree[i];
}
if(tree[i].children)
{
var returned = getObjById(tree[i].children,id);
if(returned!= undefined)
return returned;
}
}
};
link:
https://jsfiddle.net/aa7zyyof/14/

Recursive function in node.js using q library

I need to prepare JSON by fetching the data from MYSQL. I have data in MYSQl in tree structure. I am trying to make recursive function to prepare JSON to meet the requirement but getting errors, I have following two files
main.js
/* jshint node: true */
"use strict";
var db = require('./helpers/db');
var list_worker = require('./workers/list');
var Q = require("q");
module.exports = function (app) {
/**
* return the profiles list
*/
app.get('/api/lists/get_list_tree_by_user/:user_id', function (req, res) {
list_worker.fetch_list_tree(req.params.user_id, 0).done(function (out) {
console.log(out);
res.send(out);
});
});
};
list.js
/* jshint node: true */
"use strict";
var db = require('../helpers/db');
var Q = require("q");
var output = {
data: []
};
var fetch_list_tree = function (user_id, list_id) {
// prepare query to fetch lists assosiated with a user.
var query = "SELECT b.`id`, b.`name` FROM `lists_users` a JOIN `lists` b ON(a.`list_id` = b.`id`) WHERE a.`user_id` = " + user_id + " AND a.`user_role` = 'owner' AND b.`parent_id` = " + list_id + " AND b.`deleted` = 'N';";
return db.query(query).then(function (result) {
if (result.length > 0) {
var lists = result.map(function (list, index) {
output.data[index] = {
label: list.name,
data: {
id: list.id
}
};
return fetch_list_tree(user_id, list.id).then(function (leaf_childs) {
output.data[index].children = [];
output.data[index].children.push(leaf_childs);
return leaf_childs;
});
});
return Q.all(lists).then(function (data) {
return output;
}, function (err) {
throw err;
});
} else {
return [];
}
}, function (err) {
throw err;
});
};
module.exports = {
fetch_list_tree: fetch_list_tree
};
data in database I am having is
item 1
item 1.1
item 1.1.1
item 2
Output I want
{
"label": "item 1",
"data": {
"id": "1"
},
"children": [{
"label": "item 1.1",
"data": {
"id": "2"
},
"children": [{
"label": "item 1.1.1",
"data": {
"id": "3"
},
"children": []
}]
}]
}
I am getting the following error
TypeError: Converting circular structure to JSON
Try change this.fetch_list_tree to exports.fetch_list_tree.
this != module.exports on line 28 => undefined

Change key name in nested JSON structure

I have a JSON data structure as shown below:
{
"name": "World",
"children": [
{ "name": "US",
"children": [
{ "name": "CA" },
{ "name": "NJ" }
]
},
{ "name": "INDIA",
"children": [
{ "name": "OR" },
{ "name": "TN" },
{ "name": "AP" }
]
}
]
};
I need to change the key names from "name" & "children" to say "key" & "value". Any suggestion on how to do that for each key name in this nested structure?
I don't know why you have a semicolon at the end of your JSON markup (assuming that's what you've represented in the question), but if that's removed, then you can use a reviver function to make modifications while parsing the data.
var parsed = JSON.parse(myJSONData, function(k, v) {
if (k === "name")
this.key = v;
else if (k === "children")
this.value = v;
else
return v;
});
DEMO: http://jsfiddle.net/BeSad/
Try this:
function convert(data){
return {
key: data.name,
value: data.children.map(convert);
};
}
Or if you need to support older browsers without map:
function convert(data){
var children = [];
for (var i = 0, len = data.children.length; i < len; i++){
children.push(convert(data.children[i]));
}
return {
key: data.name,
value: children
};
}
You could use a function like this :
function clonerename(source) {
if (Object.prototype.toString.call(source) === '[object Array]') {
var clone = [];
for (var i=0; i<source.length; i++) {
clone[i] = goclone(source[i]);
}
return clone;
} else if (typeof(source)=="object") {
var clone = {};
for (var prop in source) {
if (source.hasOwnProperty(prop)) {
var newPropName = prop;
if (prop=='name') newPropName='key';
else if (prop=='children') newPropName='value';
clone[newPropName] = clonerename(source[prop]);
}
}
return clone;
} else {
return source;
}
}
var B = clonerename(A);
Note that what you have isn't a JSON data structure (this doesn't exist as JSON is a data-exchange format) but probably an object you got from a JSON string.

Categories