Smarter route loading, more sensible folder names

This commit is contained in:
Timothy Warren 2014-09-22 09:59:44 -04:00
parent 3ec3efca0d
commit 6b025fa08c
33 changed files with 413 additions and 7 deletions

18
app.js
View File

@ -4,9 +4,14 @@ var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var requireDir = require('require-dir');
var app = express();
// General config
app.set('trust proxy', true); // Trust X-Forwarded-* headers
// view engine setup
var consolidate = require('consolidate');
var dust = require('dustjs-linkedin');
@ -23,10 +28,13 @@ app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public'), {redirect:false}));
// Route mapping
var routes = require('./routes/index');
var users = require('./routes/users');
app.use('/', routes);
app.use('/users', users);
var routes = requireDir('routes');
Object.keys(routes).forEach(function(route) {
var path = (route != 'index')
? '/' + route
: '/';
app.use(path, routes[route]);
});
// catch 404 and forward to error handler
app.use(function(req, res, next) {
@ -60,4 +68,4 @@ app.use(function(err, req, res, next) {
});
module.exports = app;
module.exports = app;

2
node_modules/require-dir/.npmignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
npm-debug.log
node_modules

108
node_modules/require-dir/README.md generated vendored Normal file
View File

@ -0,0 +1,108 @@
# requireDir()
Node helper to `require()` directories. The directory's files are examined,
and each one that can be `require()`'d is `require()`'d and returned as part
of a hash from that file's basename to its exported contents.
## Example
Given this directory structure:
```
dir
+ a.js
+ b.json
+ c.coffee
+ d.txt
```
`requireDir('./dir')` will return the equivalent of:
```js
{ a: require('./dir/a.js')
, b: require('./dir/b.json')
}
```
And if CoffeeScript was registered, `c.coffee` will also be returned.
## Installation
```
npm install require-dir
```
Note that this package is *not* `requireDir` turns out that's already
[taken](https://github.com/JamesEggers1/node-requiredir)! ;)
## Usage
Basic usage that examines only directories' immediate files:
```js
var requireDir = require('require-dir');
var dir = requireDir('./path/to/dir');
```
You can optionally customize the behavior by passing an extra options object:
```js
var dir = requireDir('./path/to/dir', {recurse: true});
```
## Options
`recurse`: Whether to recursively `require()` subdirectories too.
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
over files if `recurse` is true.) Specifying this option `require()`'s all
files and returns full filename keys in addition to basename keys.
Default is false.
E.g. in the example above, if there were also an `a.json`, the behavior would
be the same by default, but specifying `duplicates: true` would yield:
```js
{ a: require('./dir/a.js')
, 'a.js': require('./dir/a.js')
, 'a.json': require('./dir/a.json')
, b: require('./dir/b.json')
, 'b.json': require('./dir/b.json')
}
```
There might be more options in the future. ;)
## Tips
If you want to `require()` the same directory in multiple places, you can do
this in the directory itself! Just make an `index.js` file with the following:
```js
module.exports = require('require-dir')(); // defaults to '.'
```
And don't worry, the calling file is always ignored to prevent infinite loops.
## TODO
It'd be awesome if this could work with the regular `require()`, e.g. like a
regular `require()` hook. Not sure that's possible though; directories are
already special-cased to look for an `index` file or `package.json`.
An `ignore` option would be nice: a string or regex, or an array of either or
both, of paths, relative to the directory, to ignore. String paths can be
extensionless to ignore all extensions for that path. Supporting shell-style
globs in string paths would be nice.
Currently, basenames are derived for directories too — e.g. a directory named
`a.txt` will be returned as `a` when recursing — but should that be the case?
Maybe directories should always be returned by their full name, and/or maybe
this behavior should be customizable. This is hopefully an edge case.
## License
MIT. © 2012 Aseem Kishore.

120
node_modules/require-dir/index.js generated vendored Normal file
View File

@ -0,0 +1,120 @@
// 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 = {};
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 path = Path.resolve(dir, file);
// ignore the calling file:
if (path === parentFile) {
continue;
}
if (FS.statSync(path).isDirectory()) {
if (opts.recurse) {
map[base] = requireDir(path, opts);
// if duplicates are wanted, key off the full name too:
if (opts.duplicates) {
map[file] = map[base];
}
}
} else {
filesMinusDirs[file] = path;
}
}
// 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 in require.extensions) {
// again protect against enumerable object prototype extensions:
if (!require.extensions.hasOwnProperty(ext)) {
continue;
}
// if a file exists with this extension, we'll require() it:
var file = base + ext;
var path = filesMinusDirs[file];
if (path) {
// 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(path);
if (!map[base]) {
map[base] = map[file];
}
} else {
map[base] = require(path);
break;
}
}
}
}
return map;
};

