slower 2.1.0 → 2.1.2

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 -9
  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.0",
6
+ "version": "2.1.2",
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
@@ -179,13 +215,72 @@ class SlowerRouter {
179
215
  this.static(layer.directoryPath, mount(layer.mountPath));
180
216
  continue;
181
217
  }
182
- console.log(layer)
183
218
  this.#setRoute(layer.method, mount(layer.path), layer.handler);
184
219
  }
185
220
  return this;
186
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
+ }
187
237
  }
188
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
+ */
189
284
  class SlowerSubRouter {
190
285
  constructor () {
191
286
  this.METHODS = HTTP_VERBS;
@@ -229,12 +324,12 @@ class SlowerSubRouter {
229
324
  }
230
325
 
231
326
  // Create basic main routing creation
232
- function Slower (options) {
327
+ function slower (options) {
233
328
  return new SlowerRouter(options);
234
329
  }
235
330
  // Add the subrouter class
236
- Slower.Router = function () {
331
+ slower.Router = function () {
237
332
  return new SlowerSubRouter();
238
333
  }
239
334
 
240
- 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
+ };