Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

transform file/directory structure into 'tree' in javascript

I have an array of objects that looks like this:

[{ name: 'test',
  size: 0,
  type: 'directory',
  path: '/storage/test' },
{ name: 'asdf',
  size: 170,
  type: 'directory',
  path: '/storage/test/asdf' },
{ name: '2.txt',
  size: 0,
  type: 'file',
  path: '/storage/test/asdf/2.txt' }]

There could be any number of arbitrary path's, this is the result of iterating through files and folders within a directory.

What I'm trying to do is determine the 'root' node of these. Ultimately, this will be stored in mongodb and use materialized path to determine it's relationships.

In this example, /storage/test is a root with no parent. /storage/test/asdf has the parent of /storage/test which is the parent to /storage/test/asdf/2.txt.

My question is, how would you go about iterating through this array, to determine the parent's and associated children? Any help in the right direction would be great!

Thank you

like image 543
dzm Avatar asked Oct 23 '13 01:10

dzm


People also ask

Is a directory a tree structure?

Structure. The directory is structured in the form of a tree. It also has a root directory, and every file in the system has a unique path. A directory within a tree-structured directory may contain files or subdirectories.

How do I display a directory tree?

You need to use command called tree. It will list contents of directories in a tree-like format. It is a recursive directory listing program that produces a depth indented listing of files. When directory arguments are given, tree lists all the files and/or directories found in the given directories each in turn.

What is a directory tree file?

A directory structure/system/tree is simply a layout of directories on your computer. Taking a big step back, the early computer designers realized that lumping together every single file on your computer would create a massive jumble and make it impossible to find anything. So they wisely created the directory.


2 Answers

You can do it like this:

var arr = [] //your array;
var tree = {};

function addnode(obj){
  var splitpath = obj.path.replace(/^\/|\/$/g, "").split('/');
  var ptr = tree;
  for (i=0;i<splitpath.length;i++)
  {
    node = { name: splitpath[i],
    type: 'directory'};
    if(i == splitpath.length-1)
    {node.size = obj.size;node.type = obj.type;}
    ptr[splitpath[i]] = ptr[splitpath[i]]||node;
    ptr[splitpath[i]].children=ptr[splitpath[i]].children||{};
    ptr=ptr[splitpath[i]].children;
  }    
}

arr.map(addnode);
console.log(require('util').inspect(tree, {depth:null}));

Output

{ storage:
   { name: 'storage',
     type: 'directory',
     children:
      { test:
         { name: 'test',
           type: 'directory',
           size: 0,
           children:
            { asdf:
               { name: 'asdf',
                 type: 'directory',
                 size: 170,
                 children: { '2.txt': { name: '2.txt', type: 'file', size: 0, children: {} } } } } } } } }
like image 173
user568109 Avatar answered Sep 21 '22 23:09

user568109


Assuming / will never show up in the list of files, something like this should work:

function treeify(files) {
  var path = require('path')

  files = files.reduce(function(tree, f) {
    var dir = path.dirname(f.path)

    if (tree[dir]) {
      tree[dir].children.push(f)
    } else {
      tree[dir] = { implied: true, children: [f] }
    }

    if (tree[f.path]) {
      f.children = tree[f.path].children
    } else {
      f.children = []
    }

    return (tree[f.path] = f), tree
  }, {})

  return Object.keys(files).reduce(function(tree, f) {
    if (files[f].implied) {
      return tree.concat(files[f].children)
    }

    return tree
  }, [])
}

It'll turn the array you mention in the question in to something like this:

[ { name: 'test',
    size: 0,
    type: 'directory',
    path: '/storage/test',
    children: 
     [ { name: 'asdf',
         size: 170,
         type: 'directory',
         path: '/storage/test/asdf',
         children: 
          [ { name: '2.txt',
              size: 0,
              type: 'file',
              path: '/storage/test/asdf/2.txt',
              children: [] } ] } ] } ]

I haven't actually tested this with any other data sources, so your milage may vary but at least it ought to nudge you in the right direction.

like image 23
Marcus Stade Avatar answered Sep 21 '22 23:09

Marcus Stade