Synchrone method with two option, simple and efficacy.
const path = require('path');const fs = require('fs'); function toHierarchie_files(pathDir, output_normalize=false, removeEmpty=true) { var result = {}, enqueue = [pathDir]; //normalize slash separator if output_normalize is true or just return val output_normalize = output_normalize == false?val => {return val}:val => {return path.normalize(val)}; //allows absolute or relative path with extended resolution. Returns path normalize absolute to work with or 'none' string. const path_exist = (path_test) => {var tmpTab = fs.existsSync(path.normalize(path.resolve(path_test))) == true?[path.normalize(path.resolve(path_test))]:['', '../', '../../'].map(val => path.normalize(path.resolve(__dirname, val+path_test))).filter((val, index) => fs.existsSync(path.normalize(path.resolve(__dirname, val+path_test))) == true);return tmpTab.length > 0?tmpTab[0]:'none'}; //Check if file exist and return her type or 'none' string const getType = (path_test) => {path_test = path_exist(path_test);return path_test == 'none'?'none':fs.lstatSync(path_test).isDirectory() == true?'dir':fs.lstatSync(path_test).isFile() == true?'file':'none';}; function recursive() { //init new entrie var parentDir = enqueue.pop();result[parentDir]=[]; //read dir fs.readdirSync(path_exist(parentDir)).forEach((file, index) =>{ switch(getType(parentDir+'/'+file)) { //if detect dir push in queue case 'dir': enqueue.push(output_normalize(parentDir+'/'+file)); break; //if file, add in entrie case 'file': result[parentDir].push(file); break; //else done default: break; }; }); //if optional arg remove empty is true, delete entries if not contains files if(result[parentDir].length == 0 && removeEmpty == true){Reflect.deleteProperty(result, parentDir);} //if queue is not empty continue processing if(enqueue.length > 0){recursive();} }; //if dir renseign exist, go recusive if(getType(pathDir) == 'dir'){recursive();} return result; };
Result:
{ "public/assets": [ "favicon.ico" ], "public/assets/js": [ "dede.js", "test.js" ], "public/assets/js/css/secure": [ "config.json", "index.js" ], "public/assets/css": [ "style.css" ]
}