123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- // requireDir.js
- // See README.md for details.
- var fs = require('fs');
- var path = require('path');
- // make a note of the calling file's path, so that we can resolve relative
- // paths. this only works if a fresh version of this module is run on every
- // require(), so important: we clear the require() cache each time!
- var parent = module.parent;
- var parentFile = parent.filename;
- var parentDir = path.dirname(parentFile);
- delete require.cache[__filename];
- module.exports = function requireDir(dir, opts) {
- // default arguments:
- dir = dir || '.';
- opts = opts || {};
- // resolve the path to an absolute one:
- dir = path.resolve(parentDir, dir);
- // read the directory's files:
- // note that this'll throw an error if the path isn't a directory.
- var files = fs.readdirSync(dir);
- // to prioritize between multiple files with the same basename, we'll
- // first derive all the basenames and create a map from them to files:
- var filesForBase = {};
- for (var i = 0; i < files.length; i++) {
- var file = files[i];
- var ext = path.extname(file);
- var base = path.basename(file, ext);
- (filesForBase[base] = filesForBase[base] || []).push(file);
- }
- // then we'll go through each basename, and first check if any of the
- // basenames' files are directories, since directories take precedence if
- // we're recursing and can be ignored if we're not. if a basename has no
- // directory, then we'll follow Node's own require() algorithm of going
- // through and trying the require.extension keys in order. in the process,
- // we create and return a map from basename to require()'d contents! and
- // if duplicates are asked for, we'll never short-circuit; we'll just add
- // to the map using the full filename as a key also.
- var map = {};
- // get the array of extensions we need to require
- var extensions = opts.extensions || Object.keys(require.extensions);
- for (var base in filesForBase) {
- // protect against enumerable object prototype extensions:
- if (!filesForBase.hasOwnProperty(base)) {
- continue;
- }
- // go through the files for this base and check for directories. we'll
- // also create a hash "set" of the non-dir files so that we can
- // efficiently check for existence in the next step:
- var files = filesForBase[base];
- var filesMinusDirs = {};
- for (var i = 0; i < files.length; i++) {
- var file = files[i];
- var abs = path.resolve(dir, file);
- // ignore the calling file:
- if (abs === parentFile) {
- continue;
- }
- // apply file filter:
- if (opts.filter && !opts.filter(abs)) {
- continue;
- }
- if (fs.statSync(abs).isDirectory()) {
- if (opts.recurse) {
- if (base === 'node_modules') {
- continue;
- }
- map[base] = requireDir(abs, opts);
- // if duplicates are wanted, key off the full name too:
- if (opts.duplicates) {
- map[file] = map[base];
- }
- }
- } else {
- filesMinusDirs[file] = abs;
- }
- }
- // if we're recursing and we already encountered a directory for this
- // basename, we're done for this base if we're ignoring duplicates:
- if (map[base] && !opts.duplicates) {
- continue;
- }
- // otherwise, go through and try each require.extension key!
- for (ext of extensions) {
- // if a file exists with this extension, we'll require() it:
- var file = base + ext;
- var abs = filesMinusDirs[file];
- if (abs) {
- // ignore TypeScript declaration files. They should never be
- // `require`d
- if (/\.d\.ts$/.test(abs)) {
- continue;
- }
- // delete cache
- if (opts.noCache) {
- delete require.cache[abs];
- }
- // if duplicates are wanted, key off the full name always, and
- // also the base if it hasn't been taken yet (since this ext
- // has higher priority than any that follow it). if duplicates
- // aren't wanted, we're done with this basename.
- if (opts.duplicates) {
- map[file] = require(abs);
- if (!map[base]) {
- map[base] = map[file];
- }
- } else {
- map[base] = require(abs);
- break;
- }
- }
- }
- }
- if (opts.mapKey || opts.mapValue) {
- for (var base in map) {
- // protect against enumerable object prototype extensions:
- if (!map.hasOwnProperty(base)) {
- continue;
- }
- var newKey = opts.mapKey ? opts.mapKey(map[base], base) : base;
- var newVal = opts.mapValue ? opts.mapValue(map[base], newKey) : map[base];
- delete map[base];
- map[newKey] = newVal;
- }
- }
- return map;
- };
|