@ditojs/router
Advanced tools
Comparing version 2.27.0 to 2.28.0
{ | ||
"name": "@ditojs/router", | ||
"version": "2.27.0", | ||
"version": "2.28.0", | ||
"type": "module", | ||
@@ -24,3 +24,3 @@ "description": "Dito.js Router – Dito.js is a declarative and modern web framework, based on Objection.js, Koa.js and Vue.js", | ||
"dependencies": { | ||
"@ditojs/utils": "^2.27.0" | ||
"@ditojs/utils": "^2.28.0" | ||
}, | ||
@@ -34,4 +34,4 @@ "keywords": [ | ||
], | ||
"gitHead": "e80d56a1887faa60f61f4c642502687d50ead333", | ||
"gitHead": "2bb631b6048da2d1dcb850d89796c87a4787b258", | ||
"readme": "# Dito.js Router\n\nDito.js is a declarative and modern web framework with a focus on API driven\ndevelopment, based on Koa.js, Objection.js and Vue.js\n\nReleased in 2018 under the MIT license, with support by https://lineto.com/\n\nDito.js Router is a high performance, tree-based, framework agnostic HTTP\nrouter, based on [trek-router](https://github.com/trekjs/router), which in turn\nis inspired by [Echo](https://github.com/labstack/echo)'s Router.\n\n## How does it work?\n\nThe router relies on a tree structure which makes heavy use of common\nprefixes, essentially a [prefix tree](https://en.wikipedia.org/wiki/Trie).\n\n## Usage\n\n```js\nimport Koa from 'koa'\nimport Router from '@ditojs/router'\n\nconst app = new Koa()\nconst router = new Router()\n\n// static route\nrouter.get('/folders/files/bolt.gif', ctx => {\n ctx.body = `this ain't no GIF!`\n})\n\n// param route\nrouter.get('/users/:id', ctx => {\n ctx.body = `requesting user ${ctx.params.id}`\n})\n\n// match-any route\nrouter.get('/books/*', ctx => {\n ctx.body = `sub-route: ${ctx.params['*']}`\n})\n\n// Handler found\nlet { handler, params } = router.find('get', '/users/233')\nconsole.log(handler) // ctx => { ... }\n\n// Entry not Found\nlet { handler, params } = router.find('get', '/photos/233')\nconsole.log(handler) // null\n\n// Install router middleware\napp.use(async (ctx, next) => {\n const { method, path } = ctx\n const result = router.find(method, path)\n const { handler, params } = result\n if (handler) {\n ctx.params = params || {}\n return handler(ctx, next)\n } else {\n try {\n await next()\n } finally {\n if (ctx.body === undefined && ctx.status === 404) {\n ctx.status = result.status || 404\n if (ctx.status !== 404 && result.allowed) {\n ctx.set('Allow', result.allowed.join(', '))\n }\n }\n }\n }\n})\n\napp.listen(4040, () => console.log('Koa app listening on 4040'))\n```\n" | ||
} |
@@ -29,7 +29,9 @@ import { getCommonOffset } from '@ditojs/utils' | ||
this.prefix = prefix | ||
this.children = children | ||
this.children = [] | ||
this.parameters = parameters | ||
this.handler = handler | ||
this.paramKey = null | ||
this.hasMatchAny = false | ||
for (const child of children) { | ||
this.addChild(child) | ||
} | ||
} | ||
@@ -36,0 +38,0 @@ |
@@ -182,9 +182,14 @@ import Router from './Router.js' | ||
}) | ||
result = router.find('GET', '/prefix/hello/there/suffix') | ||
expect(result.handler).toBeUndefined() | ||
}) | ||
it('handles match-any nodes with suffixes', () => { | ||
router.add('GET', '/static/**/suffix', handler) | ||
router.add('GET', '/static/**/suffix/**/more', handler) | ||
router.add('GET', '/static/**/suffix/*/1/:param/2', handler) | ||
router.add('GET', '/static/**/suffix/*/1/:param/2/**/end', handler) | ||
createRoutes(router, [ | ||
['GET', '/static/**/suffix', 'one'], | ||
['GET', '/static/**/suffix/**/more', 'two'], | ||
['GET', '/static/**/suffix/*/1/:param/2', 'three'], | ||
['GET', '/static/**/suffix/*/1/:param/2/**/end', 'four'] | ||
]) | ||
@@ -195,6 +200,6 @@ expect(router.toString()).toBe( | ||
└── static/ children=4 | ||
├── **/suffix handler() children=0 | ||
├── **/suffix/**/more handler() children=0 | ||
├── **/suffix/*/1/:param/2 handler() children=0 | ||
└── **/suffix/*/1/:param/2/**/end handler() children=0 | ||
├── **/suffix one() children=0 | ||
├── **/suffix/**/more two() children=0 | ||
├── **/suffix/*/1/:param/2 three() children=0 | ||
└── **/suffix/*/1/:param/2/**/end four() children=0 | ||
`.trim() | ||
@@ -216,3 +221,3 @@ ) | ||
result = router.find('GET', '/static/one/suffix') | ||
expect(result.handler).toBe(handler) | ||
expect(result.handler?.name).toBe('one') | ||
expect(result.params).toEqual({ | ||
@@ -223,3 +228,3 @@ $$: 'one' | ||
result = router.find('GET', '/static/one/two/suffix') | ||
expect(result.handler).toBe(handler) | ||
expect(result.handler?.name).toBe('one') | ||
expect(result.params).toEqual({ | ||
@@ -233,3 +238,3 @@ $$: 'one/two' | ||
result = router.find('GET', '/static/one/two/suffix/three/four/more') | ||
expect(result.handler).toBe(handler) | ||
expect(result.handler?.name).toBe('two') | ||
expect(result.params).toEqual({ | ||
@@ -241,3 +246,3 @@ $$0: 'one/two', | ||
result = router.find('GET', '/static/one/two/suffix/three/1/bla/2') | ||
expect(result.handler).toBe(handler) | ||
expect(result.handler?.name).toBe('three') | ||
expect(result.params).toEqual({ | ||
@@ -256,3 +261,3 @@ $$: 'one/two', | ||
) | ||
expect(result.handler).toBe(handler) | ||
expect(result.handler?.name).toBe('four') | ||
expect(result.params).toEqual({ | ||
@@ -266,18 +271,45 @@ $: 'three', | ||
it.only('Allow match-any child-routes to coexist with other child-routes', () => { | ||
createRoutes(router, [ | ||
['POST', '/api/admin/pages'], | ||
['POST', '/api/admin/pages/upload/items/**/file'], | ||
['POST', '/api/admin/pages/upload/items/**/files'], | ||
['POST', '/api/admin/pages/:id/child-pages'] | ||
]) | ||
expect(router.toString('POST')).toBe( | ||
deindent` | ||
/ children=1 | ||
└── api/admin/pages ƒ() children=1 | ||
└── / children=2 | ||
├── upload/items/ children=2 | ||
│ ├── **/file ƒ() children=0 | ||
│ └── **/files ƒ() children=0 | ||
└── :id children=1 | ||
└── /child-pages ƒ() children=0 | ||
`.trim() | ||
) | ||
result = router.find('POST', '/api/admin/pages/upload/items/1/file') | ||
expect(result.handler).not.toBeUndefined() | ||
result = router.find('POST', '/api/admin/pages/upload/items/1/2/file') | ||
expect(result.handler).not.toBeUndefined() | ||
}) | ||
it('handles resources', () => { | ||
createRoutes(router, [ | ||
['/', 'root'], | ||
['/geocoder', 'geocoder'], | ||
['/geocoder/new', 'newGeocoder'], | ||
['/geocoder/notify', 'notifyGeocoder'], | ||
// ['/geocoder/nnn', 'nnnGeocoder'], | ||
['/geocoder/edit', 'editGeocoder'], | ||
['/geocoder/edit/email', 'editEmailGeocoder'], | ||
['/geocoder/edit/:item', 'editItemGeocoder'], | ||
['/geocoder/exchange', 'exchangeGeocoder'], | ||
['/geocoder/exchange/email', 'exchangeEmailGeocoder'], | ||
['/geocoder/exchange/:item', 'exchangeItemGeocoder'], | ||
['/geocoder/:id/echo', 'echoGeocoder'], | ||
['/geocoder/:action', 'actionGeocoder'], | ||
['/geocoder/**', 'anyGeocoder'] | ||
['GET', '/', 'root'], | ||
['GET', '/geocoder', 'geocoder'], | ||
['GET', '/geocoder/new', 'newGeocoder'], | ||
['GET', '/geocoder/notify', 'notifyGeocoder'], | ||
// ['GET', '/geocoder/nnn', 'nnnGeocoder'], | ||
['GET', '/geocoder/edit', 'editGeocoder'], | ||
['GET', '/geocoder/edit/email', 'editEmailGeocoder'], | ||
['GET', '/geocoder/edit/:item', 'editItemGeocoder'], | ||
['GET', '/geocoder/exchange', 'exchangeGeocoder'], | ||
['GET', '/geocoder/exchange/email', 'exchangeEmailGeocoder'], | ||
['GET', '/geocoder/exchange/:item', 'exchangeItemGeocoder'], | ||
['GET', '/geocoder/:id/echo', 'echoGeocoder'], | ||
['GET', '/geocoder/:action', 'actionGeocoder'], | ||
['GET', '/geocoder/**', 'anyGeocoder'] | ||
]) | ||
@@ -388,13 +420,13 @@ | ||
createRoutes(router, [ | ||
['/users', 'users'], | ||
['/users/new', 'newUser'], | ||
['/users/noi', 'newUser'], | ||
['/users/nei', 'newUser'], | ||
['/users/:id', 'user'], | ||
['/users/:id/edit', 'editUser'], | ||
['/users/:id/:hello/:good/:bad/ddd', 'editUser'], | ||
['/users/:id/:action', 'actionUser'], | ||
['/users/:userId/photos/:id', 'photo'], | ||
['/users/:userId/books/:id', 'book'], | ||
['/users/**', 'anyUser'] | ||
['GET', '/users', 'users'], | ||
['GET', '/users/new', 'newUser'], | ||
['GET', '/users/noi', 'newUser'], | ||
['GET', '/users/nei', 'newUser'], | ||
['GET', '/users/:id', 'user'], | ||
['GET', '/users/:id/edit', 'editUser'], | ||
['GET', '/users/:id/:hello/:good/:bad/ddd', 'editUser'], | ||
['GET', '/users/:id/:action', 'actionUser'], | ||
['GET', '/users/:userId/photos/:id', 'photo'], | ||
['GET', '/users/:userId/books/:id', 'book'], | ||
['GET', '/users/**', 'anyUser'] | ||
]) | ||
@@ -491,23 +523,23 @@ | ||
const routes = [ | ||
['/users', 'users'], | ||
['/users/new', 'newUser'], | ||
['/users/:id', 'user'], | ||
['/users/:id/:action', 'actionUser'], | ||
['/users/:id/edit', 'editUser'], | ||
['/users/:id/change', 'changeUser'], | ||
['/users/:id/event', 'eventUser'], | ||
['/photos', 'photos'], | ||
['/photos/new', 'newPhoto'], | ||
['/photos/:id', 'photo'], | ||
['/photos/:id/:action', 'actionPhoto'], | ||
['/photos/:id/edit', 'editPhoto'], | ||
['/photos/:id/change', 'changePhoto'], | ||
['/photos/:id/event', 'eventPhoto'], | ||
['/books', 'books'], | ||
['/books/new', 'newBook'], | ||
['/books/:id', 'book'], | ||
['/books/:id/:action', 'actionBook'], | ||
['/books/:id/edit', 'editBook'], | ||
['/books/:id/change', 'changeBook'], | ||
['/books/:id/event', 'eventBook'] | ||
['GET', '/users', 'users'], | ||
['GET', '/users/new', 'newUser'], | ||
['GET', '/users/:id', 'user'], | ||
['GET', '/users/:id/:action', 'actionUser'], | ||
['GET', '/users/:id/edit', 'editUser'], | ||
['GET', '/users/:id/change', 'changeUser'], | ||
['GET', '/users/:id/event', 'eventUser'], | ||
['GET', '/photos', 'photos'], | ||
['GET', '/photos/new', 'newPhoto'], | ||
['GET', '/photos/:id', 'photo'], | ||
['GET', '/photos/:id/:action', 'actionPhoto'], | ||
['GET', '/photos/:id/edit', 'editPhoto'], | ||
['GET', '/photos/:id/change', 'changePhoto'], | ||
['GET', '/photos/:id/event', 'eventPhoto'], | ||
['GET', '/books', 'books'], | ||
['GET', '/books/new', 'newBook'], | ||
['GET', '/books/:id', 'book'], | ||
['GET', '/books/:id/:action', 'actionBook'], | ||
['GET', '/books/:id/edit', 'editBook'], | ||
['GET', '/books/:id/change', 'changeBook'], | ||
['GET', '/books/:id/event', 'eventBook'] | ||
] | ||
@@ -645,6 +677,6 @@ | ||
const routes = [ | ||
['/admin/articles', 'articles'], | ||
['/admin/articles/new', 'newArticle'], | ||
['/admin/articles/:id', 'article'], | ||
['/admin/articles/:id/edit', 'editArticle'] | ||
['GET', '/admin/articles', 'articles'], | ||
['GET', '/admin/articles/new', 'newArticle'], | ||
['GET', '/admin/articles/:id', 'article'], | ||
['GET', '/admin/articles/:id/edit', 'editArticle'] | ||
] | ||
@@ -691,10 +723,10 @@ | ||
const routes = [ | ||
['/magazines/:mid/articles', 'articles'], | ||
['/magazines/:mid/articles/new', 'newArticle'], | ||
['/magazines/:mid/articles/:id', 'article'], | ||
['/magazines/:mid/articles/:id/edit', 'editArticle'], | ||
['/magazines/:m_id/photos', 'photos'], | ||
['/magazines/:m_id/photos/new', 'newPhoto'], | ||
['/magazines/:m_id/photos/:id', 'photo'], | ||
['/magazines/:m_id/photos/:id/edit', 'editPhoto'] | ||
['GET', '/magazines/:mid/articles', 'articles'], | ||
['GET', '/magazines/:mid/articles/new', 'newArticle'], | ||
['GET', '/magazines/:mid/articles/:id', 'article'], | ||
['GET', '/magazines/:mid/articles/:id/edit', 'editArticle'], | ||
['GET', '/magazines/:m_id/photos', 'photos'], | ||
['GET', '/magazines/:m_id/photos/new', 'newPhoto'], | ||
['GET', '/magazines/:m_id/photos/:id', 'photo'], | ||
['GET', '/magazines/:m_id/photos/:id/edit', 'editPhoto'] | ||
] | ||
@@ -796,9 +828,11 @@ | ||
// eslint-disable-next-line no-new-func | ||
return new Function(`return function ${name}(){}`)() | ||
return new Function( | ||
`return ${name ? `function ${name}(){}` : '() => {}'}` | ||
)() | ||
} | ||
function createRoutes(router, routes) { | ||
routes.forEach(([path, name]) => { | ||
router.add('GET', path, createFunc(name)) | ||
routes.forEach(([method, path, name]) => { | ||
router.add(method, path, createFunc(name)) | ||
}) | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
48917
1104
Updated@ditojs/utils@^2.28.0