Skip to content

Commit

Permalink
1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Contra committed Feb 7, 2018
1 parent 1da3990 commit 3d39752
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 82 deletions.
3 changes: 2 additions & 1 deletion .gitignore
@@ -1,2 +1,3 @@
npm-debug.log
node_modules
node_modules
package-lock.json
6 changes: 6 additions & 0 deletions CHANGELOG.md
@@ -0,0 +1,6 @@
## 1.0.0

- mapValue option added
- mapKey option added
- filter option added
- camelcase option removed, use mapKey to achieve the same functionality
34 changes: 25 additions & 9 deletions README.md
Expand Up @@ -28,7 +28,7 @@ dir
```

And if CoffeeScript has been registered via `require('coffee-script/register')`,
`c.coffee` will also be returned.
`c.coffee` will also be returned. Any extension registered with node will work the same way without any additional configuration.

## Installation

Expand Down Expand Up @@ -60,10 +60,6 @@ var dir = requireDir('./path/to/dir', {recurse: true});
(`node_modules` within subdirectories will be ignored.)
Default is false.

`camelcase`: Automatically add camelcase aliases for files with dash- and
underscore-separated names. E.g. `foo-bar.js` will be exposed under both the
original `'foo-bar'` name as well as a `'fooBar'` alias. Default is false.

`duplicates`: By default, if multiple files share the same basename, only the
highest priority one is `require()`'d and returned. (Priority is determined by
the order of `require.extensions` keys, with directories taking precedence
Expand All @@ -83,15 +79,35 @@ be the same by default, but specifying `duplicates: true` would yield:
}
```

`filter`: Apply a filter on the filename before require-ing. For example:
`filter`: Apply a filter on the filename before require-ing. For example, ignoring files prefixed with `dev` in a production environment:

```js
requiredir('./dir', function (f) { return process.env.NODE_ENV !== 'production' && !f.match(/$dev/); })
requireDir('./dir', {
filter: function (fullPath) {
return process.env.NODE_ENV !== 'production' && !fullPath.match(/$dev/);
}
})
```

This will ignore files prefixed with `dev` if running in a production environment.
`mapKey`: Apply a transform to the module base name after require-ing. For example, uppercasing any module names:

```js
requireDir('./dir', {
mapKey: function (value, baseName) {
return baseName.toUpperCase();
}
})
```

There might be more options in the future. ;)
`mapValue`: Apply a transform to the value after require-ing. For example, uppercasing any text exported:

```js
requireDir('./dir', {
mapValue: function (value, fileName) {
return typeof value === 'string' ? value.toUpperCase() : value;
}
})
```

## Tips

Expand Down
53 changes: 23 additions & 30 deletions index.js
@@ -1,40 +1,37 @@
// requireDir.js
// See README.md for details.

var FS = require('fs');
var Path = require('path');
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);
var parentDir = path.dirname(parentFile);
delete require.cache[__filename];

module.exports = function requireDir(dir, opts) {
// default arguments:
dir = dir || '.';
opts = opts || {};

opts.filter = opts.filter || function (file) { return true; };

// resolve the path to an absolute one:
dir = Path.resolve(parentDir, dir);
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);
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);

var ext = path.extname(file);
var base = path.basename(file, ext);
(filesForBase[base] = filesForBase[base] || []).push(file);
}

