@jnode/server 2.0.1 → 2.1.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.
- package/README.md +2 -1
- package/package.json +1 -1
- package/src/handlers.js +1 -1
- package/src/routers.js +31 -7
package/README.md
CHANGED
|
@@ -264,10 +264,11 @@ We provide two methods to use them:
|
|
|
264
264
|
- `<METHOD>/<path_segment>[/<path_segment>...]` [router](#class-serverrouter) | [handler-extended](#handler-extended) Used when the method matches; equals to `'/<path_segment>': r.Method({ '<METHOD>': <value> })`. E.G., `'GET/meow': 'Meow!'` (only works for HTTP method `'GET'`).
|
|
265
265
|
- `@<METHOD>/<path_segment>[/<path_segment>...]` [router](#class-serverrouter) | [handler-extended](#handler-extended) Used when both the path resolver ends and the method matches; equals to `'/<path_segment>': r.Path(r.Method({ '<METHOD>': <value> }))`. E.G., `'@GET/meow': 'Meow!'` (only works for path `'/meow'` but not `'/meow/something'` and request method is `'GET'`).
|
|
266
266
|
- `*` [router](#class-serverrouter) | [handler-extended](#handler-extended) Any path segment. E.G. `'*': h.Text('Meow? Nothing here!', { statusCode: 404 })`.
|
|
267
|
+
- `/%:<path_parameter_name>` [router](#class-serverrouter) | [handler-extended](#handler-extended) Match any segment (if exists) and save the segment to `ctx.params` by `<path_parameter_name>`. Do the similar thing as [`PathArgRouter`](#router-pathargrouterparamname-next).
|
|
267
268
|
|
|
268
269
|
`PathRouter` is probably the most important router; almost every server needs it!
|
|
269
270
|
|
|
270
|
-
By the way,
|
|
271
|
+
By the way, if you’re looking for a universal matching character, use `'/%:'` instead of `'/*'` (this will match to `'*'` in a literal sense).
|
|
271
272
|
|
|
272
273
|
#### How it works?
|
|
273
274
|
|
package/package.json
CHANGED
package/src/handlers.js
CHANGED
|
@@ -54,7 +54,7 @@ class DataHandler {
|
|
|
54
54
|
// file handler: local file
|
|
55
55
|
class FileHandler {
|
|
56
56
|
constructor(file, options = {}) {
|
|
57
|
-
this.file = path.resolve(
|
|
57
|
+
this.file = path.resolve(file);
|
|
58
58
|
this.options = options;
|
|
59
59
|
|
|
60
60
|
// range may be disabled by `options.disableRange` or when `statusCode` is set to non-200 value
|
package/src/routers.js
CHANGED
|
@@ -29,20 +29,30 @@ class PathRouter {
|
|
|
29
29
|
// key format: '[@ (path end check)][METHOD (method check)]/path/segments'
|
|
30
30
|
// example: '@ GET /cat/names', 'POST /cats', '/api'
|
|
31
31
|
const routeEnd = key.startsWith('@');
|
|
32
|
-
const routeMethod = key.substring(routeEnd ? 1 : 0, firstSlashIndex).trim()
|
|
33
|
-
const routePath = key.substring(firstSlashIndex).split('/').slice(1)
|
|
32
|
+
const routeMethod = key.substring(routeEnd ? 1 : 0, firstSlashIndex).trim();
|
|
33
|
+
const routePath = key.substring(firstSlashIndex).split('/').slice(1);
|
|
34
34
|
|
|
35
35
|
// expand map
|
|
36
36
|
let current = this.map;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
let args = [];
|
|
38
|
+
for (let segment of routePath) {
|
|
39
|
+
if (segment.startsWith('%:')) {
|
|
40
|
+
args.push(segment.substring(2));
|
|
41
|
+
if (!current[':']) current[':'] = {};
|
|
42
|
+
current = current[':'];
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
segment = '/' + decodeURIComponent(segment);
|
|
47
|
+
if (!current[segment]) current[segment] = {};
|
|
48
|
+
current = current[segment];
|
|
40
49
|
}
|
|
41
50
|
|
|
42
51
|
// '*' for non-end check, '@' for end check
|
|
43
52
|
// '*' for any method, 'METHOD' for specific method
|
|
44
53
|
if (!current[routeEnd ? '@' : '*']) current[routeEnd ? '@' : '*'] = {};
|
|
45
54
|
current[routeEnd ? '@' : '*'][routeMethod || '*'] = value;
|
|
55
|
+
if (args.length > 0) current[routeEnd ? '@' : '*']['::' + (routeMethod || '*')] = args;
|
|
46
56
|
}
|
|
47
57
|
}
|
|
48
58
|
|
|
@@ -52,14 +62,23 @@ class PathRouter {
|
|
|
52
62
|
let result = this.map['*'];
|
|
53
63
|
let resultPointer = env.pathPointer;
|
|
54
64
|
let current = this.map;
|
|
65
|
+
let resultArgs = [];
|
|
66
|
+
let currentArgs = [];
|
|
67
|
+
let resultArgNames = [];
|
|
55
68
|
while (env.pathPointer < env.path.length) {
|
|
56
|
-
|
|
57
|
-
if (!current[segment]) break;
|
|
69
|
+
let segment = '/' + env.path[env.pathPointer];
|
|
70
|
+
if (!current[segment] && !current[':']) break;
|
|
71
|
+
if (!current[segment]) {
|
|
72
|
+
segment = ':';
|
|
73
|
+
currentArgs.push(env.path[env.pathPointer]);
|
|
74
|
+
}
|
|
58
75
|
|
|
59
76
|
// prepare fallback
|
|
60
77
|
if (current[segment]['*']?.['*'] || current[segment]['*']?.[ctx.method]) {
|
|
61
78
|
result = current[segment]['*'][ctx.method] ?? current[segment]['*']['*'];
|
|
62
79
|
resultPointer = env.pathPointer + 1;
|
|
80
|
+
resultArgs = [...currentArgs];
|
|
81
|
+
resultArgNames = current[segment]['*']['::' + ctx.method] ?? current[segment]['*']['::*'];
|
|
63
82
|
}
|
|
64
83
|
|
|
65
84
|
current = current[segment];
|
|
@@ -69,10 +88,15 @@ class PathRouter {
|
|
|
69
88
|
if (env.pathPointer >= env.path.length && (current['@']?.['*'] || current['@']?.[ctx.method])) {
|
|
70
89
|
result = current['@'][ctx.method] ?? current['@']['*'];
|
|
71
90
|
resultPointer = env.pathPointer;
|
|
91
|
+
resultArgs = currentArgs;
|
|
92
|
+
resultArgNames = current['@']['::' + ctx.method] ?? current['@']['::*'];
|
|
72
93
|
}
|
|
73
94
|
}
|
|
74
95
|
|
|
75
96
|
env.pathPointer = resultPointer;
|
|
97
|
+
if (resultArgNames) resultArgs.forEach((arg, index) => {
|
|
98
|
+
ctx.params[resultArgNames[index]] = arg;
|
|
99
|
+
});
|
|
76
100
|
return result;
|
|
77
101
|
}
|
|
78
102
|
}
|