# Don't include root directory in HTML tree

I've written a function to create an HTML tree from JSON.

async function traverseTree (list, node) {
const li = document.createElement('li')
if (node.kids) {
const
ul = document.createElement('ul'),
span = document.createElement('span')
span.innerText = node.name
li.appendChild(span)
li.appendChild(ul)
list.appendChild(li)
for (const kid of node.kids) {
traverse(ul, kid)
}
return list
}
li.innerText = node.name
list.appendChild(li)
return list
}

;(async function(){
const
list = document.createElement('ul'),
output = await traverseTree(list, tree)
console.log(output)
})()


The issue is that I don't want to display the root node in the HTML tree since it is already displayed elsewhere, therefore I modified the code to exclude it.

async function traverseTree (list, node, isNotRoot) { // additional parameter
const li = document.createElement('li')
if (node.kids) {
let ul = list                                     // now let
if (isNotRoot) {                                  // additional conditional
const span = document.createElement('span')
ul = document.createElement('ul')               // additional assignment of value
span.innerText = node.name
li.appendChild(span)
li.appendChild(ul)
list.appendChild(li)
}
for (const kid of node.kids) {
traverseTree(ul, kid, true)                     // additional argument
}
return list
}
li.innerText = node.name
list.appendChild(li)
return list
}


Let's separate it by responsibilities into renderKids, renderName, traverseTree so that:

1. the main function can start explicitly from where you want
2. functions become immutable, free of side-effects
3. less repeated code
4. a single return is used
5. hopefully, the intent and flow become more obvious
function renderTree(json) {

function renderKids(kids) {
const ul = document.createElement('ul');
for (const kid of kids) {
ul.appendChild(traverseTree(kid))
}
return ul;
}

function renderName(name) {
const span = document.createElement('span');
span.textContent = name;
return span;
}

function traverseTree(node) {
const li = document.createElement('li');
if (node.kids) {
li.appendChild(renderName(node.name));
li.appendChild(renderKids(node.kids));
} else {
li.textContent = node.name;
}
return li;
}

return renderKids(json.kids || []);
}


Usage: const output = renderTree(await readJson('./tree.json'))

Note, traverseTree is not asynchronous so there's no need for async keyword.

• Modularizing code makes everything better. – SpeedOfRound Nov 8 '19 at 20:58
• why not make the function asynchronous? – oldboy Nov 12 '19 at 22:37
• man, although your code is cleaner, its wayyy harder to follow the logic, partly due to the fact that the names youve chosen for your nested functions are misnomers in certain contexts – oldboy Nov 12 '19 at 22:49
• and theres issues using your code because it treats the top level folders no differently than children folders – oldboy Nov 12 '19 at 22:57
• I can't agree. The code became so simple compared to the original spaghetti with side effects that "way harder" is an obvious exaggeration. The rest of your comments feels like a needless nitpicking and exaggeration as well. As for the "it treats the top level folders no differently", even without seeing the actual data I can't agree as it doesn't render the node name of the root which in my understanding was the entire point of the question. Anyway, this code was an example. – wOxxOm Nov 13 '19 at 4:14