@ditojs/router 1.25.0 → 1.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/Node.js +20 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/router",
|
|
3
|
-
"version": "1.25.
|
|
3
|
+
"version": "1.25.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Dito.js Router – Dito.js is a declarative and modern web framework, based on Objection.js, Koa.js and Vue.js",
|
|
6
6
|
"repository": "https://github.com/ditojs/dito/tree/master/packages/router",
|
|
@@ -30,6 +30,6 @@
|
|
|
30
30
|
"koa",
|
|
31
31
|
"dito"
|
|
32
32
|
],
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "bebbf44ddf15a565e50ed8b2cbe0bf8a463c276d",
|
|
34
34
|
"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 compose from 'koa-compose'\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"
|
|
35
35
|
}
|
package/src/Node.js
CHANGED
|
@@ -133,13 +133,13 @@ export default class Node {
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
find(path,
|
|
136
|
+
find(path, parameterValues = []) {
|
|
137
137
|
const { prefix } = this
|
|
138
138
|
if (!path || path === prefix) {
|
|
139
139
|
// It's a match!
|
|
140
140
|
const { handler } = this
|
|
141
141
|
if (handler) {
|
|
142
|
-
const params = this.parameters.getObject(
|
|
142
|
+
const params = this.parameters.getObject(parameterValues)
|
|
143
143
|
// Support HTTP status on found entries.
|
|
144
144
|
return { handler, params, status: 200 }
|
|
145
145
|
}
|
|
@@ -165,7 +165,7 @@ export default class Node {
|
|
|
165
165
|
child => child.type === TYPE_STATIC && child.label === label
|
|
166
166
|
)
|
|
167
167
|
if (staticChild) {
|
|
168
|
-
const result = staticChild.find(path,
|
|
168
|
+
const result = staticChild.find(path, parameterValues)
|
|
169
169
|
if (result) {
|
|
170
170
|
return result
|
|
171
171
|
}
|
|
@@ -185,21 +185,21 @@ export default class Node {
|
|
|
185
185
|
while (pos < max && path[pos] !== CHAR_SLASH) {
|
|
186
186
|
pos++
|
|
187
187
|
}
|
|
188
|
-
|
|
189
|
-
const result = paramChild.find(path.slice(pos),
|
|
188
|
+
parameterValues.push(path.slice(0, pos))
|
|
189
|
+
const result = paramChild.find(path.slice(pos), parameterValues)
|
|
190
190
|
if (result) {
|
|
191
191
|
return result
|
|
192
192
|
}
|
|
193
|
-
|
|
193
|
+
parameterValues.pop()
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
// Match-any nodes
|
|
197
197
|
if (this.hasMatchAny) {
|
|
198
198
|
for (const child of this.children) {
|
|
199
|
-
const
|
|
200
|
-
if (
|
|
201
|
-
|
|
202
|
-
return child.find('',
|
|
199
|
+
const values = child.parameters?.matchPathPattern(path)
|
|
200
|
+
if (values) {
|
|
201
|
+
parameterValues.push(...values)
|
|
202
|
+
return child.find('', parameterValues) // '' == End
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
}
|
|
@@ -240,8 +240,8 @@ class Parameters {
|
|
|
240
240
|
this.placeholderIndex = 0
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
-
add(
|
|
244
|
-
this.keys.push(
|
|
243
|
+
add(key) {
|
|
244
|
+
this.keys.push(key)
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
getMatchAnyKey() {
|
|
@@ -257,39 +257,38 @@ class Parameters {
|
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
matchPathPattern(path) {
|
|
260
|
-
|
|
260
|
+
const match = this.pathPattern?.exec(path)
|
|
261
|
+
return match ? Object.values(match.groups) : null
|
|
261
262
|
}
|
|
262
263
|
|
|
263
264
|
setupPathPattern(path) {
|
|
264
265
|
// Replace all '**' with '.+?' and all '*' with '[^/]+'.
|
|
265
266
|
// Use named groups to merge multiple ** or * into one.
|
|
266
267
|
const pattern = []
|
|
267
|
-
const keys = []
|
|
268
268
|
for (const token of path.split('/')) {
|
|
269
269
|
if (token === '**') {
|
|
270
270
|
const key = this.getMatchAnyKey()
|
|
271
271
|
pattern.push(`(?<${key}>.+?)`)
|
|
272
|
-
|
|
272
|
+
this.add(key)
|
|
273
273
|
} else if (token === '*') {
|
|
274
274
|
const key = this.getPlaceholderKey()
|
|
275
275
|
pattern.push(`(?<${key}>[^/]+)`)
|
|
276
|
-
|
|
276
|
+
this.add(key)
|
|
277
277
|
} else if (token.startsWith(':')) {
|
|
278
278
|
const key = token.slice(1)
|
|
279
279
|
pattern.push(`(?<${key}>[^/]+)`)
|
|
280
|
-
|
|
280
|
+
this.add(key)
|
|
281
281
|
} else {
|
|
282
282
|
pattern.push(token)
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
285
|
this.pathPattern = new RegExp(`^${pattern.join('/')}$`)
|
|
286
|
-
this.add(...keys)
|
|
287
286
|
}
|
|
288
287
|
|
|
289
288
|
getObject(values) {
|
|
290
289
|
// Convert parameters and values to a params object, but rename path pattern
|
|
291
290
|
// groups back to param names
|
|
292
|
-
const
|
|
291
|
+
const object = {}
|
|
293
292
|
let i = 0
|
|
294
293
|
for (const key of this.keys) {
|
|
295
294
|
const name = key.startsWith('$$')
|
|
@@ -301,8 +300,8 @@ class Parameters {
|
|
|
301
300
|
? '$'
|
|
302
301
|
: key
|
|
303
302
|
: key
|
|
304
|
-
|
|
303
|
+
object[name] = values[i++]
|
|
305
304
|
}
|
|
306
|
-
return
|
|
305
|
+
return object
|
|
307
306
|
}
|
|
308
307
|
}
|