@tsed/platform-serverless 6.88.1 → 6.89.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.
Files changed (68) hide show
  1. package/lib/{builder → cjs/builder}/PlatformServerless.d.ts +0 -0
  2. package/lib/cjs/builder/PlatformServerless.js +156 -0
  3. package/lib/cjs/builder/PlatformServerless.js.map +1 -0
  4. package/lib/{builder → cjs/builder}/PlatformServerlessHandler.d.ts +0 -0
  5. package/lib/cjs/builder/PlatformServerlessHandler.js +93 -0
  6. package/lib/cjs/builder/PlatformServerlessHandler.js.map +1 -0
  7. package/lib/{domain → cjs/domain}/ServerlessContext.d.ts +0 -0
  8. package/lib/cjs/domain/ServerlessContext.js +26 -0
  9. package/lib/cjs/domain/ServerlessContext.js.map +1 -0
  10. package/lib/{domain → cjs/domain}/ServerlessRequest.d.ts +0 -0
  11. package/lib/cjs/domain/ServerlessRequest.js +80 -0
  12. package/lib/cjs/domain/ServerlessRequest.js.map +1 -0
  13. package/lib/{domain → cjs/domain}/ServerlessResponse.d.ts +0 -0
  14. package/lib/cjs/domain/ServerlessResponse.js +193 -0
  15. package/lib/cjs/domain/ServerlessResponse.js.map +1 -0
  16. package/lib/{index.d.ts → cjs/index.d.ts} +0 -0
  17. package/lib/cjs/index.js +23 -0
  18. package/lib/cjs/index.js.map +1 -0
  19. package/lib/{services → cjs/services}/PlatformServerlessTest.d.ts +0 -0
  20. package/lib/cjs/services/PlatformServerlessTest.js +196 -0
  21. package/lib/cjs/services/PlatformServerlessTest.js.map +1 -0
  22. package/lib/{utils → cjs/utils}/getRequestId.d.ts +0 -0
  23. package/lib/cjs/utils/getRequestId.js +13 -0
  24. package/lib/cjs/utils/getRequestId.js.map +1 -0
  25. package/lib/{utils → cjs/utils}/setResponseHeaders.d.ts +0 -0
  26. package/lib/cjs/utils/setResponseHeaders.js +35 -0
  27. package/lib/cjs/utils/setResponseHeaders.js.map +1 -0
  28. package/lib/esm/builder/PlatformServerless.js +133 -0
  29. package/lib/esm/builder/PlatformServerless.js.map +1 -0
  30. package/lib/esm/builder/PlatformServerlessHandler.js +90 -0
  31. package/lib/esm/builder/PlatformServerlessHandler.js.map +1 -0
  32. package/lib/esm/domain/ServerlessContext.js +22 -0
  33. package/lib/esm/domain/ServerlessContext.js.map +1 -0
  34. package/lib/esm/domain/ServerlessRequest.js +76 -0
  35. package/lib/esm/domain/ServerlessRequest.js.map +1 -0
  36. package/lib/esm/domain/ServerlessResponse.js +189 -0
  37. package/lib/esm/domain/ServerlessResponse.js.map +1 -0
  38. package/lib/esm/index.js +11 -0
  39. package/lib/esm/index.js.map +1 -0
  40. package/lib/esm/services/PlatformServerlessTest.js +191 -0
  41. package/lib/esm/services/PlatformServerlessTest.js.map +1 -0
  42. package/lib/esm/utils/getRequestId.js +9 -0
  43. package/lib/esm/utils/getRequestId.js.map +1 -0
  44. package/lib/esm/utils/setResponseHeaders.js +31 -0
  45. package/lib/esm/utils/setResponseHeaders.js.map +1 -0
  46. package/lib/types/builder/PlatformServerless.d.ts +31 -0
  47. package/lib/types/builder/PlatformServerlessHandler.d.ts +19 -0
  48. package/lib/types/domain/ServerlessContext.d.ts +19 -0
  49. package/lib/types/domain/ServerlessRequest.d.ts +55 -0
  50. package/lib/types/domain/ServerlessResponse.d.ts +105 -0
  51. package/lib/types/index.d.ts +9 -0
  52. package/lib/types/services/PlatformServerlessTest.d.ts +46 -0
  53. package/lib/types/utils/getRequestId.d.ts +2 -0
  54. package/lib/types/utils/setResponseHeaders.d.ts +5 -0
  55. package/package.json +17 -13
  56. package/tsconfig.compile.esm.json +23 -0
  57. package/lib/index-a6c91998.js +0 -955
  58. package/lib/index-a6c91998.js.map +0 -1
  59. package/lib/index-a7574150.js +0 -975
  60. package/lib/index-a7574150.js.map +0 -1
  61. package/lib/index-b255dcf0.js +0 -2350
  62. package/lib/index-b255dcf0.js.map +0 -1
  63. package/lib/index-eeb85309.js +0 -2354
  64. package/lib/index-eeb85309.js.map +0 -1
  65. package/lib/index.js +0 -90
  66. package/lib/index.js.map +0 -1
  67. package/lib/index.modern.js +0 -12
  68. package/lib/index.modern.js.map +0 -1
