@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.
- package/lib/{builder → cjs/builder}/PlatformServerless.d.ts +0 -0
- package/lib/cjs/builder/PlatformServerless.js +156 -0
- package/lib/cjs/builder/PlatformServerless.js.map +1 -0
- package/lib/{builder → cjs/builder}/PlatformServerlessHandler.d.ts +0 -0
- package/lib/cjs/builder/PlatformServerlessHandler.js +93 -0
- package/lib/cjs/builder/PlatformServerlessHandler.js.map +1 -0
- package/lib/{domain → cjs/domain}/ServerlessContext.d.ts +0 -0
- package/lib/cjs/domain/ServerlessContext.js +26 -0
- package/lib/cjs/domain/ServerlessContext.js.map +1 -0
- package/lib/{domain → cjs/domain}/ServerlessRequest.d.ts +0 -0
- package/lib/cjs/domain/ServerlessRequest.js +80 -0
- package/lib/cjs/domain/ServerlessRequest.js.map +1 -0
- package/lib/{domain → cjs/domain}/ServerlessResponse.d.ts +0 -0
- package/lib/cjs/domain/ServerlessResponse.js +193 -0
- package/lib/cjs/domain/ServerlessResponse.js.map +1 -0
- package/lib/{index.d.ts → cjs/index.d.ts} +0 -0
- package/lib/cjs/index.js +23 -0
- package/lib/cjs/index.js.map +1 -0
- package/lib/{services → cjs/services}/PlatformServerlessTest.d.ts +0 -0
- package/lib/cjs/services/PlatformServerlessTest.js +196 -0
- package/lib/cjs/services/PlatformServerlessTest.js.map +1 -0
- package/lib/{utils → cjs/utils}/getRequestId.d.ts +0 -0
- package/lib/cjs/utils/getRequestId.js +13 -0
- package/lib/cjs/utils/getRequestId.js.map +1 -0
- package/lib/{utils → cjs/utils}/setResponseHeaders.d.ts +0 -0
- package/lib/cjs/utils/setResponseHeaders.js +35 -0
- package/lib/cjs/utils/setResponseHeaders.js.map +1 -0
- package/lib/esm/builder/PlatformServerless.js +133 -0
- package/lib/esm/builder/PlatformServerless.js.map +1 -0
- package/lib/esm/builder/PlatformServerlessHandler.js +90 -0
- package/lib/esm/builder/PlatformServerlessHandler.js.map +1 -0
- package/lib/esm/domain/ServerlessContext.js +22 -0
- package/lib/esm/domain/ServerlessContext.js.map +1 -0
- package/lib/esm/domain/ServerlessRequest.js +76 -0
- package/lib/esm/domain/ServerlessRequest.js.map +1 -0
- package/lib/esm/domain/ServerlessResponse.js +189 -0
- package/lib/esm/domain/ServerlessResponse.js.map +1 -0
- package/lib/esm/index.js +11 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/services/PlatformServerlessTest.js +191 -0
- package/lib/esm/services/PlatformServerlessTest.js.map +1 -0
- package/lib/esm/utils/getRequestId.js +9 -0
- package/lib/esm/utils/getRequestId.js.map +1 -0
- package/lib/esm/utils/setResponseHeaders.js +31 -0
- package/lib/esm/utils/setResponseHeaders.js.map +1 -0
- package/lib/types/builder/PlatformServerless.d.ts +31 -0
- package/lib/types/builder/PlatformServerlessHandler.d.ts +19 -0
- package/lib/types/domain/ServerlessContext.d.ts +19 -0
- package/lib/types/domain/ServerlessRequest.d.ts +55 -0
- package/lib/types/domain/ServerlessResponse.d.ts +105 -0
- package/lib/types/index.d.ts +9 -0
- package/lib/types/services/PlatformServerlessTest.d.ts +46 -0
- package/lib/types/utils/getRequestId.d.ts +2 -0
- package/lib/types/utils/setResponseHeaders.d.ts +5 -0
- package/package.json +17 -13
- package/tsconfig.compile.esm.json +23 -0
- package/lib/index-a6c91998.js +0 -955
- package/lib/index-a6c91998.js.map +0 -1
- package/lib/index-a7574150.js +0 -975
- package/lib/index-a7574150.js.map +0 -1
- package/lib/index-b255dcf0.js +0 -2350
- package/lib/index-b255dcf0.js.map +0 -1
- package/lib/index-eeb85309.js +0 -2354
- package/lib/index-eeb85309.js.map +0 -1
- package/lib/index.js +0 -90
- package/lib/index.js.map +0 -1
- package/lib/index.modern.js +0 -12
- package/lib/index.modern.js.map +0 -1
package/lib/index-b255dcf0.js
DELETED
|
@@ -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
|