Skip to content

Commit 32822cf

Browse files
authored
Merge branch 'master' into patch-1
2 parents fb2913f + a995cb4 commit 32822cf

22 files changed

+1667
-29
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
logs
33
*.log
44
npm-debug.log*
5+
.DS_Store
56

67
# Coverage directory used by tools like istanbul
78
coverage

README.md

+38
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Use the FS as your micro router
33
[![Build Status](https://travis-ci.org/jesseditson/fs-router.svg?branch=master)](https://travis-ci.org/jesseditson/fs-router)
44
[![Coverage Status](https://coveralls.io/repos/github/jesseditson/fs-router/badge.svg?branch=master)](https://coveralls.io/github/jesseditson/fs-router?branch=master)
5+
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
56

67
### "features"
78

@@ -121,3 +122,40 @@ module.exports.GET = async function(req, res) {
121122
// This works for deep paths (/thing/index.js maps to /thing and /thing/index)
122123
// and even for params (/thing/:param/index.js maps to /thing/* and /thing/*/index).
123124
```
125+
126+
**filter routes**
127+
```javascript
128+
// index.js
129+
const { send } = require('micro')
130+
131+
// set up config to filter only paths including `foo`
132+
const config = {filter: f => f.indexOf('foo') !== -1}
133+
134+
// pass config to `fs-router` as optional second paramater
135+
let match = require('fs-router')(__dirname + '/routes', config)
136+
137+
module.exports = async function(req, res) {
138+
let matched = match(req)
139+
if (matched) return await matched(req, res)
140+
send(res, 404, { error: 'Not found' })
141+
}
142+
```
143+
144+
The above usage assumes you have a folder called `routes` next to the `index.js` file, that looks something like this:
145+
```
146+
routes/
147+
├── foo
148+
│ ├── index.js
149+
│ └── thing.js
150+
└── bar
151+
├── index.js
152+
├── foo.js
153+
└── thing.js
154+
```
155+
156+
the above tree would generate the following routes:
157+
```
158+
/foo
159+
/foo/thing
160+
/bar/foo
161+
```

index.js

+17-14
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@ const path = require('path')
22
const fs = require('fs')
33
const qs = require('querystring')
44

5-
// create global paramPattern but define it in the router to allow custom char for parameterized routes
6-
let paramPattern
5+
6+
const paramPattern = /:([^\/%]+)/
77

88
// takes routes and decorates them with a 'match' method that will return { params, query } if a path matches
9-
function addMatch(route) {
9+
function addMatch (route) {
1010
let routePath = route.path
1111
let paramNames = []
1212
let matched
1313
// find any paths prefixed with a `:`, and treat them as capture groups
14-
while (matched = routePath.match(paramPattern)) {
15-
routePath = routePath.replace(paramPattern, '([^\?\/]+)')
14+
while ((matched = routePath.match(paramPattern)) !== null) {
15+
routePath = routePath.replace(paramPattern, '([^?/]+)')
1616
paramNames.push(matched[1])
1717
}
1818
// if a route ends with `index`, allow matching that route without matching the `index` part
1919
if (path.basename(routePath) === 'index') {
2020
route.isIndex = true
21-
routePath = routePath.replace(/\/index$/, '\/?(:?index)?')
21+
routePath = routePath.replace(/\/index$/, '/?(:?index)?')
2222
}
2323
// create a regex with our path
2424
let pattern = new RegExp(`^${routePath}(\\?(.*)|$)`, 'i')
@@ -38,7 +38,7 @@ function addMatch(route) {
3838
}
3939

4040
// recursively searches for all js files inside a directory tree, and returns their full paths
41-
function findRoutes(dir) {
41+
function findRoutes (dir) {
4242
let files = fs.readdirSync(dir)
4343
let resolve = f => path.join(dir, f)
4444
let routes = files.filter(f => path.extname(f) === '.js').map(resolve)
@@ -48,19 +48,22 @@ function findRoutes(dir) {
4848

4949
const val = v => (typeof v === 'undefined' ? 0 : v)
5050

51-
// allow user to define a custom character for parameterized routes, using ':' as a default
52-
module.exports = function router(routesDir, paramChar = ':') {
53-
paramPattern = new RegExp(`${paramChar}([^\/]+)`);
54-
51+
module.exports = function router (routesDir, config) {
52+
5553
const routes = findRoutes(routesDir)
54+
// if filter function is set, filter routes
55+
.filter(config && config.filter || function () { return true })
5656
// require route files, then add a 'path' property to them
5757
// the path is in the form of '/path/file', relative to routesDir
5858
.map(routeFile => {
5959
let route = require(routeFile)
6060
let extPattern = new RegExp(path.extname(routeFile) + '$')
6161
if (!route.path) {
62-
// Sanitize routesDir for cross OS compatibility
63-
route.path = '/' + path.relative(routesDir, routeFile).replace(extPattern, '').split('\\').join('/')
62+
63+
route.path = '/' + path.relative(routesDir, routeFile).replace(extPattern, '')
64+
//Fix issue with windows paths
65+
route.path = route.path.replace(/\\/, '/')
66+
6467
}
6568
return route
6669
})
@@ -75,7 +78,7 @@ module.exports = function router(routesDir, paramChar = ':') {
7578
.sort((a, b) => val(a.priority) < val(b.priority) ? 1 : -1)
7679

7780
// generated match method - call with a req object to get a route.
78-
return function match(req) {
81+
return function match (req) {
7982
let routeFn = r => r[req.method] || (typeof r === 'function' && r)
8083
let found = routes.find(r => {
8184
let matched = r.match(req.url)

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "fs-router",
3-
"version": "0.2.0",
3+
"version": "0.3.0",
44
"description": "Tiny router using the fs as paths",
55
"main": "index.js",
66
"scripts": {

test/custom-filter-test.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const path = require('path')
2+
const test = require('tape')
3+
const router = require('..')
4+
5+
// set up config to filter only paths ending `index.js`
6+
const config = {filter: f => /(?:^|\/)index.js$/.test(f)}
7+
8+
let match = router(path.join(__dirname, '/fixtures/filter'), config)
9+
10+
test('include non-filtered root path', t => {
11+
t.plan(2)
12+
let req = { url: '/', method: 'GET' }
13+
t.equal(typeof match(req), 'function', 'returns the route function')
14+
t.equal(match(req)(), 'index', 'route function is callable')
15+
})
16+
17+
test('include non-filtered nested path', t => {
18+
t.plan(2)
19+
let req = { url: '/thing', method: 'GET' }
20+
t.equal(typeof match(req), 'function', 'returns the route function')
21+
t.equal(match(req)(), 'thing', 'route function is callable')
22+
})
23+
24+
test('exclude filtered root path', t => {
25+
t.plan(1)
26+
let req = { url: '/other', method: 'GET' }
27+
t.equal(typeof match(req), 'undefined', 'excludes filtered paths')
28+
})
29+
30+
test('exclude filtered nested path', t => {
31+
t.plan(1)
32+
let req = { url: '/thing/other', method: 'GET' }
33+
t.equal(typeof match(req), 'undefined', 'excludes filtered paths')
34+
})

test/custom-path-test.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
const path = require('path')
12
const test = require('tape')
23
const router = require('..')
34

4-
let match = router(__dirname + '/fixtures/custom')
5+
let match = router(path.join(__dirname, '/fixtures/custom'))
56

67
test('uses custom path if provided', t => {
78
t.plan(1)
@@ -12,7 +13,7 @@ test('uses custom path if provided', t => {
1213
test('uses properly parses params in custom path', t => {
1314
t.plan(1)
1415
let req = { url: '/random/custom/foo', method: 'GET' }
15-
let fn = match(req)
16+
match(req)
1617
t.equal(req.params.param, 'foo', 'param is correct')
1718
})
1819

test/fixtures/custom/custom.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
module.exports = function() {}
1+
module.exports = function () {}
22
module.exports.path = '/random/custom/:param'

test/fixtures/filter/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = () => 'index'

test/fixtures/filter/other.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = () => 'other'

test/fixtures/filter/thing/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = () => 'thing'

test/fixtures/filter/thing/other.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = () => 'other'

test/fixtures/params/:root/:why.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
module.exports = function() {}
2-
module.exports.priority = -1;
1+
module.exports = function () {}
2+
module.exports.priority = -1

test/fixtures/params/:root/thing.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = function() {}
1+
module.exports = function () {}
+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = function() {}
1+
module.exports = function () {}

test/fixtures/params/things/:id.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = function() {}
1+
module.exports = function () {}

test/fixtures/simple/foo/bar.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
module.exports = function() {
1+
module.exports = function () {
22
return 'bar'
33
}

test/index-test.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
const path = require('path')
12
const test = require('tape')
23
const router = require('..')
34

4-
let match = router(__dirname + '/fixtures/index')
5+
let match = router(path.join(__dirname, '/fixtures/index'))
56

67
test('uses index.js when the root is requested', t => {
78
t.plan(2)

test/params-test.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
const path = require('path')
12
const test = require('tape')
23
const router = require('..')
34

4-
let match = router(__dirname + '/fixtures/params')
5+
let match = router(path.join(__dirname, '/fixtures/params'))
56

67
test('files starting with `:` are treated as path params', t => {
78
t.plan(1)

test/priority-test.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
const path = require('path')
12
const test = require('tape')
23
const router = require('..')
34

4-
let match = router(__dirname + '/fixtures/priority')
5+
let match = router(path.join(__dirname, '/fixtures/priority'))
56

67
test('matches high priority on collision with default', t => {
78
t.plan(1)

test/simple-test.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
const path = require('path')
12
const test = require('tape')
23
const router = require('..')
34

4-
let match = router(__dirname + '/fixtures/simple')
5+
let match = router(path.join(__dirname, '/fixtures/simple'))
56

67
test('sets up routes from the fs', t => {
78
t.plan(2)

test/verbs-test.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
const path = require('path')
12
const test = require('tape')
23
const router = require('..')
34

4-
let match = router(__dirname + '/fixtures/verbs')
5+
let match = router(path.join(__dirname, '/fixtures/verbs'))
56
const verbs = ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'OPTIONS']
67

78
test('correctly maps various verbs', t => {

0 commit comments

Comments
 (0)