@@ -1,2354 +0,0 @@
1
- var assert = require('assert');
2
- var http = require('http');
3
- var index$1 = require('./index-a7574150.js');
4
-
5
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
6
-
7
- var assert__default = /*#__PURE__*/_interopDefaultLegacy(assert);
8
- var http__default = /*#__PURE__*/_interopDefaultLegacy(http);
9
-
10
- var UTF8_ACCEPT = 12;
11
- var UTF8_REJECT = 0;
12
- var UTF8_DATA = [// The first part of the table maps bytes to character to a transition.
13
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 7, 10, 9, 9, 9, 11, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // The second part of the table maps a state to a new state when adding a
14
- // transition.
15
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 24, 36, 48, 60, 72, 84, 96, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // The third part maps the current transition to a mask that needs to apply
16
- // to the byte.
17
- 0x7F, 0x3F, 0x3F, 0x3F, 0x00, 0x1F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x07];
18
-
19
- function decodeURIComponent(uri) {
20
- var percentPosition = uri.indexOf('%');
21
- if (percentPosition === -1) return uri;
22
- var length = uri.length;
23
- var decoded = '';
24
- var last = 0;
25
- var codepoint = 0;
26
- var startOfOctets = percentPosition;
27
- var state = UTF8_ACCEPT;
28
-
29
- while (percentPosition > -1 && percentPosition < length) {
30
- var high = hexCodeToInt(uri[percentPosition + 1], 4);
31
- var low = hexCodeToInt(uri[percentPosition + 2], 0);
32
- var byte = high | low;
33
- var type = UTF8_DATA[byte];
34
- state = UTF8_DATA[256 + state + type];
35
- codepoint = codepoint << 6 | byte & UTF8_DATA[364 + type];
36
-
37
- if (state === UTF8_ACCEPT) {
38
- decoded += uri.slice(last, startOfOctets);
39
- decoded += codepoint <= 0xFFFF ? String.fromCharCode(codepoint) : String.fromCharCode(0xD7C0 + (codepoint >> 10), 0xDC00 + (codepoint & 0x3FF));
40
- codepoint = 0;
41
- last = percentPosition + 3;
42
- percentPosition = startOfOctets = uri.indexOf('%', last);
43
- } else if (state === UTF8_REJECT) {
44
- return null;
45
- } else {
46
- percentPosition += 3;
47
- if (percentPosition < length && uri.charCodeAt(percentPosition) === 37) continue;
48
- return null;
49
- }
50
- }
51
-
52
- return decoded + uri.slice(last);
53
- }
54
-
55
- var HEX = {
56
- '0': 0,
57
- '1': 1,
58
- '2': 2,
59
- '3': 3,
60
- '4': 4,
61
- '5': 5,
62
- '6': 6,
63
- '7': 7,
64
- '8': 8,
65
- '9': 9,
66
- 'a': 10,
67
- 'A': 10,
68
- 'b': 11,
69
- 'B': 11,
70
- 'c': 12,
71
- 'C': 12,
72
- 'd': 13,
73
- 'D': 13,
74
- 'e': 14,
75
- 'E': 14,
76
- 'f': 15,
77
- 'F': 15
78
- };
79
-
80
- function hexCodeToInt(c, shift) {
81
- var i = HEX[c];
82
- return i === undefined ? 255 : i << shift;
83
- }
84
-
85
- var fastDecodeUriComponent = decodeURIComponent;
86
-
87
- function createCommonjsModule(fn) {
88
- var module = { exports: {} };
89
- return fn(module, module.exports), module.exports;
90
- }
91
-
92
- var types$2 = {
93
- ROOT: 0,
94
- GROUP: 1,
95
- POSITION: 2,
96
- SET: 3,
97
- RANGE: 4,
98
- REPETITION: 5,
99
- REFERENCE: 6,
100
- CHAR: 7
101
- };
102
-
103
- const INTS = () => [{
104
- type: types$2.RANGE,
105
- from: 48,
106
- to: 57
107
- }];
108
-
109
- const WORDS = () => {
110
- return [{
111
- type: types$2.CHAR,
112
- value: 95
113
- }, {
114
- type: types$2.RANGE,
115
- from: 97,
116
- to: 122
117
- }, {
118
- type: types$2.RANGE,
119
- from: 65,
120
- to: 90
121
- }].concat(INTS());
122
- };
123
-
124
- const WHITESPACE = () => {
125
- return [{
126
- type: types$2.CHAR,
127
- value: 9
128
- }, {
129
- type: types$2.CHAR,
130
- value: 10
131
- }, {
132
- type: types$2.CHAR,
133
- value: 11
134
- }, {
135
- type: types$2.CHAR,
136
- value: 12
137
- }, {
138
- type: types$2.CHAR,
139
- value: 13
140
- }, {
141
- type: types$2.CHAR,
142
- value: 32
143
- }, {
144
- type: types$2.CHAR,
145
- value: 160
146
- }, {
147
- type: types$2.CHAR,
148
- value: 5760
149
- }, {
150
- type: types$2.RANGE,
151
- from: 8192,
152
- to: 8202
153
- }, {
154
- type: types$2.CHAR,
155
- value: 8232
156
- }, {
157
- type: types$2.CHAR,
158
- value: 8233
159
- }, {
160
- type: types$2.CHAR,
161
- value: 8239
162
- }, {
163
- type: types$2.CHAR,
164
- value: 8287
165
- }, {
166
- type: types$2.CHAR,
167
- value: 12288
168
- }, {
169
- type: types$2.CHAR,
170
- value: 65279
171
- }];
172
- };
173
-
174
- const NOTANYCHAR = () => {
175
- return [{
176
- type: types$2.CHAR,
177
- value: 10
178
- }, {
179
- type: types$2.CHAR,
180
- value: 13
181
- }, {
182
- type: types$2.CHAR,
183
- value: 8232
184
- }, {
185
- type: types$2.CHAR,
186
- value: 8233
187
- }];
188
- }; // Predefined class objects.
189
-
190
-
191
- var words = () => ({
192
- type: types$2.SET,
193
- set: WORDS(),
194
- not: false
195
- });
196
-
197
- var notWords = () => ({
198
- type: types$2.SET,
199
- set: WORDS(),
200
- not: true
201
- });
202
-
203
- var ints = () => ({
204
- type: types$2.SET,
205
- set: INTS(),
206
- not: false
207
- });
208
-
209
- var notInts = () => ({
210
- type: types$2.SET,
211
- set: INTS(),
212
- not: true
213
- });
214
-
215
- var whitespace = () => ({
216
- type: types$2.SET,
217
- set: WHITESPACE(),
218
- not: false
219
- });
220
-
221
- var notWhitespace = () => ({
222
- type: types$2.SET,
223
- set: WHITESPACE(),
224
- not: true
225
- });
226
-
227
- var anyChar = () => ({
228
- type: types$2.SET,
229
- set: NOTANYCHAR(),
230
- not: true
231
- });
232
-
233
- var sets = {
234
- words: words,
235
- notWords: notWords,
236
- ints: ints,
237
- notInts: notInts,
238
- whitespace: whitespace,
239
- notWhitespace: notWhitespace,
240
- anyChar: anyChar
241
- };
242
-
243
- var util = createCommonjsModule(function (module, exports) {
244
- const CTRL = '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ ?';
245
- const SLSH = {
246
- '0': 0,
247
- 't': 9,
248
- 'n': 10,
249
- 'v': 11,
250
- 'f': 12,
251
- 'r': 13
252
- };
253
- /**
254
- * Finds character representations in str and convert all to
255
- * their respective characters
256
- *
257
- * @param {String} str
258
- * @return {String}
259
- */
260
-
261
- exports.strToChars = function (str) {
262
- /* jshint maxlen: false */
263
- var chars_regex = /(\[\\b\])|(\\)?\\(?:u([A-F0-9]{4})|x([A-F0-9]{2})|(0?[0-7]{2})|c([@A-Z[\\\]^?])|([0tnvfr]))/g;
264
- str = str.replace(chars_regex, function (s, b, lbs, a16, b16, c8, dctrl, eslsh) {
265
- if (lbs) {
266
- return s;
267
- }
268
-
269
- var code = b ? 8 : a16 ? parseInt(a16, 16) : b16 ? parseInt(b16, 16) : c8 ? parseInt(c8, 8) : dctrl ? CTRL.indexOf(dctrl) : SLSH[eslsh];
270
- var c = String.fromCharCode(code); // Escape special regex characters.
271
-
272
- if (/[[\]{}^$.|?*+()]/.test(c)) {
273
- c = '\\' + c;
274
- }
275
-
276
- return c;
277
- });
278
- return str;
279
- };
280
- /**
281
- * turns class into tokens
282
- * reads str until it encounters a ] not preceeded by a \
283
- *
284
- * @param {String} str
285
- * @param {String} regexpStr
286
- * @return {Array.<Array.<Object>, Number>}
287
- */
288
-
289
-
290
- exports.tokenizeClass = (str, regexpStr) => {
291
- /* jshint maxlen: false */
292
- var tokens = [];
293
- var regexp = /\\(?:(w)|(d)|(s)|(W)|(D)|(S))|((?:(?:\\)(.)|([^\]\\]))-(?:\\)?([^\]]))|(\])|(?:\\)?([^])/g;
294
- var rs, c;
295
-
296
- while ((rs = regexp.exec(str)) != null) {
297
- if (rs[1]) {
298
- tokens.push(sets.words());
299
- } else if (rs[2]) {
300
- tokens.push(sets.ints());
301
- } else if (rs[3]) {
302
- tokens.push(sets.whitespace());
303
- } else if (rs[4]) {
304
- tokens.push(sets.notWords());
305
- } else if (rs[5]) {
306
- tokens.push(sets.notInts());
307
- } else if (rs[6]) {
308
- tokens.push(sets.notWhitespace());
309
- } else if (rs[7]) {
310
- tokens.push({
311
- type: types$2.RANGE,
312
- from: (rs[8] || rs[9]).charCodeAt(0),
313
- to: rs[10].charCodeAt(0)
314
- });
315
- } else if (c = rs[12]) {
316
- tokens.push({
317
- type: types$2.CHAR,
318
- value: c.charCodeAt(0)
319
- });
320
- } else {
321
- return [tokens, regexp.lastIndex];
322
- }
323
- }
324
-
325
- exports.error(regexpStr, 'Unterminated character class');
326
- };
327
- /**
328
- * Shortcut to throw errors.
329
- *
330
- * @param {String} regexp
331
- * @param {String} msg
332
- */
333
-
334
-
335
- exports.error = (regexp, msg) => {
336
- throw new SyntaxError('Invalid regular expression: /' + regexp + '/: ' + msg);
337
- };
338
- });
339
-
340
- var wordBoundary = () => ({
341
- type: types$2.POSITION,
342
- value: 'b'
343
- });
344
-
345
- var nonWordBoundary = () => ({
346
- type: types$2.POSITION,
347
- value: 'B'
348
- });
349
-
350
- var begin = () => ({
351
- type: types$2.POSITION,
352
- value: '^'
353
- });
354
-
355
- var end = () => ({
356
- type: types$2.POSITION,
357
- value: '$'
358
- });
359
-
360
- var positions = {
361
- wordBoundary: wordBoundary,
362
- nonWordBoundary: nonWordBoundary,
363
- begin: begin,
364
- end: end
365
- };
366
-
367
- var lib = regexpStr => {
368
- var i = 0,
369
- l,
370
- c,
371
- start = {
372
- type: types$2.ROOT,
373
- stack: []
374
- },
375
- // Keep track of last clause/group and stack.
376
- lastGroup = start,
377
- last = start.stack,
378
- groupStack = [];
379
-
380
- var repeatErr = i => {
381
- util.error(regexpStr, `Nothing to repeat at column ${i - 1}`);
382
- }; // Decode a few escaped characters.
383
-
384
-
385
- var str = util.strToChars(regexpStr);
386
- l = str.length; // Iterate through each character in string.
387
-
388
- while (i < l) {
389
- c = str[i++];
390
-
391
- switch (c) {
392
- // Handle escaped characters, inclues a few sets.
393
- case '\\':
394
- c = str[i++];
395
-
396
- switch (c) {
397
- case 'b':
398
- last.push(positions.wordBoundary());
399
- break;
400
-
401
- case 'B':
402
- last.push(positions.nonWordBoundary());
403
- break;
404
-
405
- case 'w':
406
- last.push(sets.words());
407
- break;
408
-
409
- case 'W':
410
- last.push(sets.notWords());
411
- break;
412
-
413
- case 'd':
414
- last.push(sets.ints());
415
- break;
416
-
417
- case 'D':
418
- last.push(sets.notInts());
419
- break;
420
-
421
- case 's':
422
- last.push(sets.whitespace());
423
- break;
424
-
425
- case 'S':
426
- last.push(sets.notWhitespace());
427
- break;
428
-
429
- default:
430
- // Check if c is integer.
431
- // In which case it's a reference.
432
- if (/\d/.test(c)) {
433
- last.push({
434
- type: types$2.REFERENCE,
435
- value: parseInt(c, 10)
436
- }); // Escaped character.
437
- } else {
438
- last.push({
439
- type: types$2.CHAR,
440
- value: c.charCodeAt(0)
441
- });
442
- }
443
-
444
- }
445
-
446
- break;
447
- // Positionals.
448
-
449
- case '^':
450
- last.push(positions.begin());
451
- break;
452
-
453
- case '$':
454
- last.push(positions.end());
455
- break;
456
- // Handle custom sets.
457
-
458
- case '[':
459
- // Check if this class is 'anti' i.e. [^abc].
460
- var not;
461
-
462
- if (str[i] === '^') {
463
- not = true;
464
- i++;
465
- } else {
466
- not = false;
467
- } // Get all the characters in class.
468
-
469
-
470
- var classTokens = util.tokenizeClass(str.slice(i), regexpStr); // Increase index by length of class.
471
-
472
- i += classTokens[1];
473
- last.push({
474
- type: types$2.SET,
475
- set: classTokens[0],
476
- not
477
- });
478
- break;
479
- // Class of any character except \n.
480
-
481
- case '.':
482
- last.push(sets.anyChar());
483
- break;
484
- // Push group onto stack.
485
-
486
- case '(':
487
- // Create group.
488
- var group = {
489
- type: types$2.GROUP,
490
- stack: [],
491
- remember: true
492
- };
493
- c = str[i]; // If if this is a special kind of group.
494
-
495
- if (c === '?') {
496
- c = str[i + 1];
497
- i += 2; // Match if followed by.
498
-
499
- if (c === '=') {
500
- group.followedBy = true; // Match if not followed by.
501
- } else if (c === '!') {
502
- group.notFollowedBy = true;
503
- } else if (c !== ':') {
504
- util.error(regexpStr, `Invalid group, character '${c}'` + ` after '?' at column ${i - 1}`);
505
- }
506
-
507
- group.remember = false;
508
- } // Insert subgroup into current group stack.
509
-
510
-
511
- last.push(group); // Remember the current group for when the group closes.
512
-
513
- groupStack.push(lastGroup); // Make this new group the current group.
514
-
515
- lastGroup = group;
516
- last = group.stack;
517
- break;
518
- // Pop group out of stack.
519
-
520
- case ')':
521
- if (groupStack.length === 0) {
522
- util.error(regexpStr, `Unmatched ) at column ${i - 1}`);
523
- }
524
-
525
- lastGroup = groupStack.pop(); // Check if this group has a PIPE.
526
- // To get back the correct last stack.
527
-
528
- last = lastGroup.options ? lastGroup.options[lastGroup.options.length - 1] : lastGroup.stack;
529
- break;
530
- // Use pipe character to give more choices.
531
-
532
- case '|':
533
- // Create array where options are if this is the first PIPE
534
- // in this clause.
535
- if (!lastGroup.options) {
536
- lastGroup.options = [lastGroup.stack];
537
- delete lastGroup.stack;
538
- } // Create a new stack and add to options for rest of clause.
539
-
540
-
541
- var stack = [];
542
- lastGroup.options.push(stack);
543
- last = stack;
544
- break;
545
- // Repetition.
546
- // For every repetition, remove last element from last stack
547
- // then insert back a RANGE object.
548
- // This design is chosen because there could be more than
549
- // one repetition symbols in a regex i.e. `a?+{2,3}`.
550
-
551
- case '{':
552
- var rs = /^(\d+)(,(\d+)?)?\}/.exec(str.slice(i)),
553
- min,
554
- max;
555
-
556
- if (rs !== null) {
557
- if (last.length === 0) {
558
- repeatErr(i);
559
- }
560
-
561
- min = parseInt(rs[1], 10);
562
- max = rs[2] ? rs[3] ? parseInt(rs[3], 10) : Infinity : min;
563
- i += rs[0].length;
564
- last.push({
565
- type: types$2.REPETITION,
566
- min,
567
- max,
568
- value: last.pop()
569
- });
570
- } else {
571
- last.push({
572
- type: types$2.CHAR,
573
- value: 123
574
- });
575
- }
576
-
577
- break;
578
-
579
- case '?':
580
- if (last.length === 0) {
581
- repeatErr(i);
582
- }
583
-
584
- last.push({
585
- type: types$2.REPETITION,
586
- min: 0,
587
- max: 1,
588
- value: last.pop()
589
- });
590
- break;
591
-
592
- case '+':
593
- if (last.length === 0) {
594
- repeatErr(i);
595
- }
596
-
597
- last.push({
598
- type: types$2.REPETITION,
599
- min: 1,
600
- max: Infinity,
601
- value: last.pop()
602
- });
603
- break;
604
-
605
- case '*':
606
- if (last.length === 0) {
607
- repeatErr(i);
608
- }
609
-
610
- last.push({
611
- type: types$2.REPETITION,
612
- min: 0,
613
- max: Infinity,
614
- value: last.pop()
615
- });
616
- break;
617
- // Default is a character that is not `\[](){}?+*^$`.
618
-
619
- default:
620
- last.push({
621
- type: types$2.CHAR,
622
- value: c.charCodeAt(0)
623
- });
624
- }
625
- } // Check if any groups have not been closed.
626
-
627
-
628
- if (groupStack.length !== 0) {
629
- util.error(regexpStr, 'Unterminated group');
630
- }
631
-
632
- return start;
633
- };
634
-
635
- var types_1 = types$2;
636
- lib.types = types_1;
637
-
638
- var types$1 = lib.types;
639
-
640
- var safeRegex2 = function (re, opts) {
641
- if (!opts) opts = {};
642
- var replimit = opts.limit === undefined ? 25 : opts.limit;
643
- if (isRegExp(re)) re = re.source;else if (typeof re !== 'string') re = String(re);
644
-
645
- try {
646
- re = lib(re);
647
- } catch (err) {
648
- return false;
649
- }
650
-
651
- var reps = 0;
652
- return function walk(node, starHeight) {
653
- var i;
654
- var ok;
655
- var len;
656
-
657
- if (node.type === types$1.REPETITION) {
658
- starHeight++;
659
- reps++;
660
- if (starHeight > 1) return false;
661
- if (reps > replimit) return false;
662
- }
663
-
664
- if (node.options) {
665
- for (i = 0, len = node.options.length; i < len; i++) {
666
- ok = walk({
667
- stack: node.options[i]
668
- }, starHeight);
669
- if (!ok) return false;
670
- }
671
- }
672
-
673
- var stack = node.stack || node.value && node.value.stack;
674
- if (!stack) return true;
675
-
676
- for (i = 0; i < stack.length; i++) {
677
- ok = walk(stack[i], starHeight);
678
- if (!ok) return false;
679
- }
680
-
681
- return true;
682
- }(re, 0);
683
- };
684
-
685
- function isRegExp(x) {
686
- return {}.toString.call(x) === '[object RegExp]';
687
- }
688
-
689
- const indent = ' ';
690
- const branchIndent = '│ ';
691
- const midBranchIndent = '├── ';
692
- const endBranchIndent = '└── ';
693
- const wildcardDelimiter = '*';
694
- const pathDelimiter = '/';
695
- const pathRegExp = /(?=\/)/;
696
- /* eslint-enable */
697
-
698
- function prettyPrintRoutesArray$1(routeArray) {
699
- const mergedRouteArray = [];
700
- let tree = '';
701
- routeArray.sort((a, b) => {
702
- if (!a.path || !b.path) return 0;
703
- return a.path.localeCompare(b.path);
704
- }); // merge alike paths
705
-
706
- for (let i = 0; i < routeArray.length; i++) {
707
- const route = routeArray[i];
708
- const pathExists = mergedRouteArray.find(r => route.path === r.path);
709
-
710
- if (pathExists) {
711
- // path already declared, add new method and break out of loop
712
- pathExists.handlers.push({
713
- method: route.method,
714
- opts: route.opts.constraints || undefined
715
- });
716
- continue;
717
- }
718
-
719
- const routeHandler = {
720
- method: route.method,
721
- opts: route.opts.constraints || undefined
722
- };
723
- mergedRouteArray.push({
724
- path: route.path,
725
- methods: [route.method],
726
- opts: [route.opts],
727
- handlers: [routeHandler],
728
- parents: [],
729
- branchLevel: 1
730
- });
731
- } // insert root level path if none defined
732
-
733
-
734
- if (!mergedRouteArray.filter(r => r.path === pathDelimiter).length) {
735
- const rootPath = {
736
- path: pathDelimiter,
737
- truncatedPath: '',
738
- methods: [],
739
- opts: [],
740
- handlers: [{}],
741
- parents: [pathDelimiter]
742
- }; // if wildcard route exists, insert root level after wildcard
743
-
744
- if (mergedRouteArray.filter(r => r.path === wildcardDelimiter).length) {
745
- mergedRouteArray.splice(1, 0, rootPath);
746
- } else {
747
- mergedRouteArray.unshift(rootPath);
748
- }
749
- } // build tree
750
-
751
-
752
- const routeTree = buildRouteTree(mergedRouteArray); // draw tree
753
-
754
- routeTree.forEach((rootBranch, idx) => {
755
- tree += drawBranch(rootBranch, null, idx === routeTree.length - 1, false, true);
756
- tree += '\n'; // newline characters inserted at beginning of drawing function to allow for nested paths
757
- });
758
- return tree;
759
- }
760
-
761
- function buildRouteTree(mergedRouteArray, rootPath) {
762
- const result = [];
763
- const temp = {
764
- result
765
- };
766
- mergedRouteArray.forEach((route, idx) => {
767
- let splitPath = route.path.split(pathRegExp); // add preceding slash for proper nesting
768
-
769
- if (splitPath[0] !== pathDelimiter) {
770
- // handle wildcard route
771
- if (splitPath[0] !== wildcardDelimiter) splitPath = [pathDelimiter, splitPath[0].slice(1), ...splitPath.slice(1)];
772
- } // build tree
773
-
774
-
775
- splitPath.reduce((acc, path, pidx) => {
776
- if (!acc[path]) {
777
- acc[path] = {
778
- result: []
779
- };
780
- const pathSeg = {
781
- path,
782
- children: acc[path].result
783
- };
784
- if (pidx === splitPath.length - 1) pathSeg.handlers = route.handlers;
785
- acc.result.push(pathSeg);
786
- }
787
-
788
- return acc[path];
789
- }, temp);
790
- }); // unfold root object from array
791
-
792
- return result;
793
- }
794
-
795
- function drawBranch(pathSeg, prefix, endBranch, noPrefix, rootBranch) {
796
- let branch = '';
797
- if (!noPrefix && !rootBranch) branch += '\n';
798
- if (!noPrefix) branch += `${prefix || ''}${endBranch ? endBranchIndent : midBranchIndent}`;
799
- branch += `${pathSeg.path}`;
800
-
801
- if (pathSeg.handlers) {
802
- const flatHandlers = pathSeg.handlers.reduce((acc, curr) => {
803
- const match = acc.findIndex(h => JSON.stringify(h.opts) === JSON.stringify(curr.opts));
804
-
805
- if (match !== -1) {
806
- acc[match].method = [acc[match].method, curr.method].join(', ');
807
- } else {
808
- acc.push(curr);
809
- }
810
-
811
- return acc;
812
- }, []);
813
- flatHandlers.forEach((handler, idx) => {
814
- if (idx > 0) branch += `${noPrefix ? '' : prefix}${endBranch ? indent : branchIndent}${pathSeg.path}`;
815
- branch += ` (${handler.method || '-'})`;
816
- if (handler.opts && JSON.stringify(handler.opts) !== '{}') branch += ` ${JSON.stringify(handler.opts)}`;
817
- if (flatHandlers.length > 1 && idx !== flatHandlers.length - 1) branch += '\n';
818
- });
819
- }
820
-
821
- if (!noPrefix) prefix = `${prefix || ''}${endBranch ? indent : branchIndent}`;
822
- pathSeg.children.forEach((child, idx) => {
823
- const endBranch = idx === pathSeg.children.length - 1;
824
- const skipPrefix = !pathSeg.handlers && pathSeg.children.length === 1;
825
- branch += drawBranch(child, prefix, endBranch, skipPrefix);
826
- });
827
- return branch;
828
- }
829
-
830
- function prettyPrintFlattenedNode$1(flattenedNode, prefix, tail) {
831
- let paramName = '';
832
- const printHandlers = [];
833
-
834
- for (const node of flattenedNode.nodes) {
835
- for (const handler of node.handlers) {
836
- printHandlers.push(index$1._extends({
837
- method: node.method
838
- }, handler));
839
- }
840
- }
841
-
842
- if (printHandlers.length) {
843
- printHandlers.forEach((handler, index) => {
844
- let suffix = `(${handler.method || '-'})`;
845
-
846
- if (Object.keys(handler.constraints).length > 0) {
847
- suffix += ' ' + JSON.stringify(handler.constraints);
848
- }
849
-
850
- let name = ''; // find locations of parameters in prefix
851
-
852
- const paramIndices = flattenedNode.prefix.split('').map((ch, idx) => ch === ':' ? idx : null).filter(idx => idx !== null);
853
-
854
- if (paramIndices.length) {
855
- let prevLoc = 0;
856
- paramIndices.forEach((loc, idx) => {
857
- // find parameter in prefix
858
- name += flattenedNode.prefix.slice(prevLoc, loc + 1); // insert parameters
859
-
860
- name += handler.params[handler.params.length - paramIndices.length + idx];
861
- if (idx === paramIndices.length - 1) name += flattenedNode.prefix.slice(loc + 1);
862
- prevLoc = loc + 1;
863
- });
864
- } else {
865
- // there are no parameters, return full object
866
- name = flattenedNode.prefix;
867
- }
868
-
869
- if (index === 0) {
870
- paramName += `${name} ${suffix}`;
871
- return;
872
- } else {
873
- paramName += '\n';
874
- }
875
-
876
- paramName += `${prefix}${tail ? indent : branchIndent}${name} ${suffix}`;
877
- });
878
- } else {
879
- paramName = flattenedNode.prefix;
880
- }
881
-
882
- let tree = `${prefix}${tail ? endBranchIndent : midBranchIndent}${paramName}\n`;
883
- prefix = `${prefix}${tail ? indent : branchIndent}`;
884
- const labels = Object.keys(flattenedNode.children);
885
-
886
- for (let i = 0; i < labels.length; i++) {
887
- const child = flattenedNode.children[labels[i]];
888
- tree += prettyPrintFlattenedNode$1(child, prefix, i === labels.length - 1);
889
- }
890
-
891
- return tree;
892
- }
893
-
894
- function flattenNode$1(flattened, node) {
895
- if (node.handlers.length > 0) {
896
- flattened.nodes.push(node);
897
- }
898
-
899
- if (node.children) {
900
- for (const child of Object.values(node.children)) {
901
- // split on the slash separator but use a regex to lookahead and not actually match it, preserving it in the returned string segments
902
- const childPrefixSegments = child.prefix.split(pathRegExp);
903
- let cursor = flattened;
904
- let parent;
905
-
906
- for (const segment of childPrefixSegments) {
907
- parent = cursor;
908
- cursor = cursor.children[segment];
909
-
910
- if (!cursor) {
911
- cursor = {
912
- prefix: segment,
913
- nodes: [],
914
- children: {}
915
- };
916
- parent.children[segment] = cursor;
917
- }
918
- }
919
-
920
- flattenNode$1(cursor, child);
921
- }
922
- }
923
- }
924
-
925
- function compressFlattenedNode$1(flattenedNode) {
926
- const childKeys = Object.keys(flattenedNode.children);
927
-
928
- if (flattenedNode.nodes.length === 0 && childKeys.length === 1) {
929
- const child = flattenedNode.children[childKeys[0]];
930
-
931
- if (child.nodes.length <= 1) {
932
- compressFlattenedNode$1(child);
933
- flattenedNode.nodes = child.nodes;
934
- flattenedNode.prefix += child.prefix;
935
- flattenedNode.children = child.children;
936
- return flattenedNode;
937
- }
938
- }
939
-
940
- for (const key of Object.keys(flattenedNode.children)) {
941
- compressFlattenedNode$1(flattenedNode.children[key]);
942
- }
943
-
944
- return flattenedNode;
945
- }
946
-
947
- var prettyPrint = {
948
- flattenNode: flattenNode$1,
949
- compressFlattenedNode: compressFlattenedNode$1,
950
- prettyPrintFlattenedNode: prettyPrintFlattenedNode$1,
951
- prettyPrintRoutesArray: prettyPrintRoutesArray$1
952
- };
953
-
954
- var fastDeepEqual = function equal(a, b) {
955
- if (a === b) return true;
956
-
957
- if (a && b && typeof a == 'object' && typeof b == 'object') {
958
- if (a.constructor !== b.constructor) return false;
959
- var length, i, keys;
960
-
961
- if (Array.isArray(a)) {
962
- length = a.length;
963
- if (length != b.length) return false;
964
-
965
- for (i = length; i-- !== 0;) if (!equal(a[i], b[i])) return false;
966
-
967
- return true;
968
- }
969
-
970
- if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
971
- if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
972
- if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
973
- keys = Object.keys(a);
974
- length = keys.length;
975
- if (length !== Object.keys(b).length) return false;
976
-
977
- for (i = length; i-- !== 0;) if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
978
-
979
- for (i = length; i-- !== 0;) {
980
- var key = keys[i];
981
- if (!equal(a[key], b[key])) return false;
982
- }
983
-
984
- return true;
985
- } // true if both NaN, false otherwise
986
-
987
-
988
- return a !== a && b !== b;
989
- };
990
-
991
- const types = {
992
- STATIC: 0,
993
- PARAM: 1,
994
- MATCH_ALL: 2,
995
- REGEX: 3,
996
- // It's used for a parameter, that is followed by another parameter in the same part
997
- MULTI_PARAM: 4
998
- };
999
-
1000
- function Node$1(options) {
1001
- options = options || {};
1002
- this.prefix = options.prefix || '/';
1003
- this.label = this.prefix[0];
1004
- this.method = options.method; // not used for logic, just for debugging and pretty printing
1005
-
1006
- this.handlers = options.handlers || []; // unoptimized list of handler objects for which the fast matcher function will be compiled
1007
-
1008
- this.unconstrainedHandler = options.unconstrainedHandler || null; // optimized reference to the handler that will match most of the time
1009
-
1010
- this.children = options.children || {};
1011
- this.numberOfChildren = Object.keys(this.children).length;
1012
- this.kind = options.kind || this.types.STATIC;
1013
- this.regex = options.regex || null;
1014
- this.wildcardChild = null;
1015
- this.parametricBrother = null;
1016
- this.constrainer = options.constrainer;
1017
- this.hasConstraints = options.hasConstraints;
1018
- this.constrainedHandlerStores = null;
1019
- }
1020
-
1021
- Object.defineProperty(Node$1.prototype, 'types', {
1022
- value: types
1023
- });
1024
-
1025
- Node$1.prototype.getLabel = function () {
1026
- return this.prefix[0];
1027
- };
1028
-
1029
- Node$1.prototype.addChild = function (node) {
1030
- var label = '';
1031
-
1032
- switch (node.kind) {
1033
- case this.types.STATIC:
1034
- label = node.getLabel();
1035
- break;
1036
-
1037
- case this.types.PARAM:
1038
- case this.types.REGEX:
1039
- case this.types.MULTI_PARAM:
1040
- label = ':';
1041
- break;
1042
-
1043
- case this.types.MATCH_ALL:
1044
- this.wildcardChild = node;
1045
- label = '*';
1046
- break;
1047
-
1048
- default:
1049
- throw new Error(`Unknown node kind: ${node.kind}`);
1050
- }
1051
-
1052
- assert__default['default'](this.children[label] === undefined, `There is already a child with label '${label}'`);
1053
- this.children[label] = node;
1054
- this.numberOfChildren = Object.keys(this.children).length;
1055
- const labels = Object.keys(this.children);
1056
- var parametricBrother = this.parametricBrother;
1057
-
1058
- for (var i = 0; i < labels.length; i++) {
1059
- const child = this.children[labels[i]];
1060
-
1061
- if (child.label === ':') {
1062
- parametricBrother = child;
1063
- break;
1064
- }
1065
- } // Save the parametric brother inside static children
1066
-
1067
-
1068
- const iterate = node => {
1069
- if (!node) {
1070
- return;
1071
- }
1072
-
1073
- if (node.kind !== this.types.STATIC) {
1074
- return;
1075
- }
1076
-
1077
- if (node !== this) {
1078
- node.parametricBrother = parametricBrother || node.parametricBrother;
1079
- }
1080
-
1081
- const labels = Object.keys(node.children);
1082
-
1083
- for (var i = 0; i < labels.length; i++) {
1084
- iterate(node.children[labels[i]]);
1085
- }
1086
- };
1087
-
1088
- iterate(this);
1089
- return this;
1090
- };
1091
-
1092
- Node$1.prototype.reset = function (prefix) {
1093
- this.prefix = prefix;
1094
- this.children = {};
1095
- this.handlers = [];
1096
- this.unconstrainedHandler = null;
1097
- this.kind = this.types.STATIC;
1098
- this.numberOfChildren = 0;
1099
- this.regex = null;
1100
- this.wildcardChild = null;
1101
- this.hasConstraints = false;
1102
-
1103
- this._decompileGetHandlerMatchingConstraints();
1104
-
1105
- return this;
1106
- };
1107
-
1108
- Node$1.prototype.split = function (length) {
1109
- const newChild = new Node$1({
1110
- prefix: this.prefix.slice(length),
1111
- children: this.children,
1112
- kind: this.kind,
1113
- method: this.method,
1114
- handlers: this.handlers.slice(0),
1115
- regex: this.regex,
1116
- constrainer: this.constrainer,
1117
- hasConstraints: this.hasConstraints,
1118
- unconstrainedHandler: this.unconstrainedHandler
1119
- });
1120
-
1121
- if (this.wildcardChild !== null) {
1122
- newChild.wildcardChild = this.wildcardChild;
1123
- }
1124
-
1125
- this.reset(this.prefix.slice(0, length));
1126
- this.addChild(newChild);
1127
- return newChild;
1128
- };
1129
-
1130
- Node$1.prototype.findByLabel = function (path) {
1131
- return this.children[path[0]];
1132
- };
1133
-
1134
- Node$1.prototype.findMatchingChild = function (derivedConstraints, path) {
1135
- var child = this.children[path[0]];
1136
-
1137
- if (child !== undefined && (child.numberOfChildren > 0 || child.getMatchingHandler(derivedConstraints) !== null)) {
1138
- if (path.slice(0, child.prefix.length) === child.prefix) {
1139
- return child;
1140
- }
1141
- }
1142
-
1143
- child = this.children[':'];
1144
-
1145
- if (child !== undefined && (child.numberOfChildren > 0 || child.getMatchingHandler(derivedConstraints) !== null)) {
1146
- return child;
1147
- }
1148
-
1149
- child = this.children['*'];
1150
-
1151
- if (child !== undefined && (child.numberOfChildren > 0 || child.getMatchingHandler(derivedConstraints) !== null)) {
1152
- return child;
1153
- }
1154
-
1155
- return null;
1156
- };
1157
-
1158
- Node$1.prototype.addHandler = function (handler, params, store, constraints) {
1159
- if (!handler) return;
1160
- assert__default['default'](!this.getHandler(constraints), `There is already a handler with constraints '${JSON.stringify(constraints)}' and method '${this.method}'`);
1161
- const handlerObject = {
1162
- handler: handler,
1163
- params: params,
1164
- constraints: constraints,
1165
- store: store || null,
1166
- paramsLength: params.length
1167
- };
1168
- this.handlers.push(handlerObject); // Sort the most constrained handlers to the front of the list of handlers so they are tested first.
1169
-
1170
- this.handlers.sort((a, b) => Object.keys(a.constraints).length - Object.keys(b.constraints).length);
1171
-
1172
- if (Object.keys(constraints).length > 0) {
1173
- this.hasConstraints = true;
1174
- } else {
1175
- this.unconstrainedHandler = handlerObject;
1176
- }
1177
-
1178
- if (this.hasConstraints && this.handlers.length > 32) {
1179
- throw new Error('find-my-way supports a maximum of 32 route handlers per node when there are constraints, limit reached');
1180
- } // Note that the fancy constraint handler matcher needs to be recompiled now that the list of handlers has changed
1181
- // This lazy compilation means we don't do the compile until the first time the route match is tried, which doesn't waste time re-compiling every time a new handler is added
1182
-
1183
-
1184
- this._decompileGetHandlerMatchingConstraints();
1185
- };
1186
-
1187
- Node$1.prototype.getHandler = function (constraints) {
1188
- return this.handlers.filter(handler => fastDeepEqual(constraints, handler.constraints))[0];
1189
- }; // We compile the handler matcher the first time this node is matched. We need to recompile it if new handlers are added, so when a new handler is added, we reset the handler matching function to this base one that will recompile it.
1190
-
1191
-
1192
- function compileThenGetHandlerMatchingConstraints(derivedConstraints) {
1193
- this._compileGetHandlerMatchingConstraints();
1194
-
1195
- return this._getHandlerMatchingConstraints(derivedConstraints);
1196
- } // This is the hot path for node handler finding -- change with care!
1197
-
1198
-
1199
- Node$1.prototype.getMatchingHandler = function (derivedConstraints) {
1200
- if (this.hasConstraints) {
1201
- // This node is constrained, use the performant precompiled constraint matcher
1202
- return this._getHandlerMatchingConstraints(derivedConstraints);
1203
- } else {
1204
- // This node doesn't have any handlers that are constrained, so it's handlers probably match. Some requests have constraint values that *must* match however, like version, so check for those before returning it.
1205
- if (derivedConstraints && derivedConstraints.__hasMustMatchValues) {
1206
- return null;
1207
- } else {
1208
- return this.unconstrainedHandler;
1209
- }
1210
- }
1211
- }; // Slot for the compiled constraint matching function
1212
-
1213
-
1214
- Node$1.prototype._getHandlerMatchingConstraints = compileThenGetHandlerMatchingConstraints;
1215
-
1216
- Node$1.prototype._decompileGetHandlerMatchingConstraints = function () {
1217
- this._getHandlerMatchingConstraints = compileThenGetHandlerMatchingConstraints;
1218
- return null;
1219
- }; // Builds a store object that maps from constraint values to a bitmap of handler indexes which pass the constraint for a value
1220
- // So for a host constraint, this might look like { "fastify.io": 0b0010, "google.ca": 0b0101 }, meaning the 3rd handler is constrainted to fastify.io, and the 2nd and 4th handlers are constrained to google.ca.
1221
- // The store's implementation comes from the strategies provided to the Router.
1222
-
1223
-
1224
- Node$1.prototype._buildConstraintStore = function (constraint) {
1225
- const store = this.constrainer.newStoreForConstraint(constraint);
1226
-
1227
- for (let i = 0; i < this.handlers.length; i++) {
1228
- const handler = this.handlers[i];
1229
- const mustMatchValue = handler.constraints[constraint];
1230
-
1231
- if (typeof mustMatchValue !== 'undefined') {
1232
- let indexes = store.get(mustMatchValue);
1233
-
1234
- if (!indexes) {
1235
- indexes = 0;
1236
- }
1237
-
1238
- indexes |= 1 << i; // set the i-th bit for the mask because this handler is constrained by this value https://stackoverflow.com/questions/1436438/how-do-you-set-clear-and-toggle-a-single-bit-in-javascrip
1239
-
1240
- store.set(mustMatchValue, indexes);
1241
- }
1242
- }
1243
-
1244
- return store;
1245
- }; // Builds a bitmask for a given constraint that has a bit for each handler index that is 0 when that handler *is* constrained and 1 when the handler *isnt* constrainted. This is opposite to what might be obvious, but is just for convienience when doing the bitwise operations.
1246
-
1247
-
1248
- Node$1.prototype._constrainedIndexBitmask = function (constraint) {
1249
- let mask = 0b0;
1250
-
1251
- for (let i = 0; i < this.handlers.length; i++) {
1252
- const handler = this.handlers[i];
1253
-
1254
- if (handler.constraints && constraint in handler.constraints) {
1255
- mask |= 1 << i;
1256
- }
1257
- }
1258
-
1259
- return ~mask;
1260
- }; // Compile a fast function to match the handlers for this node
1261
- // The function implements a general case multi-constraint matching algorithm.
1262
- // The general idea is this: we have a bunch of handlers, each with a potentially different set of constraints, and sometimes none at all. We're given a list of constraint values and we have to use the constraint-value-comparison strategies to see which handlers match the constraint values passed in.
1263
- // We do this by asking each constraint store which handler indexes match the given constraint value for each store. Trickily, the handlers that a store says match are the handlers constrained by that store, but handlers that aren't constrained at all by that store could still match just fine. So, each constraint store can only describe matches for it, and it won't have any bearing on the handlers it doesn't care about. For this reason, we have to ask each stores which handlers match and track which have been matched (or not cared about) by all of them.
1264
- // We use bitmaps to represent these lists of matches so we can use bitwise operations to implement this efficiently. Bitmaps are cheap to allocate, let us implement this masking behaviour in one CPU instruction, and are quite compact in memory. We start with a bitmap set to all 1s representing every handler that is a match candidate, and then for each constraint, see which handlers match using the store, and then mask the result by the mask of handlers that that store applies to, and bitwise AND with the candidate list. Phew.
1265
- // We consider all this compiling function complexity to be worth it, because the naive implementation that just loops over the handlers asking which stores match is quite a bit slower.
1266
-
1267
-
1268
- Node$1.prototype._compileGetHandlerMatchingConstraints = function () {
1269
- this.constrainedHandlerStores = {};
1270
- let constraints = new Set();
1271
-
1272
- for (const handler of this.handlers) {
1273
- for (const key of Object.keys(handler.constraints)) {
1274
- constraints.add(key);
1275
- }
1276
- }
1277
-
1278
- constraints = Array.from(constraints);
1279
- const lines = []; // always check the version constraint first as it is the most selective
1280
-
1281
- constraints.sort((a, b) => a === 'version' ? 1 : 0);
1282
-
1283
- for (const constraint of constraints) {
1284
- this.constrainedHandlerStores[constraint] = this._buildConstraintStore(constraint);
1285
- }
1286
-
1287
- lines.push(`
1288
- let candidates = 0b${'1'.repeat(this.handlers.length)}
1289
- let mask, matches
1290
- `);
1291
-
1292
- for (const constraint of constraints) {
1293
- // Setup the mask for indexes this constraint applies to. The mask bits are set to 1 for each position if the constraint applies.
1294
- lines.push(`
1295
- mask = ${this._constrainedIndexBitmask(constraint)}
1296
- value = derivedConstraints.${constraint}
1297
- `); // If there's no constraint value, none of the handlers constrained by this constraint can match. Remove them from the candidates.
1298
- // If there is a constraint value, get the matching indexes bitmap from the store, and mask it down to only the indexes this constraint applies to, and then bitwise and with the candidates list to leave only matching candidates left.
1299
-
1300
- lines.push(`
1301
- if (typeof value === "undefined") {
1302
- candidates &= mask
1303
- } else {
1304
- matches = this.constrainedHandlerStores.${constraint}.get(value) || 0
1305
- candidates &= (matches | mask)
1306
- }
1307
- if (candidates === 0) return null;
1308
- `);
1309
- } // Return the first handler who's bit is set in the candidates https://stackoverflow.com/questions/18134985/how-to-find-index-of-first-set-bit
1310
-
1311
-
1312
- lines.push(`
1313
- return this.handlers[Math.floor(Math.log2(candidates))]
1314
- `);
1315
- this._getHandlerMatchingConstraints = new Function('derivedConstraints', lines.join('\n')); // eslint-disable-line
1316
- };
1317
-
1318
- var node = Node$1;
1319
-
1320
- function SemVerStore() {
1321
- if (!(this instanceof SemVerStore)) {
1322
- return new SemVerStore();
1323
- }
1324
-
1325
- this.tree = new Node();
1326
- }
1327
-
1328
- SemVerStore.prototype.set = function (version, store) {
1329
- if (typeof version !== 'string') {
1330
- throw new TypeError('Version should be a string');
1331
- }
1332
-
1333
- var currentNode = this.tree;
1334
- version = version.split('.');
1335
-
1336
- while (version.length) {
1337
- currentNode = currentNode.addChild(new Node(version.shift()));
1338
- }
1339
-
1340
- currentNode.setStore(store);
1341
- return this;
1342
- };
1343
-
1344
- SemVerStore.prototype.get = function (version) {
1345
- if (typeof version !== 'string') return null;
1346
- if (version === '*') version = 'x.x.x';
1347
- var node = this.tree;
1348
- var firstDot = version.indexOf('.');
1349
- var secondDot = version.indexOf('.', firstDot + 1);
1350
- var major = version.slice(0, firstDot);
1351
- var minor = secondDot === -1 ? version.slice(firstDot + 1) : version.slice(firstDot + 1, secondDot);
1352
- var patch = secondDot === -1 ? 'x' : version.slice(secondDot + 1);
1353
- node = node.getChild(major);
1354
- if (node === null) return null;
1355
- node = node.getChild(minor);
1356
- if (node === null) return null;
1357
- node = node.getChild(patch);
1358
- if (node === null) return null;
1359
- return node.store;
1360
- };
1361
-
1362
- SemVerStore.prototype.del = function (version) {
1363
- if (typeof version !== 'string') {
1364
- throw new TypeError('Version should be a string');
1365
- }
1366
-
1367
- var firstDot = version.indexOf('.');
1368
- var secondDot = version.indexOf('.', firstDot + 1);
1369
- var major = version.slice(0, firstDot);
1370
- var minor = secondDot === -1 ? version.slice(firstDot + 1) : version.slice(firstDot + 1, secondDot);
1371
- var patch = secondDot === -1 ? 'x' : version.slice(secondDot + 1); // check existence of major node
1372
-
1373
- var majorNode = this.tree.children[major];
1374
- if (majorNode == null) return this; // if minor is the wildcard, then remove the full major node
1375
-
1376
- if (minor === 'x') {
1377
- this.tree.removeChild(major);
1378
- return this;
1379
- } // check existence of minor node
1380
-
1381
-
1382
- var minorNode = majorNode.children[minor];
1383
- if (minorNode == null) return this; // if patch is the wildcard, then remove the full minor node
1384
- // and also the major if there are no more children
1385
-
1386
- if (patch === 'x') {
1387
- this.tree.children[major].removeChild(minor);
1388
-
1389
- if (this.tree.children[major].length === 0) {
1390
- this.tree.removeChild(major);
1391
- }
1392
-
1393
- return this;
1394
- } // check existence of patch node
1395
-
1396
-
1397
- var patchNode = minorNode.children[patch];
1398
- if (patchNode == null) return this; // Specific delete
1399
-
1400
- this.tree.children[major].children[minor].removeChild(patch); // check if the minor node has no more children, if so removes it
1401
- // same for the major node
1402
-
1403
- if (this.tree.children[major].children[minor].length === 0) {
1404
- this.tree.children[major].removeChild(minor);
1405
-
1406
- if (this.tree.children[major].length === 0) {
1407
- this.tree.removeChild(major);
1408
- }
1409
- }
1410
-
1411
- return this;
1412
- };
1413
-
1414
- SemVerStore.prototype.empty = function () {
1415
- this.tree = new Node();
1416
- return this;
1417
- };
1418
-
1419
- function getMax(arr) {
1420
- var l = arr.length;
1421
- var max = arr[0];
1422
-
1423
- for (var i = 1; i < l; i++) {
1424
- if (arr[i] > max) {
1425
- max = arr[i];
1426
- }
1427
- }
1428
-
1429
- return max;
1430
- }
1431
-
1432
- function Node(prefix, children, store) {
1433
- this.prefix = Number(prefix) || 0;
1434
- this.children = children || null;
1435
- this.childrenPrefixes = children ? Object.keys(children) : [];
1436
- this.store = store || null;
1437
- }
1438
-
1439
- Node.prototype.getChild = function (prefix) {
1440
- if (this.children === null) return null;
1441
-
1442
- if (prefix === 'x') {
1443
- var max = getMax(this.childrenPrefixes);
1444
- return this.children[max];
1445
- }
1446
-
1447
- return this.children[prefix] || null;
1448
- };
1449
-
1450
- Node.prototype.addChild = function (node) {
1451
- this.children = this.children || {};
1452
- var child = this.getChild(node.prefix);
1453
-
1454
- if (child === null) {
1455
- this.children[node.prefix] = node;
1456
- this.childrenPrefixes.push(node.prefix);
1457
- }
1458
-
1459
- return child || node;
1460
- };
1461
-
1462
- Node.prototype.removeChild = function (prefix) {
1463
- if (prefix === 'x') {
1464
- this.children = null;
1465
- this.childrenPrefixes = [];
1466
- return this;
1467
- }
1468
-
1469
- if (this.children[prefix] !== undefined) {
1470
- prefix = Number(prefix);
1471
- delete this.children[prefix];
1472
- this.childrenPrefixes.splice(this.childrenPrefixes.indexOf(prefix), 1);
1473
- }
1474
-
1475
- return this;
1476
- };
1477
-
1478
- Node.prototype.setStore = function (store) {
1479
- this.store = store;
1480
- return this;
1481
- };
1482
-
1483
- Object.defineProperty(Node.prototype, 'length', {
1484
- get: function () {
1485
- return this.childrenPrefixes.length;
1486
- }
1487
- });
1488
- var semverStore = SemVerStore;
1489
-
1490
- var acceptVersion = {
1491
- name: 'version',
1492
- mustMatchWhenDerived: true,
1493
- storage: semverStore,
1494
-
1495
- validate(value) {
1496
- assert__default['default'](typeof value === 'string', 'Version should be a string');
1497
- }
1498
-
1499
- };
1500
-
1501
- function HostStorage() {
1502
- var hosts = {};
1503
- var regexHosts = [];
1504
- return {
1505
- get: host => {
1506
- var exact = hosts[host];
1507
-
1508
- if (exact) {
1509
- return exact;
1510
- }
1511
-
1512
- var item;
1513
-
1514
- for (var i = 0; i < regexHosts.length; i++) {
1515
- item = regexHosts[i];
1516
-
1517
- if (item.host.test(host)) {
1518
- return item.value;
1519
- }
1520
- }
1521
- },
1522
- set: (host, value) => {
1523
- if (host instanceof RegExp) {
1524
- regexHosts.push({
1525
- host,
1526
- value
1527
- });
1528
- } else {
1529
- hosts[host] = value;
1530
- }
1531
- },
1532
- del: host => {
1533
- delete hosts[host];
1534
- regexHosts = regexHosts.filter(obj => String(obj.host) !== String(host));
1535
- },
1536
- empty: () => {
1537
- hosts = {};
1538
- regexHosts = [];
1539
- }
1540
- };
1541
- }
1542
-
1543
- var acceptHost = {
1544
- name: 'host',
1545
- mustMatchWhenDerived: false,
1546
- storage: HostStorage,
1547
-
1548
- validate(value) {
1549
- assert__default['default'](typeof value === 'string' || Object.prototype.toString.call(value) === '[object RegExp]', 'Host should be a string or a RegExp');
1550
- }
1551
-
1552
- };
1553
-
1554
- class Constrainer {
1555
- constructor(customStrategies) {
1556
- this.strategies = {
1557
- version: acceptVersion,
1558
- host: acceptHost
1559
- };
1560
- this.strategiesInUse = new Set(); // validate and optimize prototypes of given custom strategies
1561
-
1562
- if (customStrategies) {
1563
- var kCustomStrategies = Object.keys(customStrategies);
1564
- var strategy;
1565
-
1566
- for (var i = 0; i < kCustomStrategies.length; i++) {
1567
- strategy = customStrategies[kCustomStrategies[i]];
1568
- assert__default['default'](typeof strategy.name === 'string' && strategy.name !== '', 'strategy.name is required.');
1569
- assert__default['default'](strategy.storage && typeof strategy.storage === 'function', 'strategy.storage function is required.');
1570
- assert__default['default'](strategy.deriveConstraint && typeof strategy.deriveConstraint === 'function', 'strategy.deriveConstraint function is required.');
1571
- strategy.isCustom = true;
1572
- this.strategies[strategy.name] = strategy;
1573
- }
1574
- }
1575
- }
1576
-
1577
- deriveConstraints(req, ctx) {
1578
- return undefined;
1579
- } // When new constraints start getting used, we need to rebuild the deriver to derive them. Do so if we see novel constraints used.
1580
-
1581
-
1582
- noteUsage(constraints) {
1583
- if (constraints) {
1584
- const beforeSize = this.strategiesInUse.size;
1585
-
1586
- for (const key in constraints) {
1587
- this.strategiesInUse.add(key);
1588
- }
1589
-
1590
- if (beforeSize !== this.strategiesInUse.size) {
1591
- this._buildDeriveConstraints();
1592
- }
1593
- }
1594
- }
1595
-
1596
- newStoreForConstraint(constraint) {
1597
- if (!this.strategies[constraint]) {
1598
- throw new Error(`No strategy registered for constraint key ${constraint}`);
1599
- }
1600
-
1601
- return this.strategies[constraint].storage();
1602
- }
1603
-
1604
- validateConstraints(constraints) {
1605
- for (const key in constraints) {
1606
- const value = constraints[key];
1607
-
1608
- if (typeof value === 'undefined') {
1609
- throw new Error('Can\'t pass an undefined constraint value, must pass null or no key at all');
1610
- }
1611
-
1612
- const strategy = this.strategies[key];
1613
-
1614
- if (!strategy) {
1615
- throw new Error(`No strategy registered for constraint key ${key}`);
1616
- }
1617
-
1618
- if (strategy.validate) {
1619
- strategy.validate(value);
1620
- }
1621
- }
1622
- } // Optimization: build a fast function for deriving the constraints for all the strategies at once. We inline the definitions of the version constraint and the host constraint for performance.
1623
- // If no constraining strategies are in use (no routes constrain on host, or version, or any custom strategies) then we don't need to derive constraints for each route match, so don't do anything special, and just return undefined
1624
- // This allows us to not allocate an object to hold constraint values if no constraints are defined.
1625
-
1626
-
1627
- _buildDeriveConstraints() {
1628
- if (this.strategiesInUse.size === 0) return;
1629
- const lines = [`
1630
- const derivedConstraints = {
1631
- __hasMustMatchValues: false,
1632
- `];
1633
- const mustMatchKeys = [];
1634
-
1635
- for (const key of this.strategiesInUse) {
1636
- const strategy = this.strategies[key]; // Optimization: inline the derivation for the common built in constraints
1637
-
1638
- if (!strategy.isCustom) {
1639
- if (key === 'version') {
1640
- lines.push(' version: req.headers[\'accept-version\'],');
1641
- } else if (key === 'host') {
1642
- lines.push(' host: req.headers.host,');
1643
- } else {
1644
- throw new Error('unknown non-custom strategy for compiling constraint derivation function');
1645
- }
1646
- } else {
1647
- lines.push(` ${strategy.name}: this.strategies.${key}.deriveConstraint(req, ctx),`);
1648
- }
1649
-
1650
- if (strategy.mustMatchWhenDerived) {
1651
- mustMatchKeys.push(key);
1652
- }
1653
- }
1654
-
1655
- lines.push('}'); // There are some constraints that can be derived and marked as "must match", where if they are derived, they only match routes that actually have a constraint on the value, like the SemVer version constraint.
1656
- // An example: a request comes in for version 1.x, and this node has a handler that maches the path, but there's no version constraint. For SemVer, the find-my-way semantics do not match this handler to that request.
1657
- // This function is used by Nodes with handlers to match when they don't have any constrained routes to exclude request that do have must match derived constraints present.
1658
-
1659
- if (mustMatchKeys.length > 0) {
1660
- lines.push(`derivedConstraints.__hasMustMatchValues = !!(${mustMatchKeys.map(key => `derivedConstraints.${key}`).join(' || ')})`);
1661
- }
1662
-
1663
- lines.push('return derivedConstraints');
1664
- this.deriveConstraints = new Function('req', 'ctx', lines.join('\n')).bind(this); // eslint-disable-line
1665
- }
1666
-
1667
- }
1668
-
1669
- var constrainer = Constrainer;
1670
-
1671
- /*
1672
- Char codes:
1673
- '#': 35
1674
- '*': 42
1675
- '-': 45
1676
- '/': 47
1677
- ':': 58
1678
- ';': 59
1679
- '?': 63
1680
- */
1681
-
1682
-
1683
- const {
1684
- flattenNode,
1685
- compressFlattenedNode,
1686
- prettyPrintFlattenedNode,
1687
- prettyPrintRoutesArray
1688
- } = prettyPrint;
1689
- const NODE_TYPES = node.prototype.types;
1690
- const httpMethods = http__default['default'].METHODS;
1691
- const FULL_PATH_REGEXP = /^https?:\/\/.*?\//;
1692
-
1693
- if (!safeRegex2(FULL_PATH_REGEXP)) {
1694
- throw new Error('the FULL_PATH_REGEXP is not safe, update this module');
1695
- }
1696
-
1697
- function Router(opts) {
1698
- if (!(this instanceof Router)) {
1699
- return new Router(opts);
1700
- }
1701
-
1702
- opts = opts || {};
1703
-
1704
- if (opts.defaultRoute) {
1705
- assert__default['default'](typeof opts.defaultRoute === 'function', 'The default route must be a function');
1706
- this.defaultRoute = opts.defaultRoute;
1707
- } else {
1708
- this.defaultRoute = null;
1709
- }
1710
-
1711
- if (opts.onBadUrl) {
1712
- assert__default['default'](typeof opts.onBadUrl === 'function', 'The bad url handler must be a function');
1713
- this.onBadUrl = opts.onBadUrl;
1714
- } else {
1715
- this.onBadUrl = null;
1716
- }
1717
-
1718
- this.caseSensitive = opts.caseSensitive === undefined ? true : opts.caseSensitive;
1719
- this.ignoreTrailingSlash = opts.ignoreTrailingSlash || false;
1720
- this.maxParamLength = opts.maxParamLength || 100;
1721
- this.allowUnsafeRegex = opts.allowUnsafeRegex || false;
1722
- this.constrainer = new constrainer(opts.constraints);
1723
- this.trees = {};
1724
- this.routes = [];
1725
- }
1726
-
1727
- Router.prototype.on = function on(method, path, opts, handler, store) {
1728
- if (typeof opts === 'function') {
1729
- if (handler !== undefined) {
1730
- store = handler;
1731
- }
1732
-
1733
- handler = opts;
1734
- opts = {};
1735
- } // path validation
1736
-
1737
-
1738
- assert__default['default'](typeof path === 'string', 'Path should be a string');
1739
- assert__default['default'](path.length > 0, 'The path could not be empty');
1740
- assert__default['default'](path[0] === '/' || path[0] === '*', 'The first character of a path should be `/` or `*`'); // handler validation
1741
-
1742
- assert__default['default'](typeof handler === 'function', 'Handler should be a function');
1743
-
1744
- this._on(method, path, opts, handler, store);
1745
-
1746
- if (this.ignoreTrailingSlash && path !== '/' && !path.endsWith('*')) {
1747
- if (path.endsWith('/')) {
1748
- this._on(method, path.slice(0, -1), opts, handler, store);
1749
- } else {
1750
- this._on(method, path + '/', opts, handler, store);
1751
- }
1752
- }
1753
- };
1754
-
1755
- Router.prototype._on = function _on(method, path, opts, handler, store) {
1756
- if (Array.isArray(method)) {
1757
- for (var k = 0; k < method.length; k++) {
1758
- this._on(method[k], path, opts, handler, store);
1759
- }
1760
-
1761
- return;
1762
- }
1763
-
1764
- assert__default['default'](typeof method === 'string', 'Method should be a string');
1765
- assert__default['default'](httpMethods.indexOf(method) !== -1, `Method '${method}' is not an http method.`);
1766
- let constraints = {};
1767
-
1768
- if (opts.constraints !== undefined) {
1769
- assert__default['default'](typeof opts.constraints === 'object' && opts.constraints !== null, 'Constraints should be an object');
1770
-
1771
- if (Object.keys(opts.constraints).length !== 0) {
1772
- constraints = opts.constraints;
1773
- }
1774
- }
1775
-
1776
- this.constrainer.validateConstraints(constraints); // Let the constrainer know if any constraints are being used now
1777
-
1778
- this.constrainer.noteUsage(constraints);
1779
- const params = [];
1780
- var j = 0;
1781
- this.routes.push({
1782
- method: method,
1783
- path: path,
1784
- opts: opts,
1785
- handler: handler,
1786
- store: store
1787
- });
1788
-
1789
- for (var i = 0, len = path.length; i < len; i++) {
1790
- // search for parametric or wildcard routes
1791
- // parametric route
1792
- if (path.charCodeAt(i) === 58) {
1793
- if (i !== len - 1 && path.charCodeAt(i + 1) === 58) {
1794
- // It's a double colon. Let's just replace it with a single colon and go ahead
1795
- path = path.slice(0, i) + path.slice(i + 1);
1796
- len = path.length;
1797
- continue;
1798
- }
1799
-
1800
- var nodeType = NODE_TYPES.PARAM;
1801
- j = i + 1;
1802
- var staticPart = path.slice(0, i);
1803
-
1804
- if (this.caseSensitive === false) {
1805
- staticPart = staticPart.toLowerCase();
1806
- } // add the static part of the route to the tree
1807
-
1808
-
1809
- this._insert(method, staticPart, NODE_TYPES.STATIC, null, null, null, null, constraints); // isolate the parameter name
1810
-
1811
-
1812
- var isRegex = false;
1813
-
1814
- while (i < len && path.charCodeAt(i) !== 47) {
1815
- isRegex = isRegex || path[i] === '(';
1816
-
1817
- if (isRegex) {
1818
- i = getClosingParenthensePosition(path, i) + 1;
1819
- break;
1820
- } else if (path.charCodeAt(i) !== 45) {
1821
- i++;
1822
- } else {
1823
- break;
1824
- }
1825
- }
1826
-
1827
- if (isRegex && (i === len || path.charCodeAt(i) === 47)) {
1828
- nodeType = NODE_TYPES.REGEX;
1829
- } else if (i < len && path.charCodeAt(i) !== 47) {
1830
- nodeType = NODE_TYPES.MULTI_PARAM;
1831
- }
1832
-
1833
- var parameter = path.slice(j, i);
1834
- var regex = isRegex ? parameter.slice(parameter.indexOf('('), i) : null;
1835
-
1836
- if (isRegex) {
1837
- regex = new RegExp(regex);
1838
-
1839
- if (!this.allowUnsafeRegex) {
1840
- assert__default['default'](safeRegex2(regex), `The regex '${regex.toString()}' is not safe!`);
1841
- }
1842
- }
1843
-
1844
- params.push(parameter.slice(0, isRegex ? parameter.indexOf('(') : i));
1845
- path = path.slice(0, j) + path.slice(i);
1846
- i = j;
1847
- len = path.length; // if the path is ended
1848
-
1849
- if (i === len) {
1850
- var completedPath = path.slice(0, i);
1851
-
1852
- if (this.caseSensitive === false) {
1853
- completedPath = completedPath.toLowerCase();
1854
- }
1855
-
1856
- return this._insert(method, completedPath, nodeType, params, handler, store, regex, constraints);
1857
- } // add the parameter and continue with the search
1858
-
1859
-
1860
- staticPart = path.slice(0, i);
1861
-
1862
- if (this.caseSensitive === false) {
1863
- staticPart = staticPart.toLowerCase();
1864
- }
1865
-
1866
- this._insert(method, staticPart, nodeType, params, null, null, regex, constraints);
1867
-
1868
- i--; // wildcard route
1869
- } else if (path.charCodeAt(i) === 42) {
1870
- this._insert(method, path.slice(0, i), NODE_TYPES.STATIC, null, null, null, null, constraints); // add the wildcard parameter
1871
-
1872
-
1873
- params.push('*');
1874
- return this._insert(method, path.slice(0, len), NODE_TYPES.MATCH_ALL, params, handler, store, null, constraints);
1875
- }
1876
- }
1877
-
1878
- if (this.caseSensitive === false) {
1879
- path = path.toLowerCase();
1880
- } // static route
1881
-
1882
-
1883
- this._insert(method, path, NODE_TYPES.STATIC, params, handler, store, null, constraints);
1884
- };
1885
-
1886
- Router.prototype._insert = function _insert(method, path, kind, params, handler, store, regex, constraints) {
1887
- const route = path;
1888
- var prefix = '';
1889
- var pathLen = 0;
1890
- var prefixLen = 0;
1891
- var len = 0;
1892
- var max = 0;
1893
- var node$1 = null; // Boot the tree for this method if it doesn't exist yet
1894
-
1895
- var currentNode = this.trees[method];
1896
-
1897
- if (typeof currentNode === 'undefined') {
1898
- currentNode = new node({
1899
- method: method,
1900
- constrainer: this.constrainer
1901
- });
1902
- this.trees[method] = currentNode;
1903
- }
1904
-
1905
- while (true) {
1906
- prefix = currentNode.prefix;
1907
- prefixLen = prefix.length;
1908
- pathLen = path.length;
1909
- len = 0; // search for the longest common prefix
1910
-
1911
- max = pathLen < prefixLen ? pathLen : prefixLen;
1912
-
1913
- while (len < max && path[len] === prefix[len]) len++; // the longest common prefix is smaller than the current prefix
1914
- // let's split the node and add a new child
1915
-
1916
-
1917
- if (len < prefixLen) {
1918
- node$1 = currentNode.split(len); // if the longest common prefix has the same length of the current path
1919
- // the handler should be added to the current node, to a child otherwise
1920
-
1921
- if (len === pathLen) {
1922
- assert__default['default'](!currentNode.getHandler(constraints), `Method '${method}' already declared for route '${route}' with constraints '${JSON.stringify(constraints)}'`);
1923
- currentNode.addHandler(handler, params, store, constraints);
1924
- currentNode.kind = kind;
1925
- } else {
1926
- node$1 = new node({
1927
- method: method,
1928
- prefix: path.slice(len),
1929
- kind: kind,
1930
- handlers: null,
1931
- regex: regex,
1932
- constrainer: this.constrainer
1933
- });
1934
- node$1.addHandler(handler, params, store, constraints);
1935
- currentNode.addChild(node$1);
1936
- } // the longest common prefix is smaller than the path length,
1937
- // but is higher than the prefix
1938
-
1939
- } else if (len < pathLen) {
1940
- // remove the prefix
1941
- path = path.slice(len); // check if there is a child with the label extracted from the new path
1942
-
1943
- node$1 = currentNode.findByLabel(path); // there is a child within the given label, we must go deepen in the tree
1944
-
1945
- if (node$1) {
1946
- currentNode = node$1;
1947
- continue;
1948
- } // there are not children within the given label, let's create a new one!
1949
-
1950
-
1951
- node$1 = new node({
1952
- method: method,
1953
- prefix: path,
1954
- kind: kind,
1955
- handlers: null,
1956
- regex: regex,
1957
- constrainer: this.constrainer
1958
- });
1959
- node$1.addHandler(handler, params, store, constraints);
1960
- currentNode.addChild(node$1); // the node already exist
1961
- } else if (handler) {
1962
- assert__default['default'](!currentNode.getHandler(constraints), `Method '${method}' already declared for route '${route}' with constraints '${JSON.stringify(constraints)}'`);
1963
- currentNode.addHandler(handler, params, store, constraints);
1964
- }
1965
-
1966
- return;
1967
- }
1968
- };
1969
-
1970
- Router.prototype.reset = function reset() {
1971
- this.trees = {};
1972
- this.routes = [];
1973
- };
1974
-
1975
- Router.prototype.off = function off(method, path) {
1976
- var self = this;
1977
-
1978
- if (Array.isArray(method)) {
1979
- return method.map(function (method) {
1980
- return self.off(method, path);
1981
- });
1982
- } // method validation
1983
-
1984
-
1985
- assert__default['default'](typeof method === 'string', 'Method should be a string');
1986
- assert__default['default'](httpMethods.indexOf(method) !== -1, `Method '${method}' is not an http method.`); // path validation
1987
-
1988
- assert__default['default'](typeof path === 'string', 'Path should be a string');
1989
- assert__default['default'](path.length > 0, 'The path could not be empty');
1990
- assert__default['default'](path[0] === '/' || path[0] === '*', 'The first character of a path should be `/` or `*`'); // Rebuild tree without the specific route
1991
-
1992
- const ignoreTrailingSlash = this.ignoreTrailingSlash;
1993
- var newRoutes = self.routes.filter(function (route) {
1994
- if (!ignoreTrailingSlash) {
1995
- return !(method === route.method && path === route.path);
1996
- }
1997
-
1998
- if (path.endsWith('/')) {
1999
- const routeMatches = path === route.path || path.slice(0, -1) === route.path;
2000
- return !(method === route.method && routeMatches);
2001
- }
2002
-
2003
- const routeMatches = path === route.path || path + '/' === route.path;
2004
- return !(method === route.method && routeMatches);
2005
- });
2006
-
2007
- if (ignoreTrailingSlash) {
2008
- newRoutes = newRoutes.filter(function (route, i, ar) {
2009
- if (route.path.endsWith('/') && i < ar.length - 1) {
2010
- return route.path.slice(0, -1) !== ar[i + 1].path;
2011
- } else if (route.path.endsWith('/') === false && i < ar.length - 1) {
2012
- return route.path + '/' !== ar[i + 1].path;
2013
- }
2014
-
2015
- return true;
2016
- });
2017
- }
2018
-
2019
- self.reset();
2020
- newRoutes.forEach(function (route) {
2021
- self.on(route.method, route.path, route.opts, route.handler, route.store);
2022
- });
2023
- };
2024
-
2025
- Router.prototype.lookup = function lookup(req, res, ctx) {
2026
- var handle = this.find(req.method, sanitizeUrl(req.url), this.constrainer.deriveConstraints(req, ctx));
2027
- if (handle === null) return this._defaultRoute(req, res, ctx);
2028
- return ctx === undefined ? handle.handler(req, res, handle.params, handle.store) : handle.handler.call(ctx, req, res, handle.params, handle.store);
2029
- };
2030
-
2031
- Router.prototype.find = function find(method, path, derivedConstraints) {
2032
- var currentNode = this.trees[method];
2033
- if (currentNode === undefined) return null;
2034
-
2035
- if (path.charCodeAt(0) !== 47) {
2036
- // 47 is '/'
2037
- path = path.replace(FULL_PATH_REGEXP, '/');
2038
- }
2039
-
2040
- var originalPath = path;
2041
- var originalPathLength = path.length;
2042
-
2043
- if (this.caseSensitive === false) {
2044
- path = path.toLowerCase();
2045
- }
2046
-
2047
- var maxParamLength = this.maxParamLength;
2048
- var wildcardNode = null;
2049
- var pathLenWildcard = 0;
2050
- var decoded = null;
2051
- var pindex = 0;
2052
- var params = null;
2053
- var i = 0;
2054
- var idxInOriginalPath = 0;
2055
-
2056
- while (true) {
2057
- var pathLen = path.length;
2058
- var prefix = currentNode.prefix; // found the route
2059
-
2060
- if (pathLen === 0 || path === prefix) {
2061
- var handle = derivedConstraints !== undefined ? currentNode.getMatchingHandler(derivedConstraints) : currentNode.unconstrainedHandler;
2062
-
2063
- if (handle !== null && handle !== undefined) {
2064
- var paramsObj = {};
2065
-
2066
- if (handle.paramsLength > 0) {
2067
- var paramNames = handle.params;
2068
-
2069
- for (i = 0; i < handle.paramsLength; i++) {
2070
- paramsObj[paramNames[i]] = params[i];
2071
- }
2072
- }
2073
-
2074
- return {
2075
- handler: handle.handler,
2076
- params: paramsObj,
2077
- store: handle.store
2078
- };
2079
- }
2080
- }
2081
-
2082
- var prefixLen = prefix.length;
2083
- var len = 0;
2084
- var previousPath = path; // search for the longest common prefix
2085
-
2086
- i = pathLen < prefixLen ? pathLen : prefixLen;
2087
-
2088
- while (len < i && path.charCodeAt(len) === prefix.charCodeAt(len)) len++;
2089
-
2090
- if (len === prefixLen) {
2091
- path = path.slice(len);
2092
- pathLen = path.length;
2093
- idxInOriginalPath += len;
2094
- }
2095
-
2096
- var node = currentNode.findMatchingChild(derivedConstraints, path);
2097
-
2098
- if (node === null) {
2099
- node = currentNode.parametricBrother;
2100
-
2101
- if (node === null) {
2102
- return this._getWildcardNode(wildcardNode, originalPath, pathLenWildcard);
2103
- }
2104
-
2105
- var goBack = previousPath.charCodeAt(0) === 47 ? previousPath : '/' + previousPath;
2106
-
2107
- if (originalPath.indexOf(goBack) === -1) {
2108
- // we need to know the outstanding path so far from the originalPath since the last encountered "/" and assign it to previousPath.
2109
- // e.g originalPath: /aa/bbb/cc, path: bb/cc
2110
- // outstanding path: /bbb/cc
2111
- var pathDiff = originalPath.slice(0, originalPathLength - pathLen);
2112
- previousPath = pathDiff.slice(pathDiff.lastIndexOf('/') + 1, pathDiff.length) + path;
2113
- }
2114
-
2115
- idxInOriginalPath = idxInOriginalPath - (previousPath.length - path.length);
2116
- path = previousPath;
2117
- pathLen = previousPath.length;
2118
- len = prefixLen;
2119
- }
2120
-
2121
- var kind = node.kind; // static route
2122
-
2123
- if (kind === NODE_TYPES.STATIC) {
2124
- // if exist, save the wildcard child
2125
- if (currentNode.wildcardChild !== null) {
2126
- wildcardNode = currentNode.wildcardChild;
2127
- pathLenWildcard = pathLen;
2128
- }
2129
-
2130
- currentNode = node;
2131
- continue;
2132
- }
2133
-
2134
- if (len !== prefixLen) {
2135
- return this._getWildcardNode(wildcardNode, originalPath, pathLenWildcard);
2136
- } // if exist, save the wildcard child
2137
-
2138
-
2139
- if (currentNode.wildcardChild !== null) {
2140
- wildcardNode = currentNode.wildcardChild;
2141
- pathLenWildcard = pathLen;
2142
- } // parametric route
2143
-
2144
-
2145
- if (kind === NODE_TYPES.PARAM) {
2146
- currentNode = node;
2147
- i = path.indexOf('/');
2148
- if (i === -1) i = pathLen;
2149
- if (i > maxParamLength) return null;
2150
- decoded = fastDecodeUriComponent(originalPath.slice(idxInOriginalPath, idxInOriginalPath + i));
2151
-
2152
- if (decoded === null) {
2153
- return this.onBadUrl !== null ? this._onBadUrl(originalPath.slice(idxInOriginalPath, idxInOriginalPath + i)) : null;
2154
- }
2155
-
2156
- params || (params = []);
2157
- params[pindex++] = decoded;
2158
- path = path.slice(i);
2159
- idxInOriginalPath += i;
2160
- continue;
2161
- } // wildcard route
2162
-
2163
-
2164
- if (kind === NODE_TYPES.MATCH_ALL) {
2165
- decoded = fastDecodeUriComponent(originalPath.slice(idxInOriginalPath));
2166
-
2167
- if (decoded === null) {
2168
- return this.onBadUrl !== null ? this._onBadUrl(originalPath.slice(idxInOriginalPath)) : null;
2169
- }
2170
-
2171
- params || (params = []);
2172
- params[pindex] = decoded;
2173
- currentNode = node;
2174
- path = '';
2175
- continue;
2176
- } // parametric(regex) route
2177
-
2178
-
2179
- if (kind === NODE_TYPES.REGEX) {
2180
- currentNode = node;
2181
- i = path.indexOf('/');
2182
- if (i === -1) i = pathLen;
2183
- if (i > maxParamLength) return null;
2184
- decoded = fastDecodeUriComponent(originalPath.slice(idxInOriginalPath, idxInOriginalPath + i));
2185
-
2186
- if (decoded === null) {
2187
- return this.onBadUrl !== null ? this._onBadUrl(originalPath.slice(idxInOriginalPath, idxInOriginalPath + i)) : null;
2188
- }
2189
-
2190
- if (!node.regex.test(decoded)) return null;
2191
- params || (params = []);
2192
- params[pindex++] = decoded;
2193
- path = path.slice(i);
2194
- idxInOriginalPath += i;
2195
- continue;
2196
- } // multiparametric route
2197
-
2198
-
2199
- if (kind === NODE_TYPES.MULTI_PARAM) {
2200
- currentNode = node;
2201
- i = 0;
2202
-
2203
- if (node.regex !== null) {
2204
- var matchedParameter = path.match(node.regex);
2205
- if (matchedParameter === null) return null;
2206
- i = matchedParameter[1].length;
2207
- } else {
2208
- while (i < pathLen && path.charCodeAt(i) !== 47 && path.charCodeAt(i) !== 45) i++;
2209
-
2210
- if (i > maxParamLength) return null;
2211
- }
2212
-
2213
- decoded = fastDecodeUriComponent(originalPath.slice(idxInOriginalPath, idxInOriginalPath + i));
2214
-
2215
- if (decoded === null) {
2216
- return this.onBadUrl !== null ? this._onBadUrl(originalPath.slice(idxInOriginalPath, idxInOriginalPath + i)) : null;
2217
- }
2218
-
2219
- params || (params = []);
2220
- params[pindex++] = decoded;
2221
- path = path.slice(i);
2222
- idxInOriginalPath += i;
2223
- continue;
2224
- }
2225
-
2226
- wildcardNode = null;
2227
- }
2228
- };
2229
-
2230
- Router.prototype._getWildcardNode = function (node, path, len) {
2231
- if (node === null) return null;
2232
- var decoded = fastDecodeUriComponent(path.slice(-len));
2233
-
2234
- if (decoded === null) {
2235
- return this.onBadUrl !== null ? this._onBadUrl(path.slice(-len)) : null;
2236
- }
2237
-
2238
- var handle = node.handlers[0];
2239
-
2240
- if (handle !== null && handle !== undefined) {
2241
- return {
2242
- handler: handle.handler,
2243
- params: {
2244
- '*': decoded
2245
- },
2246
- store: handle.store
2247
- };
2248
- }
2249
-
2250
- return null;
2251
- };
2252
-
2253
- Router.prototype._defaultRoute = function (req, res, ctx) {
2254
- if (this.defaultRoute !== null) {
2255
- return ctx === undefined ? this.defaultRoute(req, res) : this.defaultRoute.call(ctx, req, res);
2256
- } else {
2257
- res.statusCode = 404;
2258
- res.end();
2259
- }
2260
- };
2261
-
2262
- Router.prototype._onBadUrl = function (path) {
2263
- const onBadUrl = this.onBadUrl;
2264
- return {
2265
- handler: (req, res, ctx) => onBadUrl(path, req, res),
2266
- params: {},
2267
- store: null
2268
- };
2269
- };
2270
-
2271
- Router.prototype.prettyPrint = function (opts = {}) {
2272
- opts.commonPrefix = opts.commonPrefix === undefined ? true : opts.commonPrefix; // default to original behaviour
2273
-
2274
- if (!opts.commonPrefix) return prettyPrintRoutesArray(this.routes);
2275
- const root = {
2276
- prefix: '/',
2277
- nodes: [],
2278
- children: {}
2279
- };
2280
-
2281
- for (const node of Object.values(this.trees)) {
2282
- if (node) {
2283
- flattenNode(root, node);
2284
- }
2285
- }
2286
-
2287
- compressFlattenedNode(root);
2288
- return prettyPrintFlattenedNode(root, '', true);
2289
- };
2290
-
2291
- for (var i in http__default['default'].METHODS) {
2292
- /* eslint no-prototype-builtins: "off" */
2293
- if (!http__default['default'].METHODS.hasOwnProperty(i)) continue;
2294
- const m = http__default['default'].METHODS[i];
2295
- const methodName = m.toLowerCase();
2296
- if (Router.prototype[methodName]) throw new Error('Method already exists: ' + methodName);
2297
-
2298
- Router.prototype[methodName] = function (path, handler, store) {
2299
- return this.on(m, path, handler, store);
2300
- };
2301
- }
2302
-
2303
- Router.prototype.all = function (path, handler, store) {
2304
- this.on(httpMethods, path, handler, store);
2305
- };
2306
-
2307
- var findMyWay = Router;
2308
-
2309
- function sanitizeUrl(url) {
2310
- for (var i = 0, len = url.length; i < len; i++) {
2311
- var charCode = url.charCodeAt(i); // Some systems do not follow RFC and separate the path and query
2312
- // string with a `;` character (code 59), e.g. `/foo;jsessionid=123456`.
2313
- // Thus, we need to split on `;` as well as `?` and `#`.
2314
-
2315
- if (charCode === 63 || charCode === 59 || charCode === 35) {
2316
- return url.slice(0, i);
2317
- }
2318
- }
2319
-
2320
- return url;
2321
- }
2322
-
2323
- function getClosingParenthensePosition(path, idx) {
2324
- // `path.indexOf()` will always return the first position of the closing parenthese,
2325
- // but it's inefficient for grouped or wrong regexp expressions.
2326
- // see issues #62 and #63 for more info
2327
- var parentheses = 1;
2328
-
2329
- while (idx < path.length) {
2330
- idx++; // ignore skipped chars
2331
-
2332
- if (path[idx] === '\\') {
2333
- idx++;
2334
- continue;
2335
- }
2336
-
2337
- if (path[idx] === ')') {
2338
- parentheses--;
2339
- } else if (path[idx] === '(') {
2340
- parentheses++;
2341
- }
2342
-
2343
- if (!parentheses) return idx;
2344
- }
2345
-
2346
- throw new TypeError('Invalid regexp expression in "' + path + '"');
2347
- }
2348
-
2349
- var index = /*#__PURE__*/Object.assign(/*#__PURE__*/Object.create(null), findMyWay, {
2350
- 'default': findMyWay
2351
- });
2352
-
2353
- exports.index = index;
2354
- //# sourceMappingURL=index-eeb85309.js.map