1'use strict'; 2 3var fs = require('fs'), 4 join = require('path').join, 5 resolve = require('path').resolve, 6 dirname = require('path').dirname, 7 defaultOptions = { 8 extensions: ['js', 'json', 'coffee'], 9 recurse: true, 10 rename: function (name) { 11 return name; 12 }, 13 visit: function (obj) { 14 return obj; 15 } 16 }; 17 18function checkFileInclusion(path, filename, options) { 19 return ( 20 // verify file has valid extension 21 (new RegExp('\\.(' + options.extensions.join('|') + ')$', 'i').test(filename)) && 22 23 // if options.include is a RegExp, evaluate it and make sure the path passes 24 !(options.include && options.include instanceof RegExp && !options.include.test(path)) && 25 26 // if options.include is a function, evaluate it and make sure the path passes 27 !(options.include && typeof options.include === 'function' && !options.include(path, filename)) && 28 29 // if options.exclude is a RegExp, evaluate it and make sure the path doesn't pass 30 !(options.exclude && options.exclude instanceof RegExp && options.exclude.test(path)) && 31 32 // if options.exclude is a function, evaluate it and make sure the path doesn't pass 33 !(options.exclude && typeof options.exclude === 'function' && options.exclude(path, filename)) 34 ); 35} 36 37function requireDirectory(m, path, options) { 38 var retval = {}; 39 40 // path is optional 41 if (path && !options && typeof path !== 'string') { 42 options = path; 43 path = null; 44 } 45 46 // default options 47 options = options || {}; 48 for (var prop in defaultOptions) { 49 if (typeof options[prop] === 'undefined') { 50 options[prop] = defaultOptions[prop]; 51 } 52 } 53 54 // if no path was passed in, assume the equivelant of __dirname from caller 55 // otherwise, resolve path relative to the equivalent of __dirname 56 path = !path ? dirname(m.filename) : resolve(dirname(m.filename), path); 57 58 // get the path of each file in specified directory, append to current tree node, recurse 59 fs.readdirSync(path).forEach(function (filename) { 60 var joined = join(path, filename), 61 files, 62 key, 63 obj; 64 65 if (fs.statSync(joined).isDirectory() && options.recurse) { 66 // this node is a directory; recurse 67 files = requireDirectory(m, joined, options); 68 // exclude empty directories 69 if (Object.keys(files).length) { 70 retval[options.rename(filename, joined, filename)] = files; 71 } 72 } else { 73 if (joined !== m.filename && checkFileInclusion(joined, filename, options)) { 74 // hash node key shouldn't include file extension 75 key = filename.substring(0, filename.lastIndexOf('.')); 76 obj = m.require(joined); 77 retval[options.rename(key, joined, filename)] = options.visit(obj, joined, filename) || obj; 78 } 79 } 80 }); 81 82 return retval; 83} 84 85module.exports = requireDirectory; 86module.exports.defaults = defaultOptions; 87