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