hono 0.0.4 → 0.0.5

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/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  Hono [炎] - Tiny web framework for Cloudflare Workers and others.
4
4
 
5
5
  ```js
6
+ const Hono = require('Hono')
6
7
  const app = Hono()
7
8
 
8
9
  app.get('/', () => new Response('Hono!!'))
@@ -16,7 +17,17 @@ app.fire()
16
17
  - Tiny - use only standard API.
17
18
  - Portable - zero dependencies.
18
19
  - Flexible - you can make your own middlewares.
19
- - Optimized - for Cloudflare Workers.
20
+ - Optimized - for Cloudflare Workers and Fastly Compute@Edge.
21
+
22
+ ## Benchmark
23
+
24
+ ```
25
+ hono x 813,001 ops/sec ±2.96% (75 runs sampled)
26
+ itty-router x 160,415 ops/sec ±3.31% (85 runs sampled)
27
+ sundar x 307,438 ops/sec ±4.77% (73 runs sampled)
28
+ Fastest is hono
29
+ ✨ Done in 37.03s.
30
+ ```
20
31
 
21
32
  ## Install
22
33
 
@@ -50,7 +61,7 @@ app.post('/', () => new Response('POST /'))
50
61
 
51
62
  // Wildcard
52
63
  app.get('/wild/*/card', () => {
53
- return new Reponse('GET /wild/*/card')
64
+ return new Response('GET /wild/*/card')
54
65
  })
55
66
  ```
56
67
 
