koa-tree-router
Advanced tools
Comparing version 0.10.1 to 0.11.0
@@ -6,2 +6,3 @@ import * as Koa from "koa"; | ||
onMethodNotAllowed?: Router.Middleware<StateT, CustomT>; | ||
redirectTrailingSlash: Boolean; | ||
} | ||
@@ -8,0 +9,0 @@ export interface IRouterParamContext<StateT = any, CustomT = {}> { |
{ | ||
"name": "koa-tree-router", | ||
"version": "0.10.1", | ||
"version": "0.11.0", | ||
"description": "A high performance koa router", | ||
@@ -37,5 +37,5 @@ "main": "router.js", | ||
"expect": "^27.2.0", | ||
"koa": "^2.13.0", | ||
"koa": "^2.13.4", | ||
"mocha": "^9.1.1", | ||
"supertest": "^6.2.2" | ||
"supertest": "^6.2.3" | ||
}, | ||
@@ -42,0 +42,0 @@ "dependencies": { |
@@ -61,5 +61,12 @@ # Koa tree router | ||
} | ||
}) | ||
}); | ||
``` | ||
You can also allow trailing slash redirect `redirectTrailingSlash`. | ||
```js | ||
const router = require('koa-tree-router')({ | ||
redirectTrailingSlash: true | ||
}); | ||
``` | ||
#### on(method, path, middleware) | ||
@@ -66,0 +73,0 @@ Register a new route. |
@@ -7,3 +7,3 @@ const http = require("http"); | ||
const httpMethods = http.METHODS; | ||
const NOT_FOUND = { handle: null, params: [] }; | ||
const NOT_FOUND = { handle: null, params: [], tsr: false }; | ||
@@ -76,4 +76,19 @@ class Router { | ||
const handle = function (ctx, next) { | ||
const { handle, params } = router.find(ctx.method, ctx.path); | ||
const { handle, params, tsr } = router.find(ctx.method, ctx.path); | ||
if (!handle) { | ||
if (tsr && router.opts.redirectTrailingSlash) { | ||
const { path, search } = ctx.request; | ||
if (path !== "/" && path.slice(-1) === "/") { | ||
const redirectUrl = path.slice(0, -1) + search; | ||
ctx.response.status = 301; | ||
ctx.redirect(redirectUrl); | ||
return; | ||
} else { | ||
const redirectUrl = path + "/" + search; | ||
ctx.response.status = 301; | ||
ctx.redirect(redirectUrl); | ||
return; | ||
} | ||
} | ||
const handle405 = router.opts.onMethodNotAllowed; | ||
@@ -80,0 +95,0 @@ if (handle405) { |
99
tree.js
@@ -26,3 +26,3 @@ const STATIC = 0; | ||
i, | ||
valid | ||
valid, | ||
}; | ||
@@ -38,3 +38,3 @@ } | ||
i, | ||
valid | ||
valid, | ||
}; | ||
@@ -46,3 +46,3 @@ } | ||
i: -1, | ||
valid: false | ||
valid: false, | ||
}; | ||
@@ -252,6 +252,6 @@ } | ||
"only one wildcard per path segment is allowed, has: '" + | ||
wildcard + | ||
"' in path '" + | ||
fullPath + | ||
"'" | ||
wildcard + | ||
"' in path '" + | ||
fullPath + | ||
"'" | ||
); | ||
@@ -263,4 +263,4 @@ } | ||
"wildcards must be named with a non-empty name in path '" + | ||
fullPath + | ||
"'" | ||
fullPath + | ||
"'" | ||
); | ||
@@ -272,6 +272,6 @@ } | ||
"wildcard route '" + | ||
wildcard + | ||
"' conflicts with existing children in path '" + | ||
fullPath + | ||
"'" | ||
wildcard + | ||
"' conflicts with existing children in path '" + | ||
fullPath + | ||
"'" | ||
); | ||
@@ -308,7 +308,7 @@ } | ||
// catchAll | ||
if (i + wildcard.length != path.length) { | ||
if (i + wildcard.length !== path.length) { | ||
throw new Error( | ||
"catch-all routes are only allowed at the end of the path in path '" + | ||
fullPath + | ||
"'" | ||
fullPath + | ||
"'" | ||
); | ||
@@ -320,4 +320,4 @@ } | ||
"catch-all conflicts with existing handle for the path segment root in path '" + | ||
fullPath + | ||
"'" | ||
fullPath + | ||
"'" | ||
); | ||
@@ -369,2 +369,3 @@ } | ||
let n = this; | ||
let tsr = false; | ||
@@ -388,3 +389,6 @@ walk: while (true) { | ||
// Nothing found. | ||
return { handle, params }; | ||
// We can recommend to redirect to the same URL without a | ||
// trailing slash if a leaf exists for that path. | ||
tsr = path === "/" && n.handle !== null; | ||
return { handle, params, tsr }; | ||
} | ||
@@ -414,8 +418,17 @@ | ||
// ... but we can't | ||
return { handle, params }; | ||
tsr = path.length === end + 1; | ||
return { handle, params, tsr }; | ||
} | ||
handle = n.handle; | ||
if (handle === null && n.children.length === 1) { | ||
// No handle found. Check if a handle for this path + a | ||
// trailing slash exists for TSR recommendation | ||
n = n.children[0]; | ||
tsr = | ||
(n.path === "/" && n.handle !== null) || | ||
(n.path === "" && n.indices === "/"); | ||
} | ||
return { handle, params }; | ||
return { handle, params, tsr }; | ||
@@ -434,5 +447,45 @@ case CATCH_ALL: | ||
handle = n.handle; | ||
// We should have reached the node containing the handle. | ||
// Check if this node has a handle registered. | ||
if (handle !== null) { | ||
return { handle, params, tsr }; | ||
} | ||
// If there is no handle for this route, but this route has a | ||
// wildcard child, there must be a handle for this path with an | ||
// additional trailing slash | ||
if (path === "/" && n.wildChild && n.type !== ROOT) { | ||
tsr = true; | ||
return { handle, params, tsr }; | ||
} | ||
if (path === "/" && n.type === STATIC) { | ||
tsr = true; | ||
return { handle, params, tsr }; | ||
} | ||
// No handle found. Check if a handle for this path + a | ||
// trailing slash exists for trailing slash recommendation | ||
for (let i = 0; i < n.indices.length; i++) { | ||
const char = n.indices[i]; | ||
if (char === "/") { | ||
n = n.children[i]; | ||
tsr = | ||
(n.path.length === 1 && n.handle !== null) || | ||
(n.type === CATCH_ALL && n.children[0].handle !== null); | ||
return { handle, params, tsr }; | ||
} | ||
} | ||
return { handle, params, tsr }; | ||
} | ||
return { handle, params }; | ||
// Nothing found. We can recommend to redirect to the same URL with an | ||
// extra trailing slash if a leaf exists for that path | ||
tsr = | ||
path === "/" || | ||
(n.path.length === path.length + 1 && | ||
n.path[path.length] === "/" && | ||
path === n.path.slice(0, n.path.length - 1) && | ||
n.handle !== null); | ||
return { handle, params, tsr }; | ||
} | ||
@@ -439,0 +492,0 @@ } |
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
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
30239
863
197