0

I have the following folder structure:

+---controllers | | index.js | | | +---api | | index.js | | test.js | | | \---routes | | index.js | | | \---partials | | index.js | | | +---bugs | +---compatibility | +---documentation | | amd.js | | api.js | | jquery.js | | options.js | | usage.js | | | \---installation 

I'm trying to create an object out of the tree that would look like this:

{ api: { index: require("index.js"), test: require("test.js") }, routes: { index: require("index.js"), partials: { index: require("index.js"), bugs: {}, compatibility: {}, documentation: { amd: require("amd.js"), api: require("api.js"), jquery: require("jquery.js"), options: require("options.js"), usage: require("usage.js") }, installation: {} } } } 

I just cannot figure the logic to do it, I've managed only to get an array of the tree with the following code:

/** * Controllers */ var path = require("path"), util = require("util"), fs = require("fs"), wrench = require("wrench"); var controllers = {}, tree = wrench.readdirSyncRecursive(path.resolve(__dirname, "./")).filter(function (value) { return value !== "index.js"; }); var key, i = tree.length - 1; while (i >= 0) { key = tree[i]; console.log(fs.lstatSync(path.resolve(__dirname, key)).isDirectory(), key.split(path.sep)); i--; } module.exports = controllers; 

I'm not really sure how I'm supposed to create the object after I start looping the folder tree, but I'm thinking that I could only do it if I have some recursive function ?

EDIT:

The reason why I'm trying to do it is because I'm trying to have some kind of dynamic routing for my express application.

In my express application I would have something like:

application.get("/api/index", controllers.api.index); application.get("/api/test", controllers.api.test); application.get("/", controllers.routes.index); application.get("/partials/", controllers.routes.partials.index); application.get("/partials/documentation/amd", controllers.routes.partials.documentation.amd); ... 

And each of those files would export something similar to:

exports.index = function (request, response) { return response.render("index"); }; 

Depending on where the file is and maybe with some more logic (in case there is a model that it has to load).

So probably there is a better way of managing dynamic routes than what I'm trying, if so I'm opened for suggestions.

2 Answers 2

4

I came up with a recursive file walker for your case.

var fs = require('fs'); var filetree = {}; var walkDirectory = function(path, obj) { var dir = fs.readdirSync(path); for (var i = 0; i < dir.length; i++) { var name = dir[i]; var target = path + '/' + name; var stats = fs.statSync(target); if (stats.isFile()) { if (name.slice(-3) === '.js') { obj[name.slice(0, -3)] = require(target); } } else if (stats.isDirectory()) { obj[name] = {}; walkDirectory(target, obj[name]); } } }; walkDirectory('./controllers', filetree); console.log(filetree); 

The function will scan the directory, and if the file is a script, then it will be loaded. If it is a directory, the function will pass the directory reference to itself and do the same thing again.

Sign up to request clarification or add additional context in comments.

2 Comments

Just tested it and it works just fine :) Just a few more things, is it possible to exclude the root index.js file ? The one that is on the same level as the routes & api ? Because the script that will walk will be in that index file. Also, each file uses exports.nameOfFunction to return the export function to the require. So all of the objects will have something like { api: { test: { test: function () { ... } } } } can we flatten the last two objects to one, so it ends up like: { api: { test: function () { ... } } } ?
If you don't want index.js, then add name !== 'index.js' as a condition to if (name.slice(-3) === '.js'). Also, the objects should already be flattened like so, since functions are supposed to be assigned to module.exports, not just exports.
0

You can achieve it by using this module:

npm dree

A result could be this:

{ "name": "sample", "path": "D:/Github/dree/test/sample", "relativePath": ".", "type": "directory", "size": "1.79 MB", "children": [ { "name": "backend", "path": "D:/Github/dree/test/sample/backend", "relativePath": "backend", "type": "directory", "size": "1.79 MB", "children": [ { "name": "firebase.json", "path": "D:/Github/dree/test/sample/backend/firebase.json", "relativePath": "backend/firebase.json", "type": "file", "extension": "json", "size": "29 B" }, { "name": "server", "path": "D:/Github/dree/test/sample/backend/server", "relativePath": "backend/server", "type": "directory", "size": "1.79 MB", "children": [ { "name": "server.ts", "path": "D:/Github/dree/test/sample/backend/server/server.ts", "relativePath": "backend/server/server.ts", "type": "file", "extension": "ts", "size": "1.79 MB" } ] } ] } ] } 

You can use it to get a structure which contains only the javascript files by using the extensions option. Then you only have to convert the obtained structure to the one you want.

This codesandbox has a solution (see the solution.js file):

Edit Setup Basic Node.js Server

You can also use the file and directory callback of dree, this is another codesandbox (see the solution.js file):

Edit Setup Basic Node.js Server

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.