6
\$\begingroup\$

I'm currently working on a small application, as a learning exercise for a Javascript novice. I need to generate an object based on a folder structure. Here is an example of the folder structure:

RootFolder/FolderA/FolderB/FileA

RootFolder/FolderA/FolderB/FileB

RootFolder/FolderA/FolderB/FolderC/FileA

RootFolder/FolderA/FolderB/FolderC/FileB

The desired resulting object should have the following structure:

{
    RootFolder: {
        FolderA: {
            FolderB: {
                FileA: {},
                FileB: {},
                FolderC: {
                    FileA: {},
                    FileB: {}
                }
            }
        }
    }
};

So far I came up with the following code and it seems to be doing the job, but I'm concerned with 'eval' use and generally believe there is a more elegant way of doing it.

module.exports = {
  structure: function(structureArray) {
    var generatedObject = {};
    for (var i = 0; i < structureArray.length; i++) {
      var objectElements = '';
      var path = (structureArray[i].split('/')).filter(Boolean);
      for (var l = 0; l < path.length; l++) {
        if (objectElements.indexOf(path[l]) == -1 || path[l].length == 1) {
          objectElements += '["' + path[l] + '"]';
        }
        if (!(eval('generatedObject' + objectElements))) {
          eval('generatedObject' + objectElements + '= {}')
        }
      }
    }
    return generatedObject;
  }
};

structureArray contains full path strings as in the folder structure example above (e.g. 'RootFolder/FolderA/FolderB/FileA')

\$\endgroup\$
  • \$\begingroup\$ I would use paths delimited with dot . like this : ['RootFolder/FolderA/FolderB/FileA','RootFolder/FolderA/FolderB/FileB', '...'] and use _.set lodash.com/docs/4.17.4#set \$\endgroup\$ – Jan Osch Mar 17 '17 at 14:29
7
\$\begingroup\$

You can split each path at / using split and then use reduce() to build that object.

var paths = [
  'RootFolder/FolderA/FolderB/FileA',
  'RootFolder/FolderA/FolderB/FileB',
  'RootFolder/FolderA/FolderB/FolderC/FileA',
  'RootFolder/FolderA/FolderB/FolderC/FileB'
]

var obj = {}
paths.forEach(function(path) {
  path.split('/').reduce(function(r, e) {
    return r[e] || (r[e] = {})
  }, obj)
})

console.log(obj)

Here is how you can use this approach to read some directory and all of its nested content and create object from that. This approach is synchronous.

var fs = require('fs');
var path = require('path');

var p = path.resolve('C:\\your\\path\\here')
var result = {}

function buildObject(startPath) {
  var dir = fs.readdirSync(startPath)
  dir.forEach(function(e) {
    var newPath = path.join(startPath, e)

    var stat = fs.statSync(newPath);
    if (stat && stat.isDirectory()) buildObject(newPath)
    if (stat.isFile()) {
      newPath.split('\\').reduce(function(r, a) {
        return r[a] || (r[a] = {})
      }, result)
    }
  })
}

buildObject(p)
console.log(result)
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy