@trenskow/app 0.8.60 → 0.9.0

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.
@@ -15,7 +15,9 @@
15
15
  "args": [
16
16
  "${workspaceFolder}/test/index.js",
17
17
  "--timeout",
18
- "0"
18
+ "0",
19
+ "--skip",
20
+ "20"
19
21
  ]
20
22
  }
21
23
  ]
package/lib/endpoint.js CHANGED
@@ -1,20 +1,16 @@
1
1
  //
2
2
  // endpoint.js
3
3
  // @trenskow/app
4
- //
4
+ //
5
5
  // Created by Kristian Trenskow on 2021/11/08
6
6
  // For license see LICENSE.
7
- //
8
-
9
- import { METHODS } from 'http';
7
+ //
10
8
 
11
9
  import ApiError from '@trenskow/api-error';
12
10
 
13
11
  import Router from './router.js';
14
12
 
15
- import { isObject, matchPath, resolveInlineImport } from './util.js';
16
-
17
- const methods = METHODS.map((method) => method.toLowerCase());
13
+ import { isObject, matchPath, resolveInlineImport, methods } from './util.js';
18
14
 
19
15
  export default class Endpoint extends Router {
20
16
 
@@ -59,9 +55,12 @@ export default class Endpoint extends Router {
59
55
  throw new Error('Handler must be a function.');
60
56
  }
61
57
 
62
- const existing = this._layers.findIndex((layer) => layer.method === method);
58
+ const existing = this._layers.findIndex((layer) => {
59
+ return layer.method === method && layer.handler === this._handleMethod;
60
+ });
61
+
63
62
  if (existing !== -1) {
64
- this._layers.splice(existing, 1);
63
+ throw new Error(`Endpoint already has a \`${method}\` handler.`);
65
64
  }
66
65
 
67
66
  this._layers.push({
package/lib/router.js CHANGED
@@ -6,15 +6,23 @@
6
6
  // For license see LICENSE.
7
7
  //
8
8
 
9
- import { isObject, resolveInlineImport } from './util.js';
9
+ import { isObject, resolveInlineImport, methods } from './util.js';
10
10
 
11
11
  export default class Router {
12
12
 
13
13
  constructor() {
14
+
14
15
  this._layers = [];
16
+
17
+ methods.forEach((method) => {
18
+ return this.use[method] = (...handlers) => {
19
+ return this.#_use(handlers, method);
20
+ };
21
+ });
22
+
15
23
  }
16
24
 
17
- use(...handlers) {
25
+ #_use(handlers, method) {
18
26
 
19
27
  handlers = [].concat(...handlers);
20
28
 
@@ -28,13 +36,18 @@ export default class Router {
28
36
 
29
37
  this._layers.push({
30
38
  handler: this._handleUse,
31
- handlers
39
+ handlers,
40
+ method
32
41
  });
33
42
 
34
43
  return this;
35
44
 
36
45
  }
37
46
 
47
+ use(...handlers) {
48
+ return this.#_use(handlers, 'all');
49
+ }
50
+
38
51
  mixin(router) {
39
52
 
40
53
  if (isObject(router)) {
@@ -94,9 +107,15 @@ export default class Router {
94
107
 
95
108
  async _handleUse(layer, _, context, next) {
96
109
 
97
- for (let handler of layer.handlers) {
98
- await handler(context);
99
- if (context.state !== 'routing') return;
110
+ const { request } = context;
111
+
112
+ if (layer.method === 'all' || request.method.toLowerCase() === layer.method) {
113
+
114
+ for (let handler of layer.handlers) {
115
+ await handler(context);
116
+ if (context.state !== 'routing') return;
117
+ }
118
+
100
119
  }
101
120
 
102
121
  return await next();
package/lib/util.js CHANGED
@@ -1,13 +1,17 @@
1
1
  //
2
2
  // is-object.js
3
3
  // @trenskow/app
4
- //
4
+ //
5
5
  // Created by Kristian Trenskow on 2021/11/07
6
6
  // For license see LICENSE.
7
- //
7
+ //
8
+
9
+ import { METHODS } from 'http';
8
10
 
9
11
  import caseit from '@trenskow/caseit';
10
12
 
13
+ const methods = METHODS.map((method) => method.toLowerCase());
14
+
11
15
  const isObject = (value) => value?.constructor === Object;
12
16
 
13
17
  const matchPath = (path1, path2, { application: { path: { matchMode }} }) => {
@@ -21,6 +25,7 @@ const resolveInlineImport = (value) => {
21
25
  };
22
26
 
23
27
  export {
28
+ methods,
24
29
  isObject,
25
30
  matchPath,
26
31
  resolveInlineImport
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trenskow/app",
3
- "version": "0.8.60",
3
+ "version": "0.9.0",
4
4
  "description": "A small HTTP router.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -27,13 +27,14 @@
27
27
  "devDependencies": {
28
28
  "@eslint/eslintrc": "^3.2.0",
29
29
  "@eslint/js": "^9.13.0",
30
+ "chai": "^5.1.2",
30
31
  "eslint": "^9.17.0",
31
32
  "globals": "^15.14.0",
32
33
  "mocha": "^11.0.1",
33
34
  "supertest": "^7.0.0"
34
35
  },
35
36
  "dependencies": {
36
- "@trenskow/api-error": "^2.5.15",
37
+ "@trenskow/api-error": "^2.5.16",
37
38
  "@trenskow/caseit": "^1.4.6"
38
39
  }
39
40
  }
package/test/index.js CHANGED
@@ -7,13 +7,13 @@
7
7
  //
8
8
 
9
9
  import supertest from 'supertest';
10
- import { Endpoint, Router } from '../lib/index.js';
10
+ import { expect } from 'chai';
11
11
 
12
- import Application from '../lib/index.js';
12
+ import { Application, Endpoint, Router } from '../lib/index.js';
13
13
 
14
14
  process.on('unhandledRejection', (error) => {
15
15
  console.error(error.stack);
16
- process.exit (1);
16
+ process.eit (1);
17
17
  });
18
18
 
19
19
  let app;
@@ -104,22 +104,12 @@ describe('Application', () => {
104
104
 
105
105
  });
106
106
 
107
- it ('should ignore multiple GET method handlers and respond with 200 and `Hello, World!`.', async () => {
108
-
109
- app.root(
107
+ it ('should throw an error if endpoint already has a handler for method.', async () => {
108
+ expect(() => {
110
109
  new Endpoint()
111
- .get(() => 'Ignore this!')
112
- .post(() => 'Not used')
113
- .get(
114
- () => 'Hello, World!',
115
- () => { /* Ignore this */ })
116
- );
117
-
118
- await request
119
- .get('/')
120
- .expect('Content-Type', 'text/plain; charset=utf-8')
121
- .expect(200, 'Hello, World!');
122
-
110
+ .get(() => 'Hello, World!')
111
+ .get(() => 'Hello, World! (2)');
112
+ }).to.throw('Endpoint already has a `get` handler.');
123
113
  });
124
114
 
125
115
  it ('should ignore GET method handler when path has been rewritten and respond with 200 and `Hello, World!`.', async () => {
@@ -244,7 +234,7 @@ describe('Application', () => {
244
234
 
245
235
  });
246
236
 
247
- it ('should respond with a something generated in a transform.', async () => {
237
+ it ('should respond with a value generated in a transform.', async () => {
248
238
 
249
239
  app.root(
250
240
  new Endpoint()
@@ -261,6 +251,38 @@ describe('Application', () => {
261
251
 
262
252
  });
263
253
 
254
+ it ('should respond with an ignored value generated in a specific transform.', async () => {
255
+
256
+ app.root(
257
+ new Endpoint()
258
+ .use(({ parameters }) => parameters.value = 'my-value')
259
+ .use.post(({ parameters }) => parameters.value = 'my-value-post')
260
+ .get(({ parameters: { value }}) => value)
261
+ );
262
+
263
+ await request
264
+ .get('/')
265
+ .expect('Content-Type', 'text/plain; charset=utf-8')
266
+ .expect(200, 'my-value');
267
+
268
+ });
269
+
270
+ it ('should respond with a value generated in a specific transform.', async () => {
271
+
272
+ app.root(
273
+ new Endpoint()
274
+ .use(({ parameters }) => parameters.value = 'my-value')
275
+ .use.get(({ parameters }) => parameters.value = 'my-value-get')
276
+ .get(({ parameters: { value }}) => value)
277
+ );
278
+
279
+ await request
280
+ .get('/')
281
+ .expect('Content-Type', 'text/plain; charset=utf-8')
282
+ .expect(200, 'my-value-get');
283
+
284
+ });
285
+
264
286
  it ('should respond with a value when using PUT on a catch-all method.', async () => {
265
287
 
266
288
  app.root(