Skip to content

Commit

Permalink
feat: allow function as to value (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
juno-yu authored and manniL committed Nov 22, 2018
1 parent eb033f9 commit 9ed5407
Show file tree
Hide file tree
Showing 5 changed files with 1,301 additions and 3 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,22 @@ redirect: [
]
```

Furthermoer you can use a function to create your `to` url as well :+1:
The `from` rule and the `req` of the middleware will be provided as arguments.
The function can also be *async*!

```js
redirect: [
{
from: '^/someUrlHere/(.*)$',
to: (from, req) => {
const param = req.url.match(/functionAsync\/(.*)$/)[1]
return `/posts/${param}`
}
}
]
```

And if you really need more power... okay! You can also use a factory function
to generate your redirects:

Expand Down
10 changes: 8 additions & 2 deletions lib/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@

// Creates new middleware using provided options
function create (rules) {
return function redirectRoute (req, res, next) {
return async function redirectRoute (req, res, next) {
const decodedBaseUrl = decodeURI(req.url)
const foundRule = rules.find(o => o.from.test(decodedBaseUrl))

if (!foundRule) {
return next()
}
const toUrl = decodedBaseUrl.replace(foundRule.from, foundRule.to)
// Expect rule 'to' to be 1)regex or 2)string or
// 3)function taking from & req (when from is regex, req might be more interesting)
let toTarget = foundRule.to
if (typeof toTarget === 'function') {
toTarget = await toTarget(foundRule.from, req)
}
const toUrl = decodedBaseUrl.replace(foundRule.from, toTarget)

res.statusCode = foundRule.statusCode || 302
res.setHeader('Location', toUrl)
Expand Down
14 changes: 13 additions & 1 deletion test/fixture/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,19 @@ const redirects = [
{ from: '^/redirected', to: '/' },
{ from: /^\/äßU</, to: '/' },
{ from: '^/many/(.*)$', to: '/posts/abcde' },
{ from: '^/mapped/(.*)$', to: '/posts/$1' }
{ from: '^/mapped/(.*)$', to: '/posts/$1' },
{ from: '^/function$', to: () => '/' },
{ from: '^/functionAsync$',
to: async from => new Promise(resolve => {
setTimeout(() => resolve('/'), 2000)
})
},
{ from: '^/functionAsync/(.*)$',
to: async (from, req) => new Promise(resolve => {
const param = req.url.match(/functionAsync\/(.*)$/)[1]
setTimeout(() => resolve(`/posts/${param}`), 2000)
})
}
]

const baseConfig = {
Expand Down
18 changes: 18 additions & 0 deletions test/module.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,24 @@ const testSuite = () => {
expect(dom.window.document.querySelector('body').textContent).toContain(n)
}
})

test('function evaluated to compute redirect rule to', async () => {
const html = await get('/function')
const dom = new JSDOM(html)
expect(dom.window.document.querySelector('body').textContent).toContain('Works!')
})

test('async function evaluated to compute redirect rule to', async () => {
const html = await get('/functionAsync')
const dom = new JSDOM(html)
expect(dom.window.document.querySelector('body').textContent).toContain('Works!')
})

test('async function param considered', async () => {
const html = await get('/functionAsync/def')
const dom = new JSDOM(html)
expect(dom.window.document.querySelector('body').textContent).toContain('def')
})
}

describe('basic', () => {
Expand Down
Loading

0 comments on commit 9ed5407

Please sign in to comment.