Expand Down Expand Up @@ -62,32 +59,32 @@ module.exports = function requireDir(dir, opts) {

for (var i = 0; i < files.length; i++) {
var file = files[i];
var path = Path.resolve(dir, file);
var abs = path.resolve(dir, file);

// ignore the calling file:
if (path === parentFile) {
if (abs === parentFile) {
continue;
}
// apply file filter:
if (!opts.filter(path)) {
if (opts.filter && !opts.filter(abs)) {
continue;
}

if (FS.statSync(path).isDirectory()) {
if (fs.statSync(abs).isDirectory()) {
if (opts.recurse) {
if (base === 'node_modules') {
continue;
}

map[base] = requireDir(path, opts);
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] = path;
filesMinusDirs[file] = abs;
}
}

Expand All @@ -107,12 +104,12 @@ module.exports = function requireDir(dir, opts) {

// if a file exists with this extension, we'll require() it:
var file = base + ext;
var path = filesMinusDirs[file];
var abs = filesMinusDirs[file];

if (path) {
if (abs) {
// ignore TypeScript declaration files. They should never be
// `require`d
if (/\.d\.ts$/.test(path)) {
if (/\.d\.ts$/.test(abs)) {
continue;
}

Expand All @@ -121,34 +118,30 @@ module.exports = function requireDir(dir, opts) {
// 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(path);
map[file] = require(abs);
if (!map[base]) {
map[base] = map[file];
}
} else {
map[base] = require(path);
map[base] = require(abs);
break;
}
}
}
}

if (opts.camelcase) {
if (opts.mapKey || opts.mapValue) {
for (var base in map) {
// protect against enumerable object prototype extensions:
if (!map.hasOwnProperty(base)) {
continue;
}

map[toCamelCase(base)] = map[base];
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;
};

function toCamelCase(str) {
return str.replace(/[_-][a-z]/ig, function (s) {
return s.substring(1).toUpperCase();
});
}
44 changes: 22 additions & 22 deletions package.json
@@ -1,24 +1,24 @@
{ "name": "require-dir"
, "description": "Helper to require() directories."
, "version": "0.3.2"
, "author": "Aseem Kishore <aseem.kishore@gmail.com>"
, "license": "MIT"
, "dependencies": {}
, "devDependencies":
{ "coffee-script": "~1.3.3"
, "mkdirp": "^0.5.0"
, "ts-node": "^1.3.0"
, "typescript": "^1.8.0"
}
, "engines":
{ "node": "*"
}
, "scripts":
{ "test": "node test"
}
, "homepage": "https://github.com/aseemk/requireDir"
, "repository":
{ "type": "git"
, "url": "git://github.com/aseemk/requireDir.git"
{
"name": "require-dir",
"description": "Helper to require() directories.",
"version": "1.0.0",
"author": "Aseem Kishore <aseem.kishore@gmail.com>",
"license": "MIT",
"dependencies": {},
"devDependencies": {
"coffee-script": "^1.3.3",
"ts-node": "^1.3.0",
"typescript": "^1.8.0"
},
"engines": {
"node": "*"
},
"scripts": {
"test": "node test"
},
"homepage": "https://github.com/aseemk/requireDir",
"repository": {
"type": "git",
"url": "git://github.com/aseemk/requireDir.git"
}
}
20 changes: 0 additions & 20 deletions test/camelcase.js

This file was deleted.

29 changes: 29 additions & 0 deletions test/mapKey.js
@@ -0,0 +1,29 @@
var assert = require('assert');
var requireDir = require('..');

var mapper = function(v, f) {
return f.toUpperCase();
};

// first test without recursing:
assert.deepEqual(requireDir('./recurse', { mapKey: mapper }), {
A: 'a',
});

// then test with recursing:
assert.deepEqual(requireDir('./recurse', { recurse: true, mapKey: mapper }), {
A: 'a',
B: {
'1': {
FOO: 'foo',
BAR: 'bar',
},
'2': {} // note how the directory is always returned
},
C: {
'3': 3
},
// note that node_modules was explicitly ignored
});

console.log('mapKey tests passed.');
30 changes: 30 additions & 0 deletions test/mapValue.js
@@ -0,0 +1,30 @@
var assert = require('assert');
var requireDir = require('..');

var mapper = function(v, f) {
if (typeof v === 'string') return v.toUpperCase();
return v;
};

// first test without recursing:
assert.deepEqual(requireDir('./recurse', { mapValue: mapper }), {
a: 'A',
});

// then test with recursing:
assert.deepEqual(requireDir('./recurse', { recurse: true, mapValue: mapper }), {
a: 'A',
b: {
'1': {
foo: 'FOO',
bar: 'BAR',
},
'2': {} // note how the directory is always returned
},
c: {
'3': 3
},
// note that node_modules was explicitly ignored
});

console.log('mapValue tests passed.');

2 comments on commit 3d39752

@aseemk
Copy link
Owner

@aseemk aseemk commented on 3d39752 Feb 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fantastic stuff! Thank you.

@yocontra
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aseemk Sent you an email

Please sign in to comment.