@@ -58,7 +69,7 @@ app.get('/wild/*/card', () => {
58
69
 
59
70
  ```js
60
71
  // Any HTTP methods
61
- app.all('/hello', () => 'ALL Method /hello')
72
+ app.all('/hello', () => new Response('ALL Method /hello'))
62
73
  ```
63
74
 
64
75
  ### Named Parameter
@@ -152,6 +163,7 @@ app.get('/entry/:id', (c) => {
152
163
 
153
164
  - koa <https://github.com/koajs/koa>
154
165
  - express <https://github.com/expressjs/express>
166
+ - oak <https://github.com/oakserver/oak>
155
167
  - itty-router <https://github.com/kwhitley/itty-router>
156
168
  - Sunder <https://github.com/SunderJS/sunder>
157
169
  - goblin <https://github.com/bmf-san/goblin>
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "hono",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Minimal web framework for Cloudflare Workers",
5
5
  "main": "src/hono.js",
6
6
  "scripts": {
7
- "test": "jest --verbose"
7
+ "test": "jest"
8
8
  },
9
9
  "author": "Yusuke Wada <yusuke@kamawada.com> (https://github.com/yusukebe)",
10
10
  "license": "MIT",
@@ -17,4 +17,4 @@
17
17
  "jest": "^27.4.5",
18
18
  "node-fetch": "^2.6.6"
19
19
  }
20
- }
20
+ }
package/src/hono.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  const Node = require('./node')
4
4
  const compose = require('./compose')
5
- const filter = require('./middleware/filter')
5
+ const defaultFilter = require('./middleware/defaultFilter')
6
6
 
7
7
  class Router {
8
8
  constructor() {
@@ -15,91 +15,107 @@ class Router {
15
15
  }
16
16
 
17
17
  match(method, path) {
18
- method = method.toLowerCase()
19
18
  return this.node.search(method, path)
20
19
  }
21
20
  }
22
21
 
23
- const proxyHandler = {
24
- get:
25
- (target, prop) =>
26
- (...args) => {
27
- if (target.constructor.prototype.hasOwnProperty(prop)) {
28
- return target[prop](...args)
29
- } else {
30
- if (args.length == 1) {
31
- return target.addRoute(prop, target.router.tempPath, ...args)
32
- }
33
- return target.addRoute(prop, ...args)
34
- }
35
- },
22
+ const getPathFromURL = (url) => {
23
+ // XXX
24
+ const match = url.match(/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/)
25
+ return match[5]
36
26
  }
37
27
 
38
- class App {
28
+ class Hono {
39
29
  constructor() {
40
30
  this.router = new Router()
41
31
  this.middlewareRouter = new Router()
42
- this.middleware = []
32
+ this.middlewareRouters = []
43
33
  }
44
34
 
45
- addRoute(method, path, ...args) {
46
- this.router.add(method, path, ...args)
47
- return WrappedApp(this)
35
+ get(...args) {
36
+ return this.addRoute('GET', ...args)
37
+ }
38
+ post(...args) {
39
+ return this.addRoute('POST', ...args)
40
+ }
41
+ put(...args) {
42
+ return this.addRoute('PUT', ...args)
43
+ }
44
+ delete(...args) {
45
+ return this.addRoute('DELETE', ...args)
46
+ }
47
+ patch(...args) {
48
+ return this.addRoute('PATCH', ...args)
48
49
  }
49
50
 
50
- matchRoute(method, path) {
51
- return this.router.match(method, path)
51
+ addRoute(method, ...args) {
52
+ method = method.toUpperCase()
53
+ if (args.length === 1) {
54
+ this.router.add(method, this.router.tempPath, ...args)
55
+ } else {
56
+ this.router.add(method, ...args)
57
+ }
58
+ return this
59
+ }
60
+
61
+ getRouter() {
62
+ return this.router
52
63
  }
53
64
 
54
65
  route(path) {
55
66
  this.router.tempPath = path
56
- return WrappedApp(this)
67
+ return this
57
68
  }
58
69
 
59
70
  use(path, middleware) {
60
- middleware = [middleware]
61
- const result = this.middlewareRouter.match('all', path)
62
- if (result) {
63
- middleware.push(...result.handler)
64
- }
65
- this.middlewareRouter.add('all', path, ...middleware)
71
+ const router = new Router()
72
+ router.add('all', path, middleware)
73
+ this.middlewareRouters.push(router)
74
+ }
75
+
76
+ async matchRoute(method, path) {
77
+ const res = this.router.match(method, path)
78
+ return res
66
79
  }
67
80
 
68
81
  // XXX
69
- createContext(req, res) {
70
- return { req: req, res: res }
82
+ async createContext(req, res) {
83
+ return {
84
+ req: req,
85
+ res: res,
86
+ newResponse: (params) => {
87
+ return new Response(params)
88
+ },
89
+ }
71
90
  }
72
91
 
73
92
  async dispatch(request, response) {
74
- const url = new URL(request.url)
75
- const [method, path] = [request.method, url.pathname]
93
+ const [method, path] = [request.method, getPathFromURL(request.url)]
76
94
 
77
- const result = this.matchRoute(method, path)
95
+ const result = await this.matchRoute(method, path)
78
96
  if (!result) return this.notFound()
79
97
 
80
98
  request.params = (key) => result.params[key]
81
99
 
82
- const middleware = [filter]
83
- const mwResult = this.middlewareRouter.match('all', path)
84
- if (mwResult) {
85
- middleware.push(...mwResult.handler)
86
- }
100
+ let handler = result.handler[0] // XXX
101
+
102
+ const middleware = [defaultFilter] // add defaultFilter later
87
103
 
88
- let handler
89
- for (const resultHandler of result.handler) {
90
- if (resultHandler) {
91
- handler = resultHandler
104
+ for (const mr of this.middlewareRouters) {
105
+ const mwResult = mr.match('all', path)
106
+ if (mwResult) {
107
+ middleware.push(...mwResult.handler)
92
108
  }
93
109
  }
94
110
 
95
- let wrappedHandler = (context, next) => {
111
+ let wrappedHandler = async (context, next) => {
96
112
  context.res = handler(context)
97
113
  next()
98
114
  }
99
115
 
100
116
  middleware.push(wrappedHandler)
101
117
  const composed = compose(middleware)
102
- const c = this.createContext(request, response)
118
+ const c = await this.createContext(request, response)
103
119
 
104
120
  composed(c)
105
121
 
@@ -107,7 +123,7 @@ class App {
107
123
  }
108
124
 
109
125
  async handleEvent(event) {
110
- return await this.dispatch(event.request, new Response())
126
+ return this.dispatch(event.request, {}) // XXX
111
127
  }
112
128
 
113
129
  fire() {
@@ -121,8 +137,8 @@ class App {
121
137
  }
122
138
  }
123
139
 
124
- const WrappedApp = (router = new App()) => {
125
- return new Proxy(router, proxyHandler)
140
+ const CreateApp = () => {
141
+ return new Hono()
126
142
  }
127
143
 
128
- module.exports = WrappedApp
144
+ module.exports = CreateApp
@@ -1,19 +1,19 @@
1
- const filter = (c, next) => {
2
- const url = new URL(c.req.url)
1
+ const defaultFilter = (c, next) => {
3
2
  c.req.query = (key) => {
3
+ const url = new URL(c.req.url)
4
4
  return url.searchParams.get(key)
5
5
  }
6
6
 
7
7
  next()
8
8
 
9
9
  if (typeof c.res === 'string') {
10
- c.res = new Response(c.res, {
10
+ c.res = new Reponse(c.res, {
11
11
  status: 200,
12
12
  headers: {
13
- 'Content-Type': 'text/plain',
13
+ 'Conten-Type': 'text/plain',
14
14
  },
15
15
  })
16
16
  }
17
17
  }
18
18
 
19
- module.exports = filter
19
+ module.exports = defaultFilter
package/src/node.js CHANGED
@@ -1,131 +1,91 @@
1
- const methodNameOfAll = 'all'
1
+ 'use strict'
2
2
 
3
- class Result {
4
- constructor({ handler, params } = {}) {
5
- this.handler = handler || []
6
- this.params = params || {}
7
- }
8
- }
3
+ const { splitPath, getPattern } = require('./util')
9
4
 
10
- class Node {
11
- constructor({ method, label, handler, children } = {}) {
12
- this.label = label || ''
13
- this.children = children || []
14
- this.method = {}
15
- if (method && handler) {
16
- this.method[method] = handler
17
- }
18
- }
5
+ const METHOD_NAME_OF_ALL = 'all'
19
6
 
20
- insert(method, path, handler) {
21
- let curNode = this
22
- const ps = this.splitPath(path)
23
- for (const p of ps) {
24
- let nextNode = curNode.children[p]
25
- if (nextNode) {
26
- curNode = nextNode
27
- } else {
28
- curNode.children[p] = new Node({
29
- label: p,
30
- handler: handler,
31
- })
32
- curNode = curNode.children[p]
33
- }
34
- }
35
- curNode.method[method] = handler
36
- }
7
+ const createResult = (handler, params) => {
8
+ return { handler: handler, params: params }
9
+ }
37
10
 
38
- splitPath(path) {
39
- let ps = ['/']
40
- for (const p of path.split('/')) {
41
- if (p) {
42
- ps.push(p)
43
- }
44
- }
45
- return ps
46
- }
11
+ const noRoute = () => {
12
+ return null
13
+ }
47
14
 
48
- getPattern(label) {
49
- // :id{[0-9]+} → [0-9]+$
50
- // :id → (.+)
51
- const match = label.match(/^\:.+?\{(.+)\}$/)
52
- if (match) {
53
- return '(' + match[1] + ')'
54
- }
55
- return '(.+)'
15
+ function Node(method, handler, children) {
16
+ this.children = children || {}
17
+ this.method = {}
18
+ if (method && handler) {
19
+ this.method[method] = handler
56
20
  }
21
+ }
57
22
 
58
- getParamName(label) {
59
- const match = label.match(/^\:([^\{\}]+)/)
60
- if (match) {
61
- return match[1]
23
+ Node.prototype.insert = function (method, path, handler) {
24
+ let curNode = this
25
+ const parts = splitPath(path)
26
+ for (let i = 0; i < parts.length; i++) {
27
+ const p = parts[i]
28
+ if (Object.keys(curNode.children).includes(p)) {
29
+ curNode = curNode.children[p]
30
+ continue
62
31
  }
32
+ curNode.children[p] = new Node(method, handler)
33
+ curNode = curNode.children[p]
63
34
  }
35
+ curNode.method[method] = handler
36
+ return curNode
37
+ }
64
38
 
65
- search(method, path) {
66
- let curNode = this
67
- let [handler, params] = [, {}]
39
+ Node.prototype.search = function (method, path) {
40
+ let curNode = this
68
41
 
69
- if (path === '/') {
70
- const root = this.children['/']
71
- if (!root) return this.noRoute()
72
- // app.get('*', () => 'All')
73
- const rootAsterisk = root.children['*']
74
- if (rootAsterisk) {
75
- handler =
76
- rootAsterisk.method[method] || rootAsterisk.method[methodNameOfAll]
77
- } else if (!root.method[method]) {
78
- return this.noRoute()
79
- }
80
- }
42
+ const params = {}
43
+ const parts = splitPath(path)
81
44
 
82
- for (const p of this.splitPath(path)) {
83
- let nextNode = curNode.children[p]
45
+ for (let i = 0; i < parts.length; i++) {
46
+ const p = parts[i]
47
+ const nextNode = curNode.children[p]
48
+ if (nextNode) {
49
+ curNode = nextNode
50
+ continue
51
+ }
84
52
 
85
- if (nextNode) {
86
- curNode = nextNode
87
- continue
53
+ let isParamMatch = false
54
+ const keys = Object.keys(curNode.children)
55
+ for (let j = 0; j < keys.length; j++) {
56
+ const key = keys[j]
57
+ // Wildcard
58
+ if (key === '*') {
59
+ curNode = curNode.children['*']
60
+ isParamMatch = true
61
+ break
88
62
  }
89
-
90
- let isParamMatch = false
91
- for (const key in curNode.children) {
92
- if (key === '*') {
93
- // Wildcard
63
+ const pattern = getPattern(key)
64
+ if (pattern) {
65
+ const match = p.match(new RegExp(pattern[1]))
66
+ if (match) {
67
+ const k = pattern[0]
68
+ params[k] = match[1]
94
69
  curNode = curNode.children[key]
95
70
  isParamMatch = true
96
71
  break
97
72
  }
98
- if (key.match(/^:/)) {
99
- const pattern = this.getPattern(key)
100
- const match = p.match(new RegExp(pattern))
101
- if (match) {
102
- const k = this.getParamName(key)
103
- params[k] = match[0]
104
- curNode = curNode.children[key]
105
- isParamMatch = true
106
- break
107
- }
108
- return this.noRoute()
109
- }
110
- }
111
- if (isParamMatch == false) {
112
- return this.noRoute()
73
+ return noRoute()
113
74
  }
114
75
  }
115
76
 
116
- handler =
117
- handler || curNode.method[methodNameOfAll] || curNode.method[method]
118
-
119
- if (!handler) {
120
- return this.noRoute()
77
+ if (isParamMatch === false) {
78
+ return noRoute()
121
79
  }
122
- const res = new Result({ handler: handler, params: params })
123
- return res
124
80
  }
125
81
 
126
- noRoute() {
127
- return null
82
+ const handler = curNode.method[METHOD_NAME_OF_ALL] || curNode.method[method]
83
+
84
+ if (!handler) {
85
+ return noRoute()
128
86
  }
87
+
88
+ return createResult(handler, params)
129
89
  }
130
90
 
131
91
  module.exports = Node
package/src/node.test.js CHANGED
@@ -1,26 +1,17 @@
1
1
  const Node = require('./node')
2
2
 
3
- describe('Util Methods', () => {
4
- const node = new Node()
5
- it('node.splitPath', () => {
6
- let ps = node.splitPath('/')
7
- expect(ps[0]).toBe('/')
8
- ps = node.splitPath('/hello')
9
- expect(ps[0]).toBe('/')
10
- expect(ps[1]).toBe('hello')
11
- })
12
- })
13
-
14
3
  describe('Root Node', () => {
15
4
  const node = new Node()
16
5
  node.insert('get', '/', 'get root')
17
6
  it('get /', () => {
18
- expect(node.search('get', '/')).not.toBeNull()
7
+ let res = node.search('get', '/')
8
+ expect(res).not.toBeNull()
9
+ expect(res.handler).toBe('get root')
19
10
  expect(node.search('get', '/hello')).toBeNull()
20
11
  })
21
12
  })
22
13
 
23
- describe('Root Node', () => {
14
+ describe('Root Node id not defined', () => {
24
15
  const node = new Node()
25
16
  node.insert('get', '/hello', 'get hello')
26
17
  it('get /', () => {
@@ -28,7 +19,7 @@ describe('Root Node', () => {
28
19
  })
29
20
  })
30
21
 
31
- describe('All', () => {
22
+ describe('All with *', () => {
32
23
  const node = new Node()
33
24
  node.insert('get', '*', 'get all')
34
25
  it('get /', () => {
@@ -78,25 +69,33 @@ describe('Name path', () => {
78
69
 
79
70
  it('get /entry/456/comment', () => {
80
71
  node.insert('get', '/entry/:id', 'get entry')
81
- res = node.search('get', '/entry/456/comment')
72
+ let res = node.search('get', '/entry/456/comment')
82
73
  expect(res).toBeNull()
83
74
  })
84
75
 
85
76
  it('get /entry/789/comment/123', () => {
86
77
  node.insert('get', '/entry/:id/comment/:comment_id', 'get comment')
87
- res = node.search('get', '/entry/789/comment/123')
78
+ let res = node.search('get', '/entry/789/comment/123')
88
79
  expect(res).not.toBeNull()
89
80
  expect(res.handler).toBe('get comment')
90
81
  expect(res.params['id']).toBe('789')
91
82
  expect(res.params['comment_id']).toBe('123')
92
83
  })
84
+
85
+ it('get /map/:location/events', () => {
86
+ node.insert('get', '/map/:location/events', 'get events')
87
+ let res = node.search('get', '/map/yokohama/events')
88
+ expect(res).not.toBeNull()
89
+ expect(res.handler).toBe('get events')
90
+ expect(res.params['location']).toBe('yokohama')
91
+ })
93
92
  })
94
93
 
95
94
  describe('Wildcard', () => {
96
95
  const node = new Node()
97
96
  it('/wildcard-abc/xxxxxx/wildcard-efg', () => {
98
97
  node.insert('get', '/wildcard-abc/*/wildcard-efg', 'wildcard')
99
- res = node.search('get', '/wildcard-abc/xxxxxx/wildcard-efg')
98
+ let res = node.search('get', '/wildcard-abc/xxxxxx/wildcard-efg')
100
99
  expect(res).not.toBeNull()
101
100
  expect(res.handler).toBe('wildcard')
102
101
  })
@@ -104,11 +103,7 @@ describe('Wildcard', () => {
104
103
 
105
104
  describe('Regexp', () => {
106
105
  const node = new Node()
107
- node.insert(
108
- 'get',
109
- '/regex-abc/:id{[0-9]+}/comment/:comment_id{[a-z]+}',
110
- 'regexp'
111
- )
106
+ node.insert('get', '/regex-abc/:id{[0-9]+}/comment/:comment_id{[a-z]+}', 'regexp')
112
107
  it('/regexp-abc/123/comment/abc', () => {
113
108
  res = node.search('get', '/regex-abc/123/comment/abc')
114
109
  expect(res).not.toBeNull()
@@ -1,24 +1,24 @@
1
1
  const App = require('./hono')
2
2
 
3
3
  describe('Basic Usage', () => {
4
- let router = App()
4
+ const router = App()
5
5
 
6
- it('get, post hello', () => {
6
+ it('get, post hello', async () => {
7
7
  router.get('/hello', 'get hello')
8
8
  router.post('/hello', 'post hello')
9
9
 
10
- let res = router.matchRoute('GET', '/hello')
10
+ let res = await router.matchRoute('GET', '/hello')
11
11
  expect(res).not.toBeNull()
12
12
  expect(res.handler[0]).toBe('get hello')
13
13
 
14
- res = router.matchRoute('POST', '/hello')
14
+ res = await router.matchRoute('POST', '/hello')
15
15
  expect(res).not.toBeNull()
16
16
  expect(res.handler[0]).toBe('post hello')
17
17
 
18
- res = router.matchRoute('PUT', '/hello')
18
+ res = await router.matchRoute('PUT', '/hello')
19
19
  expect(res).toBeNull()
20
20
 
21
- res = router.matchRoute('GET', '/')
21
+ res = await router.matchRoute('GET', '/')
22
22
  expect(res).toBeNull()
23
23
  })
24
24
  })
@@ -26,31 +26,31 @@ describe('Basic Usage', () => {
26
26
  describe('Complex', () => {
27
27
  let router = App()
28
28
 
29
- it('Named Param', () => {
29
+ it('Named Param', async () => {
30
30
  router.get('/entry/:id', 'get entry')
31
- res = router.matchRoute('GET', '/entry/123')
31
+ res = await router.matchRoute('GET', '/entry/123')
32
32
  expect(res).not.toBeNull()
33
33
  expect(res.handler[0]).toBe('get entry')
34
34
  expect(res.params['id']).toBe('123')
35
35
  })
36
36
 
37
- it('Wildcard', () => {
37
+ it('Wildcard', async () => {
38
38
  router.get('/wild/*/card', 'get wildcard')
39
- res = router.matchRoute('GET', '/wild/xxx/card')
39
+ res = await router.matchRoute('GET', '/wild/xxx/card')
40
40
  expect(res).not.toBeNull()
41
41
  expect(res.handler[0]).toBe('get wildcard')
42
42
  })
43
43
 
44
- it('Regexp', () => {
44
+ it('Regexp', async () => {
45
45
  router.get('/post/:date{[0-9]+}/:title{[a-z]+}', 'get post')
46
- res = router.matchRoute('GET', '/post/20210101/hello')
46
+ res = await router.matchRoute('GET', '/post/20210101/hello')
47
47
  expect(res).not.toBeNull()
48
48
  expect(res.handler[0]).toBe('get post')
49
49
  expect(res.params['date']).toBe('20210101')
50
50
  expect(res.params['title']).toBe('hello')
51
- res = router.matchRoute('GET', '/post/onetwothree')
51
+ res = await router.matchRoute('GET', '/post/onetwothree')
52
52
  expect(res).toBeNull()
53
- res = router.matchRoute('GET', '/post/123/123')
53
+ res = await router.matchRoute('GET', '/post/123/123')
54
54
  expect(res).toBeNull()
55
55
  })
56
56
  })
@@ -58,27 +58,31 @@ describe('Complex', () => {
58
58
  describe('Chained Route', () => {
59
59
  let router = App()
60
60
 
61
- it('Return rooter object', () => {
61
+ it('Return rooter object', async () => {
62
62
  router = router.patch('/hello', 'patch hello')
63
63
  expect(router).not.toBeNull()
64
64
  router = router.delete('/hello', 'delete hello')
65
- res = router.matchRoute('DELETE', '/hello')
65
+ res = await router.matchRoute('DELETE', '/hello')
66
66
  expect(res).not.toBeNull()
67
67
  expect(res.handler[0]).toBe('delete hello')
68
68
  })
69
69
 
70
- it('Chain with route method', () => {
70
+ it('Chain with route method', async () => {
71
71
  router.route('/api/book').get('get book').post('post book').put('put book')
72
- res = router.matchRoute('GET', '/api/book')
72
+
73
+ res = await router.matchRoute('GET', '/api/book')
73
74
  expect(res).not.toBeNull()
74
75
  expect(res.handler[0]).toBe('get book')
75
- res = router.matchRoute('POST', '/api/book')
76
+
77
+ res = await router.matchRoute('POST', '/api/book')
76
78
  expect(res).not.toBeNull()
77
79
  expect(res.handler[0]).toBe('post book')
78
- res = router.matchRoute('PUT', '/api/book')
80
+
81
+ res = await router.matchRoute('PUT', '/api/book')
79
82
  expect(res).not.toBeNull()
80
83
  expect(res.handler[0]).toBe('put book')
81
- res = router.matchRoute('DELETE', '/api/book')
84
+
85
+ res = await router.matchRoute('DELETE', '/api/book')
82
86
  expect(res).toBeNull()
83
87
  })
84
88
  })
package/src/util.js ADDED
@@ -0,0 +1,26 @@
1
+ const splitPath = (path) => {
2
+ path = path.split(/\//) // faster than path.split('/')
3
+ if (path[0] === '') {
4
+ path.shift()
5
+ }
6
+ return path
7
+ }
8
+
9
+ const getPattern = (label) => {
10
+ // :id{[0-9]+} => ([0-9]+)
11
+ // :id => (.+)
12
+ //const name = ''
13
+ const match = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/)
14
+ if (match) {
15
+ if (match[2]) {
16
+ return [match[1], '(' + match[2] + ')']
17
+ } else {
18
+ return [match[1], '(.+)']
19
+ }
20
+ }
21
+ }
22
+
23
+ module.exports = {
24
+ splitPath,
25
+ getPattern,
26
+ }
@@ -0,0 +1,29 @@
1
+ const { splitPath, getPattern, getParamName } = require('./util')
2
+
3
+ describe('Utility methods', () => {
4
+ it('splitPath', () => {
5
+ let ps = splitPath('/')
6
+ expect(ps[0]).toBe('')
7
+ ps = splitPath('/hello')
8
+ expect(ps[0]).toBe('hello')
9
+ ps = splitPath('*')
10
+ expect(ps[0]).toBe('*')
11
+ ps = splitPath('/wildcard-abc/*/wildcard-efg')
12
+ expect(ps[0]).toBe('wildcard-abc')
13
+ expect(ps[1]).toBe('*')
14
+ expect(ps[2]).toBe('wildcard-efg')
15
+ ps = splitPath('/map/:location/events')
16
+ expect(ps[0]).toBe('map')
17
+ expect(ps[1]).toBe(':location')
18
+ expect(ps[2]).toBe('events')
19
+ })
20
+
21
+ it('getPattern', () => {
22
+ let res = getPattern(':id')
23
+ expect(res[0]).toBe('id')
24
+ expect(res[1]).toBe('(.+)')
25
+ res = getPattern(':id{[0-9]+}')
26
+ expect(res[0]).toBe('id')
27
+ expect(res[1]).toBe('([0-9]+)')
28
+ })
29
+ })
@@ -1,28 +0,0 @@
1
- const Hono = require('../../src/hono')
2
- const app = Hono()
3
-
4
- // Middleware
5
- const logger = (c, next) => {
6
- console.log(`[${c.req.method}] ${c.req.url}`)
7
- next()
8
- }
9
- const addHeader = (c, next) => {
10
- next()
11
- c.res.headers.append('X-message', 'This is addHeader middleware!')
12
- }
13
-
14
- // Mount middleware
15
- app.use('*', logger)
16
- app.use('/hello', addHeader)
17
-
18
- // Routing
19
- app.get('/', () => new Response('Hono!!'))
20
- app.get('/hello', () => new Response('This is /hello'))
21
-
22
- app.get('/entry/:id', (c) => {
23
- const id = c.req.params('id')
24
- return new Response(`Your ID is ${id}`)
25
- })
26
-
27
- // addEventListener
28
- app.fire()
@@ -1,13 +0,0 @@
1
- {
2
- "name": "sandbox",
3
- "version": "1.0.0",
4
- "lockfileVersion": 2,
5
- "requires": true,
6
- "packages": {
7
- "": {
8
- "name": "sandbox",
9
- "version": "1.0.0",
10
- "license": "ISC"
11
- }
12
- }
13
- }
@@ -1,11 +0,0 @@
1
- {
2
- "name": "hono-example-basic",
3
- "version": "0.0.1",
4
- "description": "",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
8
- },
9
- "author": "Yusuke Wada <yusuke@kamawada.com> (https://github.com/yusukebe)",
10
- "license": "MIT"
11
- }
@@ -1,8 +0,0 @@
1
- name = "hono-example-basic"
2
- type = "webpack"
3
- route = ''
4
- zone_id = ''
5
- usage_model = ''
6
- compatibility_flags = []
7
- workers_dev = true
8
- compatibility_date = "2021-12-15"