48
node_modules/require-dir/package.json generated vendored Normal file
View File

@ -0,0 +1,48 @@
{
"name": "require-dir",
"description": "Helper to require() directories.",
"version": "0.1.0",
"author": {
"name": "Aseem Kishore",
"email": "aseem.kishore@gmail.com"
},
"dependencies": {},
"devDependencies": {
"coffee-script": "~1.3.3"
},
"engines": {
"node": "*"
},
"scripts": {
"test": "node test"
},
"homepage": "https://github.com/aseemk/requireDir",
"repository": {
"type": "git",
"url": "git://github.com/aseemk/requireDir.git"
},
"_npmUser": {
"name": "aseemk",
"email": "aseem.kishore@gmail.com"
},
"_id": "require-dir@0.1.0",
"optionalDependencies": {},
"_engineSupported": true,
"_npmVersion": "1.1.21",
"_nodeVersion": "v0.6.16",
"_defaultsLoaded": true,
"dist": {
"shasum": "81e01e299faf5b74c34b6594f8e5add5985ddec5",
"tarball": "http://registry.npmjs.org/require-dir/-/require-dir-0.1.0.tgz"
},
"maintainers": [
{
"name": "aseemk",
"email": "aseem.kishore@gmail.com"
}
],
"directories": {},
"_shasum": "81e01e299faf5b74c34b6594f8e5add5985ddec5",
"_from": "require-dir@",
"_resolved": "https://registry.npmjs.org/require-dir/-/require-dir-0.1.0.tgz"
}

43
node_modules/require-dir/test/duplicates.js generated vendored Normal file
View File

@ -0,0 +1,43 @@
var assert = require('assert');
var requireDir = require('..');
// first test without recursing *or* duplicates:
assert.deepEqual(requireDir('./duplicates'), {
a: 'a.js',
b: 'b.json',
d: 'd.js',
});
// then test with duplicates but without recursing:
assert.deepEqual(requireDir('./duplicates', {duplicates: true}), {
a: 'a.js',
'a.js': 'a.js',
b: 'b.json',
'b.json': 'b.json',
d: 'd.js',
'd.js': 'd.js',
'd.json': 'd.json',
});
// finally, test with duplicates while recursing:
assert.deepEqual(requireDir('./duplicates', {duplicates: true, recurse: true}), {
a: 'a.js',
'a.js': 'a.js',
b: {
'1': '1.js',
'1.js': '1.js',
'2': '2.js',
'2.js': '2.js',
'2.json': '2.json',
},
'b.json': 'b.json',
c: {
'3': '3.json',
'3.json': '3.json',
},
d: 'd.js',
'd.js': 'd.js',
'd.json': 'd.json',
});
console.log('Duplicate tests passed.');

1
node_modules/require-dir/test/duplicates/a.js generated vendored Normal file
View File

@ -0,0 +1 @@
module.exports = 'a.js';

1
node_modules/require-dir/test/duplicates/b.json generated vendored Normal file
View File

@ -0,0 +1 @@
"b.json"

1
node_modules/require-dir/test/duplicates/b/1.js generated vendored Normal file
View File

@ -0,0 +1 @@
module.exports = '1.js';

1
node_modules/require-dir/test/duplicates/b/1.txt generated vendored Normal file
View File

@ -0,0 +1 @@
'1.txt'

1
node_modules/require-dir/test/duplicates/b/2.js generated vendored Normal file
View File

@ -0,0 +1 @@
module.exports = '2.js';

