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.
- package/package.json +1 -1
- package/src/slower.js +104 -8
- package/src/utils.js +17 -13
package/package.json
CHANGED
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
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
|
327
|
+
function slower (options) {
|
|
232
328
|
return new SlowerRouter(options);
|
|
233
329
|
}
|
|
234
330
|
// Add the subrouter class
|
|
235
|
-
|
|
331
|
+
slower.Router = function () {
|
|
236
332
|
return new SlowerSubRouter();
|
|
237
333
|
}
|
|
238
334
|
|
|
239
|
-
module.exports =
|
|
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
|
-
|
|
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
|
+
};
|