slower 2.1.1 → 2.1.3

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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/src/slower.js +104 -8
  3. package/src/utils.js +17 -13
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "path-to-regexp": "^6.2.2"
4
4
  },
5
5
  "name": "slower",
6
- "version": "2.1.1",
6
+ "version": "2.1.3",
7
7
  "main": "index.js",
8
8
  "devDependencies": {},
9
9
  "scripts": {
package/src/slower.js CHANGED
@@ -12,6 +12,7 @@ const utils = require('./utils');
12
12
 
13
13
  const MIME_TABLE = require('./mimetable.json');
14
14
  const HTTP_VERBS = http.METHODS.map(v => v.toLowerCase());
15
+ const MATCH_ANY = '/(.{0,})';
15
16
 
16
17
  class SlowerRouter {
17
18
  #server;
@@ -33,9 +34,18 @@ class SlowerRouter {
33
34
 
34
35
  // Create basic route shortcuts
35
36
  // get(), post(), put(), delete()
37
+ // They can be used with either 1 or 2 params
38
+ /**
39
+ * app.get({path}, {handler}) -> apply handler for a specific route
40
+ * or
41
+ * app.get({handler}) -> apply handler for any route for a specific method
42
+ *
43
+ */
36
44
  for (let verb of HTTP_VERBS) {
37
45
  this.layers.set(verb, new Map());
38
46
  this[verb] = function (path, callback) {
47
+ if (typeof path === 'function')
48
+ return this.#setRoute(verb, MATCH_ANY, path);
39
49
  return this.#setRoute(verb, path, callback);
40
50
  };
41
51
  }
@@ -57,6 +67,8 @@ class SlowerRouter {
57
67
  // Get all routes that match the URL and join with middlewares to cycle
58
68
  let foundRoutes = utils.getMatchingRoute(req.url, req.method, self.layers);
59
69
  let layers = foundRoutes;
70
+ // If there are no layers, add an Error:404 special layer (not found)
71
+ if (layers.length === 0) layers.push(utils.noLayersFoundFallback);
60
72
 
61
73
  // Set properties on request and response objects
62
74
  req = await setupRequest(req);
@@ -99,20 +111,44 @@ class SlowerRouter {
99
111
  * @param {String} path
100
112
  * @param {Function} handler
101
113
  * @returns {SlowerRouter}
114
+ * @example Applies a middleware for all methods, for a specific path
115
+ * app.all('/img/:id', (req, res, next) => {console.log(...); next()})
116
+ */
117
+ /**
118
+ * Create a global middleware for a specific verb (all paths for that method)
119
+ * @info This is the same as using "app[method]({callback})", without a path. Like: app.get(() => {});
120
+ * @overload
121
+ * @param {string} verb (one of the HTTP verbs)
122
+ * @param {Function} handler
123
+ * @returns {SlowerRouter}
124
+ * @example Applies a middleware for all GET requests
125
+ * app.all('get', (req, res, next) => {console.log(...); next()})
102
126
  */
103
127
  /**
104
128
  * Create a global middleware (all paths and all HTTP methods)
105
129
  * @overload
106
130
  * @param {Function} handler
107
131
  * @returns {SlowerRouter}
132
+ * @example Applies a middleware for all HTTP requests (of any method)
133
+ * app.all((req, res, next) => {console.log(...); next()})
108
134
  */
109
135
  all (path, handler) {
110
- if (typeof path === 'string')
136
+ // function signature: app.all({METHOD}, {HANDLER})
137
+ // example: app.all('post', () => {});
138
+ if (typeof path === 'string' && HTTP_VERBS.includes(path.toLowerCase()))
139
+ this.#setRoute(path, MATCH_ANY, handler);
140
+
141
+ // function signature: app.all({PATH}, {HANDLER})
142
+ // example: app.all('/api', () => {});
143
+ else if (typeof path === 'string')
111
144
  for (let verb of HTTP_VERBS) this.#setRoute(verb, path, handler);
112
- else if (typeof path !== 'function')
113
- throw new Error('<SlowerRouter>.use :: "handler" parameter must be of type Function');
114
- else for (let verb of HTTP_VERBS) this.#setRoute(verb, '/(.{0,})', path);
115
- // this.middlewares.add(handlerA);
145
+
146
+ // function signature: app.all({HANDLER})
147
+ // example: app.all(() => {});
148
+ else if (typeof path === 'function')
149
+ for (let verb of HTTP_VERBS) this.#setRoute(verb, MATCH_ANY, path);
150
+
151
+ else throw new Error('<SlowerRouter>.use :: "handler" parameter must be of type Function');
116
152
  return this;
117
153
  }
118
154
  // Just a more comprehensive call to app.all for defining middlewares
@@ -183,8 +219,68 @@ class SlowerRouter {
183
219
  }
184
220
  return this;
185
221
  }
222
+
223
+ /**
224
+ * Creates a temporary synced mini-router for a specific path
225
+ * Allows to declare multiple handlers for methods of a specific path
226
+ * @param {string} path
227
+ * @returns {SlowerMicroRouter}
228
+ * @example
229
+ * app.route('/books')
230
+ * .get((req, res) => console.log('you retrieved a book with GET'))
231
+ * .post((req, res) => console.log('you added a book with POST'))
232
+ * ;
233
+ */
234
+ route (path) {
235
+ return new SlowerMicroRouter(path, this.layers);
236
+ }
186
237
  }
187
238
 
239
+
240
+ /**
241
+ * Used as the class for micro-routing with "app.route"
242
+ *
243
+ * only method acessors (.get(), .post(), .put(), ...)
244
+ * and .all() and .use()
245
+ *
246
+ * .static() is not allowed
247
+ */
248
+ class SlowerMicroRouter {
249
+ constructor (path, layerPool) {
250
+ this.path = path;
251
+ this.layers = layerPool;
252
+ }
253
+
254
+ #setRoute (method, handler) {
255
+ const path = this.path;
256
+ if (typeof method !== 'string')
257
+ throw new Error('<SlowerSubRouter>.route :: "method" parameter must be of type String');
258
+ if (typeof path !== 'string' && path?.constructor?.name !== 'RegExp')
259
+ throw new Error('<SlowerSubRouter>.route :: "path" parameter must be of type Function, String or RegExp');
260
+ if (typeof handler !== 'function')
261
+ throw new Error('<SlowerSubRouter>.route :: "handler" parameter must be of type Function');
262
+ this.layers.push({ method, path, handler });
263
+ return this;
264
+ }
265
+
266
+ all (handler) {
267
+ const path = this.path;
268
+ if (typeof path === 'string')
269
+ for (let verb of HTTP_VERBS) this.#setRoute(verb, path, handler);
270
+ else if (typeof path !== 'function')
271
+ throw new Error('<SlowerSubRouter>.use :: "handler" parameter must be of type Function');
272
+ else for (let verb of HTTP_VERBS) this.#setRoute(verb, '/(.{0,})', path);
273
+ return this;
274
+ }
275
+ // Just a more comprehensive call to app.all for defining middlewares
276
+ use (...b) { this.all(...b); return this; };
277
+ }
278
+
279
+
280
+ /**
281
+ * Used as the class for modular routers
282
+ * used in "slower.Router()"
283
+ */
188
284
  class SlowerSubRouter {
189
285
  constructor () {
190
286
  this.METHODS = HTTP_VERBS;
@@ -228,12 +324,12 @@ class SlowerSubRouter {
228
324
  }
229
325
 
230
326
  // Create basic main routing creation
231
- function Slower (options) {
327
+ function slower (options) {
232
328
  return new SlowerRouter(options);
233
329
  }
234
330
  // Add the subrouter class
235
- Slower.Router = function () {
331
+ slower.Router = function () {
236
332
  return new SlowerSubRouter();
237
333
  }
238
334
 
239
- module.exports = Slower;
335
+ module.exports = slower;
package/src/utils.js CHANGED
@@ -1,16 +1,4 @@
1
1
 
2
-
3
- // https://dev.to/thiagomr/como-funciona-o-express-js-criando-um-http-server-express-like-do-zero-sem-frameworks-125p
4
-
5
- // https://dev.to/wesleymreng7/creating-your-own-expressjs-from-scratch-part-1-basics-methods-and-routing-a8
6
- // https://dev.to/wesleymreng7/creating-your-own-expressjs-from-scratch-part-2-middlewares-and-controllers-2fbc
7
- // https://dev.to/wesleymreng7/creating-your-own-expressjs-from-scratch-part-3-treating-request-and-response-objects-4ecf
8
- // https://dev.to/wesleymreng7/creating-your-own-expressjs-from-scratch-part-4-modular-router-and-global-middlewares-560m
9
- // https://dev.to/wesleymreng7/creating-your-own-expressjs-from-scratch-part-5-serving-static-files-3e11
10
- // https://dev.to/wesleymreng7/creating-your-own-expressjs-from-scratch-part-6-creating-a-body-parser-middleware-15e7
11
-
12
- // https://thecodebarbarian.com/write-your-own-express-from-scratch
13
-
14
2
  const { statSync, readdirSync } = require('node:fs')
15
3
  const { join } = require('node:path');
16
4
  const { parse } = require('node:querystring');
@@ -58,4 +46,20 @@ const getURLPathBody = (urlPath = '') => urlPath.split('?')[0] || '';
58
46
  // /page?foo=bar&abc=123 -> { foo: 'bar', abc: '123' }
59
47
  const getURLQueryString = (urlPath = '') => parse((urlPath.split('?')[1] || '').split('#')[0]);
60
48
 
61
- module.exports = { getMatchingRoute, getFiles, normalizeAddress, getFileExtension, getURLPathBody, getURLQueryString };
49
+ const noLayersFoundFallback = (req, res) =>
50
+ res.status(404).send(
51
+ `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8">` +
52
+ `<title>Error</title></head><body>` +
53
+ `<pre>Cannot ${req.method.toUpperCase()} ${req.url}</pre></body></html>`
54
+ )
55
+ ;
56
+
57
+ module.exports = {
58
+ getMatchingRoute,
59
+ getFiles,
60
+ normalizeAddress,
61
+ getFileExtension,
62
+ getURLPathBody,
63
+ getURLQueryString,
64
+ noLayersFoundFallback
65
+ };