1
node_modules/require-dir/test/duplicates/b/2.json generated vendored Normal file
View File

@ -0,0 +1 @@
"2.json"

1
node_modules/require-dir/test/duplicates/c.txt generated vendored Normal file
View File

@ -0,0 +1 @@
'c.txt'

1
node_modules/require-dir/test/duplicates/c/3.json generated vendored Normal file
View File

@ -0,0 +1 @@
"3.json"

1
node_modules/require-dir/test/duplicates/d.js generated vendored Normal file
View File

@ -0,0 +1 @@
module.exports = 'd.js';

1
node_modules/require-dir/test/duplicates/d.json generated vendored Normal file
View File

@ -0,0 +1 @@
"d.json"

2
node_modules/require-dir/test/index.js generated vendored Normal file
View File

@ -0,0 +1,2 @@
require('..')('.');
console.log('\nAll tests passed!');

24
node_modules/require-dir/test/recurse.js generated vendored Normal file
View File

@ -0,0 +1,24 @@
var assert = require('assert');
var requireDir = require('..');
// first test without recursing:
assert.deepEqual(requireDir('./recurse'), {
a: 'a',
});
// then test with recursing:
assert.deepEqual(requireDir('./recurse', {recurse: true}), {
a: 'a',
b: {
'1': {
foo: 'foo',
bar: 'bar',
},
'2': {} // note how the directory is always returned
},
c: {
'3': 3
},
});
console.log('Recurse tests passed.');

1
node_modules/require-dir/test/recurse/a.js generated vendored Normal file
View File

@ -0,0 +1 @@
module.exports = 'a';

1
node_modules/require-dir/test/recurse/b/1/bar.json generated vendored Normal file
View File

@ -0,0 +1 @@
"bar"

1
node_modules/require-dir/test/recurse/b/1/foo.js generated vendored Normal file
View File

@ -0,0 +1 @@
module.exports = 'foo';

1
node_modules/require-dir/test/recurse/b/2/baz.txt generated vendored Normal file
View File

@ -0,0 +1 @@
baz

1
node_modules/require-dir/test/recurse/c/3.json generated vendored Normal file
View File

@ -0,0 +1 @@
3

20
node_modules/require-dir/test/simple.js generated vendored Normal file
View File

@ -0,0 +1,20 @@
var assert = require('assert');
var requireDir = require('..');
// first test regularly:
assert.deepEqual(requireDir('./simple'), {
a: 'a',
b: 'b',
});
// now register CoffeeScript and do it again:
// note that CoffeeScript shouldn't be used by any other tests! we can't rely
// on ordering of tests, and require.extensions and require.cache are global.
require('coffee-script');
assert.deepEqual(requireDir('./simple'), {
a: 'a',
b: 'b',
c: 'c',
});
console.log('Simple tests passed.');

1
node_modules/require-dir/test/simple/a.js generated vendored Normal file
View File

@ -0,0 +1 @@
module.exports = 'a';

1
node_modules/require-dir/test/simple/b.json generated vendored Normal file
View File

@ -0,0 +1 @@
"b"

1
node_modules/require-dir/test/simple/c.coffee generated vendored Normal file
View File

@ -0,0 +1 @@
module.exports = 'c'

1
node_modules/require-dir/test/simple/d.txt generated vendored Normal file
View File

@ -0,0 +1 @@
d

File diff suppressed because one or more lines are too long

9
routes/tasks.js Normal file
View File

@ -0,0 +1,9 @@
var express = require('express');
var router = express.Router();
/* GET list of tasks */
router.get('/', function(req, res) {
res.json([{}]);
});
module.exports = router;

View File

@ -1,6 +1,6 @@
{>layout/}
{<content}
<h1>{title}</th>
<h1>{title}</h1>
<p>Welcome to {title}</p>
{/content}

View File

@ -2,7 +2,7 @@
<html>
<head>
<title>{title}</title>
<link rel='stylesheet' href='/stylesheets/style.css' />
<link rel='stylesheet' href='/css/style.css' />
</head>
<body>
{+content}
@ -12,4 +12,6 @@
<!--
{session}
-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="/js/native.history.js"></script>
</html>