8
\$\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\$
1
  • \$\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 Grz Mar 17 '17 at 14:29
10
\$\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)
\$\endgroup\$
3
  • \$\begingroup\$ sorry my ignorance, but how could remove the "file.jpg": {}, when it is a file \$\endgroup\$ – Vitor Hugo Sep 22 '20 at 22:25
  • 1
    \$\begingroup\$ @VitorHugo You can replace the return line with this return r[e] || (e.indexOf(".")==-1?(r[e] = {}):r[e]="") but beware, you'll have to handle this while reading. \$\endgroup\$ – Shivam Sharma Oct 4 '20 at 6:54
  • \$\begingroup\$ @ShivamSharma no and what I'm looking for, your solution just exchanged brackets for quotes, what I'm trying to and remove the brackets from the files, convert the files into simple value, thanks for trying to help me. - prnt.sc/usvfyh \$\endgroup\$ – Vitor Hugo Oct 4 '20 at 12:12

Your Answer

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