k99 0.2.0 → 0.3.0-beta.1
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/LICENSE +1 -1
- package/README.md +8 -0
- package/README.zh.md +8 -0
- package/browser/package.json +8 -0
- package/browser/types.d.ts +20 -0
- package/cli/command/create.js +1 -2
- package/cli/command/index.js +1 -2
- package/cli/command/init.js +3 -5
- package/cli/command/start.js +9 -10
- package/cli/index.js +3 -4
- package/cli/opt/bind.js +1 -2
- package/cli/opt/index.js +1 -2
- package/cli/opt/listen.js +1 -2
- package/cli/opt/path.js +1 -2
- package/cli/opt/port.js +1 -2
- package/cli/opt/show-router.js +1 -2
- package/dist/k99.browser.js +3110 -0
- package/dist/k99.browser.min.js +6 -0
- package/dist/k99.esm.js +3082 -0
- package/dist/k99.esm.min.js +6 -0
- package/dist/k99.js +3104 -0
- package/dist/k99.mjs +3082 -0
- package/dist/k99Browser.browser.js +490 -0
- package/dist/k99Browser.browser.min.js +6 -0
- package/dist/k99Browser.esm.js +475 -0
- package/dist/k99Browser.esm.min.js +6 -0
- package/dist/k99Browser.js +484 -0
- package/dist/k99Browser.mjs +475 -0
- package/dist/k99Services.browser.js +145 -0
- package/dist/k99Services.browser.min.js +6 -0
- package/dist/k99Services.esm.js +136 -0
- package/dist/k99Services.esm.min.js +6 -0
- package/dist/k99Services.js +141 -0
- package/dist/k99Services.mjs +136 -0
- package/node/index.js +1386 -0
- package/node/index.mjs +1350 -0
- package/node/package.json +5 -0
- package/node/types.d.ts +166 -0
- package/package.json +77 -11
- package/services/package.json +8 -0
- package/services/types.d.ts +22 -0
- package/starter.js +0 -1
- package/types.d.ts +748 -0
- package/Container.d.ts +0 -92
- package/Container.js +0 -242
- package/Container.js.map +0 -1
- package/Controller/index.d.ts +0 -178
- package/Controller/index.js +0 -576
- package/Controller/index.js.map +0 -1
- package/Controller/patch/cookie.d.ts +0 -33
- package/Controller/patch/cookie.js +0 -168
- package/Controller/patch/cookie.js.map +0 -1
- package/Controller/patch/index.d.ts +0 -7
- package/Controller/patch/index.js +0 -26
- package/Controller/patch/index.js.map +0 -1
- package/Controller/patch/render.d.ts +0 -5
- package/Controller/patch/render.js +0 -24
- package/Controller/patch/render.js.map +0 -1
- package/ExitSignal.d.ts +0 -14
- package/ExitSignal.js +0 -29
- package/ExitSignal.js.map +0 -1
- package/Extension.d.ts +0 -56
- package/Extension.js +0 -93
- package/Extension.js.map +0 -1
- package/ExtensionContainer.d.ts +0 -55
- package/ExtensionContainer.js +0 -105
- package/ExtensionContainer.js.map +0 -1
- package/Plugin.d.ts +0 -52
- package/Plugin.js +0 -278
- package/Plugin.js.map +0 -1
- package/Preprocessor.d.ts +0 -86
- package/Preprocessor.js +0 -135
- package/Preprocessor.js.map +0 -1
- package/Router/assets.d.ts +0 -33
- package/Router/assets.js +0 -106
- package/Router/assets.js.map +0 -1
- package/Router/callback.d.ts +0 -9
- package/Router/callback.js +0 -152
- package/Router/callback.js.map +0 -1
- package/Router/extendsInterface.d.ts +0 -8
- package/Router/extendsInterface.js +0 -43
- package/Router/extendsInterface.js.map +0 -1
- package/Router/index.d.ts +0 -184
- package/Router/index.js +0 -615
- package/Router/index.js.map +0 -1
- package/Router/log.d.ts +0 -23
- package/Router/log.js +0 -120
- package/Router/log.js.map +0 -1
- package/Router/order.d.ts +0 -14
- package/Router/order.js +0 -71
- package/Router/order.js.map +0 -1
- package/Router/register.d.ts +0 -9
- package/Router/register.js +0 -252
- package/Router/register.js.map +0 -1
- package/Router/registerManager.d.ts +0 -22
- package/Router/registerManager.js +0 -102
- package/Router/registerManager.js.map +0 -1
- package/Router/scan.d.ts +0 -2
- package/Router/scan.js +0 -72
- package/Router/scan.js.map +0 -1
- package/Router/setHandleItem.d.ts +0 -3
- package/Router/setHandleItem.js +0 -94
- package/Router/setHandleItem.js.map +0 -1
- package/Router/settings.d.ts +0 -12
- package/Router/settings.js +0 -74
- package/Router/settings.js.map +0 -1
- package/Router/start.d.ts +0 -3
- package/Router/start.js +0 -270
- package/Router/start.js.map +0 -1
- package/Router/vars.d.ts +0 -10
- package/Router/vars.js +0 -40
- package/Router/vars.js.map +0 -1
- package/Service.d.ts +0 -12
- package/Service.js +0 -20
- package/Service.js.map +0 -1
- package/cli/command/create.d.ts +0 -7
- package/cli/command/create.js.map +0 -1
- package/cli/command/index.d.ts +0 -7
- package/cli/command/index.js.map +0 -1
- package/cli/command/init.d.ts +0 -6
- package/cli/command/init.js.map +0 -1
- package/cli/command/start.d.ts +0 -6
- package/cli/command/start.js.map +0 -1
- package/cli/index.d.ts +0 -2
- package/cli/index.js.map +0 -1
- package/cli/opt/bind.d.ts +0 -3
- package/cli/opt/bind.js.map +0 -1
- package/cli/opt/index.d.ts +0 -16
- package/cli/opt/index.js.map +0 -1
- package/cli/opt/listen.d.ts +0 -3
- package/cli/opt/listen.js.map +0 -1
- package/cli/opt/path.d.ts +0 -3
- package/cli/opt/path.js.map +0 -1
- package/cli/opt/port.d.ts +0 -3
- package/cli/opt/port.js.map +0 -1
- package/cli/opt/show-router.d.ts +0 -3
- package/cli/opt/show-router.js.map +0 -1
- package/index.d.ts +0 -354
- package/index.js +0 -155
- package/index.js.map +0 -1
- package/setOptions.d.ts +0 -12
- package/setOptions.js +0 -60
- package/setOptions.js.map +0 -1
- package/starter.d.ts +0 -2
- package/starter.js.map +0 -1
- package/symbols.d.ts +0 -13
- package/symbols.js +0 -31
- package/symbols.js.map +0 -1
- package/util/index.d.ts +0 -5
- package/util/index.js +0 -92
- package/util/index.js.map +0 -1
- package/util/stream.d.ts +0 -19
- package/util/stream.js +0 -66
- package/util/stream.js.map +0 -1
package/dist/k99.esm.js
ADDED
|
@@ -0,0 +1,3082 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* k99 v0.3.0-beta.1
|
|
3
|
+
* (c) 2019-2022 Fierflame
|
|
4
|
+
* @license MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* 服务
|
|
8
|
+
*/
|
|
9
|
+
class Service {
|
|
10
|
+
/**
|
|
11
|
+
* @warning 不要重载构造函数或者主动调用创建实例
|
|
12
|
+
*/
|
|
13
|
+
constructor(context) {
|
|
14
|
+
this.context = context;
|
|
15
|
+
Object.defineProperties(this, Object.getOwnPropertyDescriptors(context));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** 销毁时,会自动调用此方法销毁自动创建的容器 */
|
|
19
|
+
async destroy() {}
|
|
20
|
+
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
(function (_Service) {})(Service || (Service = {}));
|
|
24
|
+
|
|
25
|
+
var Service$1 = Service;
|
|
26
|
+
|
|
27
|
+
const returnSymbol = Symbol('return');
|
|
28
|
+
const catchSymbol = Symbol('catch');
|
|
29
|
+
const finallySymbol = Symbol('finally');
|
|
30
|
+
const dataSymbol = Symbol('data');
|
|
31
|
+
const initSymbol = Symbol('init');
|
|
32
|
+
const methodsSymbol = Symbol('methods');
|
|
33
|
+
const testSymbol = Symbol('test');
|
|
34
|
+
const optionsSymbol = Symbol('options');
|
|
35
|
+
|
|
36
|
+
function Handle(handle) {
|
|
37
|
+
return handle;
|
|
38
|
+
}
|
|
39
|
+
/** 处理函数定义 */
|
|
40
|
+
|
|
41
|
+
let Log;
|
|
42
|
+
|
|
43
|
+
(function (_Log) {})(Log || (Log = {}));
|
|
44
|
+
|
|
45
|
+
let Settings;
|
|
46
|
+
|
|
47
|
+
(function (_Settings) {})(Settings || (Settings = {}));
|
|
48
|
+
|
|
49
|
+
let Assets;
|
|
50
|
+
|
|
51
|
+
(function (_Assets) {})(Assets || (Assets = {}));
|
|
52
|
+
|
|
53
|
+
function _defineProperty(obj, key, value) {
|
|
54
|
+
if (key in obj) {
|
|
55
|
+
Object.defineProperty(obj, key, {
|
|
56
|
+
value: value,
|
|
57
|
+
enumerable: true,
|
|
58
|
+
configurable: true,
|
|
59
|
+
writable: true
|
|
60
|
+
});
|
|
61
|
+
} else {
|
|
62
|
+
obj[key] = value;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return obj;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** 花括号开 */
|
|
69
|
+
const OPEN = '{';
|
|
70
|
+
/** 花括号关 */
|
|
71
|
+
|
|
72
|
+
const CLOSE = '}';
|
|
73
|
+
/** 正则匹配 */
|
|
74
|
+
|
|
75
|
+
const PATTERN = 3;
|
|
76
|
+
/** 名字 */
|
|
77
|
+
|
|
78
|
+
const NAME = 4;
|
|
79
|
+
/** 普通字符 */
|
|
80
|
+
|
|
81
|
+
const CHAR = 5;
|
|
82
|
+
/** 转义字符 */
|
|
83
|
+
|
|
84
|
+
const ESCAPED_CHAR = 6;
|
|
85
|
+
/** 数量修饰符 */
|
|
86
|
+
|
|
87
|
+
const MODIFIER = 7;
|
|
88
|
+
|
|
89
|
+
function getType$1(char) {
|
|
90
|
+
if (char === '{') {
|
|
91
|
+
return OPEN;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (char === '}') {
|
|
95
|
+
return CLOSE;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (char === '*' || char === '+' || char === '?') {
|
|
99
|
+
return MODIFIER;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return CHAR;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function isNameChar(c) {
|
|
106
|
+
return '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c === '_';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function* lexer(str) {
|
|
110
|
+
let i = 0;
|
|
111
|
+
|
|
112
|
+
while (i < str.length) {
|
|
113
|
+
const index = i;
|
|
114
|
+
const char = str[i++];
|
|
115
|
+
|
|
116
|
+
if (char === '\\') {
|
|
117
|
+
const ch = str[i++];
|
|
118
|
+
yield [ESCAPED_CHAR, index, ch];
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (char === ':') {
|
|
123
|
+
for (; i < str.length; i++) {
|
|
124
|
+
if (!isNameChar(str[i])) {
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (index + 1 === i) {
|
|
130
|
+
yield [CHAR, i, char];
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
yield [NAME, index, str.substring(index + 1, i)];
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (char !== '(') {
|
|
139
|
+
yield [getType$1(char), index, char];
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (str[i] === '?') {
|
|
144
|
+
throw new TypeError(`Pattern cannot start with "?" at ${i}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let count = 1;
|
|
148
|
+
const pattern = ['(?:'];
|
|
149
|
+
|
|
150
|
+
while (i < str.length) {
|
|
151
|
+
const c = str[i++];
|
|
152
|
+
pattern.push(c);
|
|
153
|
+
|
|
154
|
+
if (c === '\\') {
|
|
155
|
+
pattern.push(str[i++]);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (c === ')') {
|
|
160
|
+
count--;
|
|
161
|
+
|
|
162
|
+
if (count === 0) {
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (c === '[') {
|
|
170
|
+
while (i < str.length) {
|
|
171
|
+
const c = str[i++];
|
|
172
|
+
pattern.push(c);
|
|
173
|
+
|
|
174
|
+
if (c === ']') {
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (c !== '\\') {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
pattern.push(str[i++]);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (c !== '(') {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
count++;
|
|
193
|
+
pattern.push('?:');
|
|
194
|
+
|
|
195
|
+
if (str[i] !== '?') {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
i += 2;
|
|
200
|
+
|
|
201
|
+
if (str[i - 1] === ':') {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
throw new TypeError(`Invalid pattern group at ${i - 2}`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (count) {
|
|
209
|
+
throw new TypeError(`Unterminated pattern at ${index}`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (!pattern.length) {
|
|
213
|
+
throw new TypeError(`Missing pattern at ${index}`);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
yield [PATTERN, index, pattern.join('')];
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function throwError([type, index, value]) {
|
|
221
|
+
switch (type) {
|
|
222
|
+
case OPEN:
|
|
223
|
+
case CLOSE:
|
|
224
|
+
throw new TypeError(`Unexpected token '${type}' at ${index}`);
|
|
225
|
+
|
|
226
|
+
case PATTERN:
|
|
227
|
+
throw new TypeError(`Unexpected pattern '(${value})' at ${index}`);
|
|
228
|
+
|
|
229
|
+
case NAME:
|
|
230
|
+
throw new TypeError(`Unexpected name ':${value}' at ${index}`);
|
|
231
|
+
|
|
232
|
+
case CHAR:
|
|
233
|
+
throw new TypeError(`Unexpected char '${value}' at ${index}`);
|
|
234
|
+
|
|
235
|
+
case ESCAPED_CHAR:
|
|
236
|
+
throw new TypeError(`Unexpected char '\\' at ${index}`);
|
|
237
|
+
|
|
238
|
+
case MODIFIER:
|
|
239
|
+
throw new TypeError(`Unexpected token '${value}' at ${index}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const prefixes = '-/.:';
|
|
244
|
+
|
|
245
|
+
function throwUnexpectedError() {
|
|
246
|
+
throw new TypeError('Unexpected end of input');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function* parse(tokens) {
|
|
250
|
+
let i = 0;
|
|
251
|
+
|
|
252
|
+
function get(type) {
|
|
253
|
+
const token = tokens[i];
|
|
254
|
+
|
|
255
|
+
if (!token) {
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const [nextType,, value] = token;
|
|
260
|
+
|
|
261
|
+
if (nextType !== type) {
|
|
262
|
+
return undefined;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
i++;
|
|
266
|
+
return value;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function getText() {
|
|
270
|
+
let result = '';
|
|
271
|
+
|
|
272
|
+
for (let token = tokens[i]; token; token = tokens[++i]) {
|
|
273
|
+
const [type,, value] = token;
|
|
274
|
+
|
|
275
|
+
if (CHAR === type) {
|
|
276
|
+
result += value;
|
|
277
|
+
} else if (ESCAPED_CHAR === type) {
|
|
278
|
+
result += value;
|
|
279
|
+
} else {
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return result;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const path = [];
|
|
288
|
+
|
|
289
|
+
while (i < tokens.length) {
|
|
290
|
+
const char = get(CHAR) || get(MODIFIER) || '';
|
|
291
|
+
const name = get(NAME);
|
|
292
|
+
const pattern = get(PATTERN);
|
|
293
|
+
|
|
294
|
+
if (name || pattern) {
|
|
295
|
+
let prefix = '';
|
|
296
|
+
|
|
297
|
+
if (char && prefixes.includes(char)) {
|
|
298
|
+
prefix = char;
|
|
299
|
+
} else if (char) {
|
|
300
|
+
path.push(char);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (path.length) {
|
|
304
|
+
yield path.join('');
|
|
305
|
+
path.length = 0;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const modifier = get(MODIFIER) || '';
|
|
309
|
+
yield {
|
|
310
|
+
prefix,
|
|
311
|
+
name: name || '',
|
|
312
|
+
suffix: '',
|
|
313
|
+
pattern,
|
|
314
|
+
modifier
|
|
315
|
+
};
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const value = char || get(ESCAPED_CHAR) || get(MODIFIER);
|
|
320
|
+
|
|
321
|
+
if (value) {
|
|
322
|
+
if (value !== '/') {
|
|
323
|
+
path.push(value);
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (path.length) {
|
|
328
|
+
yield path.join('');
|
|
329
|
+
path.length = 0;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
yield '/';
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (path.length) {
|
|
337
|
+
yield path.join('');
|
|
338
|
+
path.length = 0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const openToken = tokens[i++];
|
|
342
|
+
|
|
343
|
+
if (!openToken) {
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (openToken[0] !== OPEN) {
|
|
348
|
+
throwError(openToken);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const prefix = getText();
|
|
352
|
+
const groupName = get(NAME) || '';
|
|
353
|
+
const groupPattern = get(PATTERN);
|
|
354
|
+
const suffix = getText();
|
|
355
|
+
const closeToken = tokens[i++];
|
|
356
|
+
|
|
357
|
+
if (!closeToken) {
|
|
358
|
+
throwUnexpectedError();
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (closeToken[0] !== CLOSE) {
|
|
362
|
+
throwError(closeToken);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const modifier = get(MODIFIER) || '';
|
|
366
|
+
yield {
|
|
367
|
+
prefix,
|
|
368
|
+
name: groupName || '',
|
|
369
|
+
pattern: groupPattern,
|
|
370
|
+
suffix,
|
|
371
|
+
modifier,
|
|
372
|
+
group: true
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (path.length) {
|
|
377
|
+
yield path.join('');
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function isNewLine(token) {
|
|
382
|
+
if (token === '/') {
|
|
383
|
+
return true;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (typeof token !== 'string' && token.prefix === '/') {
|
|
387
|
+
return true;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const dotRegex$1 = /^\.+$/;
|
|
394
|
+
|
|
395
|
+
function valid(paragraph) {
|
|
396
|
+
if (paragraph[0] !== '/') {
|
|
397
|
+
return true;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (paragraph.length === 1) {
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (paragraph.length !== 2) {
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const [, t] = paragraph;
|
|
409
|
+
|
|
410
|
+
if (typeof t !== 'string') {
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (!dotRegex$1.test(t)) {
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function* clear(tokens) {
|
|
422
|
+
let paragraph = ['/'];
|
|
423
|
+
|
|
424
|
+
for (const token of tokens) {
|
|
425
|
+
if (isNewLine(token)) {
|
|
426
|
+
if (valid(paragraph)) {
|
|
427
|
+
yield* paragraph;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
paragraph = [];
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
paragraph.push(token);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (valid(paragraph)) {
|
|
437
|
+
yield* paragraph;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function toTokens(path) {
|
|
442
|
+
const lexTokens = [...lexer(path)];
|
|
443
|
+
const tokens = parse(lexTokens);
|
|
444
|
+
return [...clear(tokens)];
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function escapeString(str) {
|
|
448
|
+
return decodeURIComponent(str).replace(/([.+*?=^!:${}()[\]|\\])/g, '\\$1');
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function createSetFn({
|
|
452
|
+
name,
|
|
453
|
+
modifier,
|
|
454
|
+
suffix,
|
|
455
|
+
prefix
|
|
456
|
+
}) {
|
|
457
|
+
if (!['*', '+'].includes(modifier) || !prefix && !suffix) {
|
|
458
|
+
if (typeof name === 'number') {
|
|
459
|
+
return (p, s, k) => p[name + k] = decodeURIComponent(s);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
return (p, s) => p[name] = decodeURIComponent(s);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const split = prefix + suffix;
|
|
466
|
+
|
|
467
|
+
if (typeof name === 'number') {
|
|
468
|
+
return (p, s, k) => {
|
|
469
|
+
p[name + k] = s.split(split).map(value => decodeURIComponent(value));
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return (p, s) => {
|
|
474
|
+
p[name] = s.split(split).map(value => decodeURIComponent(value));
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const defaultPattern = '[^/]+?';
|
|
479
|
+
|
|
480
|
+
function tokenToFragment(token, setFns) {
|
|
481
|
+
if (typeof token === 'string') {
|
|
482
|
+
return escapeString(token);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const prefix = escapeString(token.prefix);
|
|
486
|
+
const suffix = escapeString(token.suffix);
|
|
487
|
+
const {
|
|
488
|
+
name,
|
|
489
|
+
modifier
|
|
490
|
+
} = token;
|
|
491
|
+
|
|
492
|
+
if (name === '') {
|
|
493
|
+
return `(?:${prefix}${suffix})${modifier}`;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
setFns.push(createSetFn(token));
|
|
497
|
+
const pattern = token.pattern || defaultPattern;
|
|
498
|
+
|
|
499
|
+
if (!prefix && !suffix) {
|
|
500
|
+
return `((?:${pattern})${modifier})`;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (modifier === '?') {
|
|
504
|
+
return `(?:${prefix}(${pattern})${suffix})?`;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if (modifier === '+') {
|
|
508
|
+
return `${prefix}(${pattern}(?:${suffix}${prefix}${pattern})*)${suffix}`;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (modifier === '*') {
|
|
512
|
+
return `(?:${prefix}(${pattern}(?:${suffix}${prefix}${pattern})*)${suffix})?`;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return `${prefix}(${pattern})${suffix}`;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
function tokensToRegex(paramsSetters, tokens, end) {
|
|
519
|
+
const tokenRegex = tokens.map(t => tokenToFragment(t, paramsSetters));
|
|
520
|
+
tokenRegex.unshift('^');
|
|
521
|
+
tokenRegex.push(end ? '$' : '(?=/|$)');
|
|
522
|
+
return new RegExp(tokenRegex.join(''), 'i');
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function setParams(paramsSetters, regexExecArray, key, path) {
|
|
526
|
+
const params = Object.create(null);
|
|
527
|
+
|
|
528
|
+
for (let i = 1; i < regexExecArray.length; i++) {
|
|
529
|
+
const v = regexExecArray[i];
|
|
530
|
+
|
|
531
|
+
if (v === undefined) {
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const fn = paramsSetters[i];
|
|
536
|
+
|
|
537
|
+
if (!fn) {
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
fn(params, v, key);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
params.$path = path;
|
|
545
|
+
return params;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function rootMatch(paramsSetters, re, path) {
|
|
549
|
+
const res = re.exec(path);
|
|
550
|
+
|
|
551
|
+
if (!res) {
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return setParams(paramsSetters, res, 0, res[0]);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function backMatch(paramsSetters, re, path, parent, key = 0) {
|
|
559
|
+
const res = re.exec(path.substring(parent.length));
|
|
560
|
+
|
|
561
|
+
if (!res) {
|
|
562
|
+
return null;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
return setParams(paramsSetters, res, key, `${parent}${res[0]}`);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
function parentMatch(paramsSetters, re, depth, path, parentPath, key = 0) {
|
|
569
|
+
const paths = parentPath.split('/').filter(Boolean);
|
|
570
|
+
|
|
571
|
+
if (depth >= paths.length) {
|
|
572
|
+
return rootMatch(paramsSetters, re, path);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
const basePath = `/${paths.splice(0, paths.length - depth).join('/')}`;
|
|
576
|
+
return backMatch(paramsSetters, re, path, basePath, key);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
function appendMatch(paramsSetters, re, path, parent, key = 0) {
|
|
580
|
+
if (parent[parent.length - 1] === '/') {
|
|
581
|
+
parent = parent.substring(0, parent.length - 1);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
return backMatch(paramsSetters, re, path, parent, key);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
function setKey(tokens) {
|
|
588
|
+
let key = 0;
|
|
589
|
+
|
|
590
|
+
for (const token of tokens) {
|
|
591
|
+
if (typeof token === 'string') {
|
|
592
|
+
continue;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (token.name) {
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
if (!token.pattern) {
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
token.name = key++;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
return key;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const regex$1 = /^(\.+)\/+/;
|
|
610
|
+
function createMatch(path, end) {
|
|
611
|
+
if (!path || path === '*') {
|
|
612
|
+
const match = (_, parent) => ({
|
|
613
|
+
$path: parent
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
match.keyLen = 0;
|
|
617
|
+
return match;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if (path === '.') {
|
|
621
|
+
const match = (path, parent) => {
|
|
622
|
+
if (parent[parent.length - 1] === '/') {
|
|
623
|
+
parent = parent.substring(0, parent.length - 1);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
const char = path[parent.length];
|
|
627
|
+
|
|
628
|
+
if (char && (char !== '/' || end && path.length - 1 > parent.length)) {
|
|
629
|
+
return null;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
const params = Object.create(null);
|
|
633
|
+
params.$path = `${parent}${char}`;
|
|
634
|
+
return params;
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
match.keyLen = 0;
|
|
638
|
+
return match;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
const isRoot = path[0] === '/';
|
|
642
|
+
let depth = 0;
|
|
643
|
+
|
|
644
|
+
for (let s = regex$1.exec(path); s; s = regex$1.exec(path)) {
|
|
645
|
+
const [{
|
|
646
|
+
length
|
|
647
|
+
}, {
|
|
648
|
+
length: len
|
|
649
|
+
}] = s;
|
|
650
|
+
path = path.substring(length);
|
|
651
|
+
depth += len - 1;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (depth) {
|
|
655
|
+
path = `/${path}`;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
const tokens = toTokens(path);
|
|
659
|
+
const key = setKey(tokens);
|
|
660
|
+
const paramsSetters = [() => {}];
|
|
661
|
+
const re = tokensToRegex(paramsSetters, tokens, end);
|
|
662
|
+
|
|
663
|
+
if (isRoot) {
|
|
664
|
+
const match = path => rootMatch(paramsSetters, re, path);
|
|
665
|
+
|
|
666
|
+
match.keyLen = key;
|
|
667
|
+
match.isRoot = true;
|
|
668
|
+
return match;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
if (depth) {
|
|
672
|
+
const match = (...p) => parentMatch(paramsSetters, re, depth, ...p);
|
|
673
|
+
|
|
674
|
+
match.keyLen = key;
|
|
675
|
+
return match;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
const match = (...p) => appendMatch(paramsSetters, re, ...p);
|
|
679
|
+
|
|
680
|
+
match.keyLen = key;
|
|
681
|
+
return match;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
function getMethods(methods) {
|
|
685
|
+
if (typeof methods === 'string') {
|
|
686
|
+
return [methods];
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
if (Array.isArray(methods)) {
|
|
690
|
+
return methods;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
return ['GET', 'POST', 'PUT', 'DELETE'];
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
function verb(routes, path, handle, options = {}) {
|
|
697
|
+
const methods = getMethods(options.methods || handle[methodsSymbol]);
|
|
698
|
+
|
|
699
|
+
if (!methods.length) {
|
|
700
|
+
return null;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const {
|
|
704
|
+
controller,
|
|
705
|
+
test = handle[testSymbol],
|
|
706
|
+
plugin = '',
|
|
707
|
+
root = '',
|
|
708
|
+
absPath = '',
|
|
709
|
+
filePath = '',
|
|
710
|
+
name = handle.name
|
|
711
|
+
} = options;
|
|
712
|
+
const route = {
|
|
713
|
+
controller,
|
|
714
|
+
root,
|
|
715
|
+
absPath,
|
|
716
|
+
filePath,
|
|
717
|
+
handle,
|
|
718
|
+
plugin,
|
|
719
|
+
path: path.replace(/(.)\/+$/, '$1').replace(/\/+/g, '/'),
|
|
720
|
+
methods,
|
|
721
|
+
test,
|
|
722
|
+
name,
|
|
723
|
+
match: createMatch(path, true)
|
|
724
|
+
};
|
|
725
|
+
routes.push(route);
|
|
726
|
+
return route;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/** 方法列表 */
|
|
730
|
+
|
|
731
|
+
const methods = new Set(['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS']);
|
|
732
|
+
|
|
733
|
+
function setHandles(routes, path, handles, opt, name = '') {
|
|
734
|
+
for (const method of methods) {
|
|
735
|
+
const fn = handles[method];
|
|
736
|
+
|
|
737
|
+
if (typeof fn !== 'function') {
|
|
738
|
+
continue;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
verb(routes, path, fn, { ...opt,
|
|
742
|
+
test: fn[testSymbol] || handles[testSymbol],
|
|
743
|
+
methods: [method],
|
|
744
|
+
name: name || method
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
function setHandle(routes, path, item, opt, name = '') {
|
|
750
|
+
const options = { ...opt
|
|
751
|
+
};
|
|
752
|
+
delete options.test;
|
|
753
|
+
delete options.methods;
|
|
754
|
+
const route = verb(routes, path, item, { ...options,
|
|
755
|
+
name
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
if (!route) {
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
if (route.methods.includes('OPTIONS')) {
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
let {
|
|
767
|
+
controller,
|
|
768
|
+
test,
|
|
769
|
+
plugin = '',
|
|
770
|
+
root = '',
|
|
771
|
+
absPath = '',
|
|
772
|
+
filePath = ''
|
|
773
|
+
} = opt || {};
|
|
774
|
+
path = path.replace(/(.)\/+$/, '$1').replace(/\/+/g, '/');
|
|
775
|
+
routes.push({
|
|
776
|
+
controller,
|
|
777
|
+
root,
|
|
778
|
+
absPath,
|
|
779
|
+
filePath,
|
|
780
|
+
handle: optionsSymbol,
|
|
781
|
+
plugin,
|
|
782
|
+
path,
|
|
783
|
+
methods: ['OPTIONS'],
|
|
784
|
+
test,
|
|
785
|
+
name: `${name}:OPTIONS`,
|
|
786
|
+
match: createMatch(path, true)
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
function setHandleItem(routes, path, item, opt, name = '') {
|
|
791
|
+
if (!item) {
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
if (typeof item === 'object') {
|
|
796
|
+
setHandles(routes, path, item, opt, name);
|
|
797
|
+
} else if (typeof item === 'function') {
|
|
798
|
+
setHandle(routes, path, item, opt, name);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
function initOptions(routes, exports, {
|
|
803
|
+
controller,
|
|
804
|
+
plugin,
|
|
805
|
+
root,
|
|
806
|
+
filePath,
|
|
807
|
+
absPath
|
|
808
|
+
} = {}) {
|
|
809
|
+
// 公共选项
|
|
810
|
+
const options = {
|
|
811
|
+
controller: exports.Controller || controller,
|
|
812
|
+
plugin,
|
|
813
|
+
root,
|
|
814
|
+
filePath,
|
|
815
|
+
absPath
|
|
816
|
+
}; // 将自身添加到路由
|
|
817
|
+
|
|
818
|
+
setHandleItem(routes, '', exports, options);
|
|
819
|
+
return options;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/** 资源的处理函数配置 */
|
|
823
|
+
|
|
824
|
+
const resourceHandleMap = {
|
|
825
|
+
index: {
|
|
826
|
+
methods: ['GET'],
|
|
827
|
+
path: ''
|
|
828
|
+
},
|
|
829
|
+
create: {
|
|
830
|
+
methods: ['POST'],
|
|
831
|
+
path: ''
|
|
832
|
+
},
|
|
833
|
+
new: {
|
|
834
|
+
methods: ['GET'],
|
|
835
|
+
path: 'new'
|
|
836
|
+
},
|
|
837
|
+
show: {
|
|
838
|
+
methods: ['GET'],
|
|
839
|
+
path: ':id'
|
|
840
|
+
},
|
|
841
|
+
update: {
|
|
842
|
+
methods: ['PUT'],
|
|
843
|
+
path: ':id'
|
|
844
|
+
},
|
|
845
|
+
destroy: {
|
|
846
|
+
methods: ['DELETE'],
|
|
847
|
+
path: ':id'
|
|
848
|
+
}
|
|
849
|
+
};
|
|
850
|
+
function setResource(routes, exports, options) {
|
|
851
|
+
options = initOptions(routes, exports, options);
|
|
852
|
+
|
|
853
|
+
for (const k in exports) {
|
|
854
|
+
const item = exports[k];
|
|
855
|
+
|
|
856
|
+
if (!item) {
|
|
857
|
+
continue;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
if (!/^[a-z0-9][a-z0-9A-Z_-]*$/.test(k)) {
|
|
861
|
+
continue;
|
|
862
|
+
} // 特定处理处理函数
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
if (typeof item === 'function' && k in resourceHandleMap) {
|
|
866
|
+
const info = resourceHandleMap[k];
|
|
867
|
+
verb(routes, info.path, item, { ...options,
|
|
868
|
+
test: item[testSymbol],
|
|
869
|
+
methods: info.methods,
|
|
870
|
+
name: k
|
|
871
|
+
});
|
|
872
|
+
continue;
|
|
873
|
+
} // 成员处理函数
|
|
874
|
+
|
|
875
|
+
|
|
876
|
+
setHandleItem(routes, `:id/${k}`, item, options, k);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
/**
|
|
881
|
+
* 处理器
|
|
882
|
+
*/
|
|
883
|
+
|
|
884
|
+
class Controller {
|
|
885
|
+
static isControllerConstructor(v) {
|
|
886
|
+
if (v === Controller) {
|
|
887
|
+
return true;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
if (typeof v !== 'function') {
|
|
891
|
+
return false;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
return Controller.isPrototypeOf(v);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
/**
|
|
898
|
+
* @warning 不要重载构造函数或者主动调用创建实例
|
|
899
|
+
*/
|
|
900
|
+
constructor(context) {
|
|
901
|
+
this.context = context;
|
|
902
|
+
Object.defineProperties(this, Object.getOwnPropertyDescriptors(context));
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* 初始化
|
|
906
|
+
* @description 如果有初始化操作,应当在 init 中实现
|
|
907
|
+
* @description 此方法由路由调用
|
|
908
|
+
*/
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
[initSymbol]() {}
|
|
912
|
+
/** 处理函数的第一个参数 */
|
|
913
|
+
|
|
914
|
+
|
|
915
|
+
[dataSymbol]() {
|
|
916
|
+
const data = { ...this.query
|
|
917
|
+
};
|
|
918
|
+
const {
|
|
919
|
+
body
|
|
920
|
+
} = this;
|
|
921
|
+
|
|
922
|
+
if (body && typeof body === 'object') {
|
|
923
|
+
Object.assign(data, body);
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
Object.assign(data, this.params);
|
|
927
|
+
return data;
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* OPTIONS 的默认处理函数
|
|
931
|
+
* @description 如果需要,则需要在此函数中实现
|
|
932
|
+
* @description 当已 OPTIONS 方法请求资源,且资源对应的路径中没有定义 OPTIONS 方法处理是的处理函数
|
|
933
|
+
*/
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
[optionsSymbol]() {}
|
|
937
|
+
/**
|
|
938
|
+
* 对处理函数的结果进行处理
|
|
939
|
+
* @description 如果需要自定义处理,需要重载此方法
|
|
940
|
+
* @description 此方法由路由调用
|
|
941
|
+
* @param result 处理函数的结果
|
|
942
|
+
*/
|
|
943
|
+
|
|
944
|
+
|
|
945
|
+
[returnSymbol](result) {
|
|
946
|
+
return this.write(result).then(e => {
|
|
947
|
+
if (e) {
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
if (typeof result !== 'object') {
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
this.responseType = 'application/json';
|
|
956
|
+
return this.write(JSON.stringify(result));
|
|
957
|
+
}).then(() => {});
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* 处理完成后,实例销毁前,如果有错误未被处理,将回交由此参数处理
|
|
961
|
+
* @description 如果需要自定义处理,需要重载此方法
|
|
962
|
+
* @description 此方法由路由调用
|
|
963
|
+
*/
|
|
964
|
+
|
|
965
|
+
|
|
966
|
+
[catchSymbol](e) {
|
|
967
|
+
return this.logs.error(e).then(() => {});
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* 处理完成后,实例即将销毁时的处理函数
|
|
971
|
+
* @description 如果有销毁操作,应当在 finally 中通过实现
|
|
972
|
+
* @description 此方法由 destroy 调用
|
|
973
|
+
*/
|
|
974
|
+
|
|
975
|
+
|
|
976
|
+
[finallySymbol]() {}
|
|
977
|
+
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
(function (_Controller) {})(Controller || (Controller = {}));
|
|
981
|
+
|
|
982
|
+
var Controller$1 = Controller;
|
|
983
|
+
|
|
984
|
+
function setControllerResource(routes, controller, {
|
|
985
|
+
plugin = '',
|
|
986
|
+
root = '',
|
|
987
|
+
absPath = '',
|
|
988
|
+
filePath = ''
|
|
989
|
+
} = {}) {
|
|
990
|
+
const {
|
|
991
|
+
prototype
|
|
992
|
+
} = controller;
|
|
993
|
+
|
|
994
|
+
for (const k in prototype) {
|
|
995
|
+
if (typeof prototype[k] !== 'function') {
|
|
996
|
+
continue;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
if (!/^[a-z0-9][a-z0-9A-Z_-]*$/.test(k)) {
|
|
1000
|
+
continue;
|
|
1001
|
+
} // 特定处理处理函数
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
let path = k.replace(/(.)\/+$/, '$1').replace(/\/+/g, '/');
|
|
1005
|
+
let methods = ['GET', 'POST', 'PUT', 'DELETE'];
|
|
1006
|
+
|
|
1007
|
+
if (k in resourceHandleMap) {
|
|
1008
|
+
const info = resourceHandleMap[k];
|
|
1009
|
+
path = info.path ? `${info.path}` : '';
|
|
1010
|
+
({
|
|
1011
|
+
methods
|
|
1012
|
+
} = info);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
routes.push({
|
|
1016
|
+
controller,
|
|
1017
|
+
root,
|
|
1018
|
+
absPath,
|
|
1019
|
+
filePath,
|
|
1020
|
+
handle: k,
|
|
1021
|
+
plugin,
|
|
1022
|
+
path,
|
|
1023
|
+
methods,
|
|
1024
|
+
name: k,
|
|
1025
|
+
match: createMatch(path, true)
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
class Router {
|
|
1031
|
+
/** 路由列表 */
|
|
1032
|
+
constructor(path = '') {
|
|
1033
|
+
_defineProperty(this, "disabled", false);
|
|
1034
|
+
|
|
1035
|
+
_defineProperty(this, "__routes", []);
|
|
1036
|
+
|
|
1037
|
+
_defineProperty(this, "guards", new Set());
|
|
1038
|
+
|
|
1039
|
+
path = path.replace(/(.)\/+$/, '$1').replace(/\/+/g, '/');
|
|
1040
|
+
this.path = path;
|
|
1041
|
+
this.match = createMatch(path, false);
|
|
1042
|
+
}
|
|
1043
|
+
/** 子路由 */
|
|
1044
|
+
|
|
1045
|
+
|
|
1046
|
+
route(path) {
|
|
1047
|
+
const router = path instanceof Router ? path : new Router(path);
|
|
1048
|
+
|
|
1049
|
+
this.__routes.push(router);
|
|
1050
|
+
|
|
1051
|
+
return router;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
verb(path, handle, methods, options) {
|
|
1055
|
+
if (typeof handle !== 'function') {
|
|
1056
|
+
return this;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
if (typeof methods === 'string') {
|
|
1060
|
+
verb(this.__routes, path, handle, { ...options,
|
|
1061
|
+
methods: [methods]
|
|
1062
|
+
});
|
|
1063
|
+
} else if (Array.isArray(methods)) {
|
|
1064
|
+
verb(this.__routes, path, handle, { ...options,
|
|
1065
|
+
methods
|
|
1066
|
+
});
|
|
1067
|
+
} else {
|
|
1068
|
+
verb(this.__routes, path, handle, methods);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
return this;
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* 注册 HTTP GET 处理函数
|
|
1075
|
+
* @param path 要注册的路径
|
|
1076
|
+
* @param handle 要注册的处理函数
|
|
1077
|
+
* @param options 选项
|
|
1078
|
+
*/
|
|
1079
|
+
|
|
1080
|
+
|
|
1081
|
+
get(path, handle, options) {
|
|
1082
|
+
if (typeof handle !== 'function') {
|
|
1083
|
+
return this;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
verb(this.__routes, path, handle, { ...options,
|
|
1087
|
+
methods: ['GET']
|
|
1088
|
+
});
|
|
1089
|
+
return this;
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* 注册 HTTP POST 处理函数
|
|
1093
|
+
* @param path 要注册的路径
|
|
1094
|
+
* @param handle 要注册的处理函数
|
|
1095
|
+
* @param options 选项
|
|
1096
|
+
*/
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
post(path, handle, options) {
|
|
1100
|
+
if (typeof handle !== 'function') {
|
|
1101
|
+
return this;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
verb(this.__routes, path, handle, { ...options,
|
|
1105
|
+
methods: ['POST']
|
|
1106
|
+
});
|
|
1107
|
+
return this;
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* 注册 HTTP PUT 处理函数
|
|
1111
|
+
* @param path 要注册的路径
|
|
1112
|
+
* @param handle 要注册的处理函数
|
|
1113
|
+
* @param options 选项
|
|
1114
|
+
*/
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
put(path, handle, options) {
|
|
1118
|
+
if (typeof handle !== 'function') {
|
|
1119
|
+
return this;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
verb(this.__routes, path, handle, { ...options,
|
|
1123
|
+
methods: ['PUT']
|
|
1124
|
+
});
|
|
1125
|
+
return this;
|
|
1126
|
+
}
|
|
1127
|
+
/**
|
|
1128
|
+
* 注册 HTTP DELETE 处理函数
|
|
1129
|
+
* @param path 要注册的路径
|
|
1130
|
+
* @param handle 要注册的处理函数
|
|
1131
|
+
* @param options 选项
|
|
1132
|
+
*/
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
delete(path, handle, options) {
|
|
1136
|
+
if (typeof handle !== 'function') {
|
|
1137
|
+
return this;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
verb(this.__routes, path, handle, { ...options,
|
|
1141
|
+
methods: ['DELETE']
|
|
1142
|
+
});
|
|
1143
|
+
return this;
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* 注册 HTTP HEAD 处理函数
|
|
1147
|
+
* @param path 要注册的路径
|
|
1148
|
+
* @param handle 要注册的处理函数
|
|
1149
|
+
* @param options 选项
|
|
1150
|
+
*/
|
|
1151
|
+
|
|
1152
|
+
|
|
1153
|
+
head(path, handle, options) {
|
|
1154
|
+
if (typeof handle !== 'function') {
|
|
1155
|
+
return this;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
verb(this.__routes, path, handle, { ...options,
|
|
1159
|
+
methods: ['HEAD']
|
|
1160
|
+
});
|
|
1161
|
+
return this;
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* 注册 HTTP OPTIONS 处理函数
|
|
1165
|
+
* @param path 要注册的路径
|
|
1166
|
+
* @param handle 要注册的处理函数
|
|
1167
|
+
* @param options 选项
|
|
1168
|
+
*/
|
|
1169
|
+
|
|
1170
|
+
|
|
1171
|
+
options(path, handle, options) {
|
|
1172
|
+
if (typeof handle !== 'function') {
|
|
1173
|
+
return this;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
verb(this.__routes, path, handle, { ...options,
|
|
1177
|
+
methods: ['OPTIONS']
|
|
1178
|
+
});
|
|
1179
|
+
return this;
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* 注册 HTTP 资源
|
|
1183
|
+
* @param exports 要注册的资源
|
|
1184
|
+
* @param options 选项
|
|
1185
|
+
*/
|
|
1186
|
+
|
|
1187
|
+
|
|
1188
|
+
resource(exports, options) {
|
|
1189
|
+
setResource(this.__routes, exports, options);
|
|
1190
|
+
return this;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
register(exports, options) {
|
|
1194
|
+
if (Controller$1.isControllerConstructor(exports)) {
|
|
1195
|
+
setControllerResource(this.__routes, exports, options);
|
|
1196
|
+
return this;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
if (Controller$1.isControllerConstructor(exports.default)) {
|
|
1200
|
+
setControllerResource(this.__routes, exports.default, options);
|
|
1201
|
+
return this;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
setResource(this.__routes, exports, options);
|
|
1205
|
+
return this;
|
|
1206
|
+
}
|
|
1207
|
+
/**
|
|
1208
|
+
* 注册 HTTP 处理函数集
|
|
1209
|
+
* @param exports 要注册的处理函数集
|
|
1210
|
+
* @param options 选项
|
|
1211
|
+
*/
|
|
1212
|
+
|
|
1213
|
+
|
|
1214
|
+
collection(exports, options) {
|
|
1215
|
+
options = initOptions(this.__routes, exports, options);
|
|
1216
|
+
|
|
1217
|
+
for (const k in exports) {
|
|
1218
|
+
if (!/^[a-z0-9][a-z0-9A-Z_-]*$/.test(k)) {
|
|
1219
|
+
continue;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
setHandleItem(this.__routes, k, exports[k], options, k);
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
return this;
|
|
1226
|
+
}
|
|
1227
|
+
/**
|
|
1228
|
+
* 注册 HTTP 资源成员处理函数集
|
|
1229
|
+
* @param exports 要注册的处理函数集
|
|
1230
|
+
* @param options 选项
|
|
1231
|
+
*/
|
|
1232
|
+
|
|
1233
|
+
|
|
1234
|
+
member(exports, options) {
|
|
1235
|
+
options = initOptions(this.__routes, exports, options);
|
|
1236
|
+
|
|
1237
|
+
for (const k in exports) {
|
|
1238
|
+
if (!/^[a-z0-9][a-z0-9A-Z_-]*$/.test(k)) {
|
|
1239
|
+
continue;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
setHandleItem(this.__routes, `:id/${k}`, exports[k], options);
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
return this;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
/**
|
|
1251
|
+
* 路由卫士
|
|
1252
|
+
* @description 用于路由的过滤及处理函数执行前的预处理
|
|
1253
|
+
*/
|
|
1254
|
+
class Guard extends Service$1 {
|
|
1255
|
+
decide() {
|
|
1256
|
+
return true;
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* 测试请求是否允许通过此路由访问
|
|
1260
|
+
* @description 同一请求、同一路径下,在此函数中调用的 this.set、this.get、this.delete、this.has、this.keys、this.clear 等方法的数据与实例初始化后的共享。目前不同路径下暂不共享,后续可能会被设计为共享,但不同请求下必然不共享
|
|
1261
|
+
* @description 同一路径下,若存在任意 test 返回 false 均会使得此路径不会被执行
|
|
1262
|
+
* @param param 请求参数
|
|
1263
|
+
*/
|
|
1264
|
+
|
|
1265
|
+
|
|
1266
|
+
static async test(param) {
|
|
1267
|
+
return true;
|
|
1268
|
+
}
|
|
1269
|
+
/**
|
|
1270
|
+
* @description 映射的 Map 实例的 set 方法,与同一请求同一路径下的 test 共享同一 Map 实例,此方法会在其他地方重载,常规方式重载无效
|
|
1271
|
+
*/
|
|
1272
|
+
|
|
1273
|
+
|
|
1274
|
+
set(k, v) {
|
|
1275
|
+
return this;
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* @description 映射的 Map 实例的 get 方法,与同一请求同一路径下的 test 共享同一 Map 实例,此方法会在其他地方重载,常规方式重载无效
|
|
1279
|
+
*/
|
|
1280
|
+
|
|
1281
|
+
|
|
1282
|
+
get(k) {
|
|
1283
|
+
return undefined;
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* @description 映射的 Map 实例的 delete 方法,与同一请求同一路径下的 test 共享同一 Map 实例,此方法会在其他地方重载,常规方式重载无效
|
|
1287
|
+
*/
|
|
1288
|
+
|
|
1289
|
+
|
|
1290
|
+
delete(k) {
|
|
1291
|
+
return false;
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* @description 映射的 Map 实例的 has 方法,与同一请求同一路径下的 test 共享同一 Map 实例,此方法会在其他地方重载,常规方式重载无效
|
|
1295
|
+
*/
|
|
1296
|
+
|
|
1297
|
+
|
|
1298
|
+
has(k) {
|
|
1299
|
+
return false;
|
|
1300
|
+
}
|
|
1301
|
+
/**
|
|
1302
|
+
* @description 映射的 Map 实例的 keys 方法,与同一请求同一路径下的 test 共享同一 Map 实例,此方法会在其他地方重载,常规方式重载无效
|
|
1303
|
+
*/
|
|
1304
|
+
|
|
1305
|
+
|
|
1306
|
+
*keys() {}
|
|
1307
|
+
/**
|
|
1308
|
+
* @description 映射的 Map 实例的 clear 方法,与同一请求同一路径下的 test 共享同一 Map 实例,此方法会在其他地方重载,常规方式重载无效
|
|
1309
|
+
*/
|
|
1310
|
+
|
|
1311
|
+
|
|
1312
|
+
clear() {}
|
|
1313
|
+
/**
|
|
1314
|
+
* @description 映射的 Map 实例的 size 属性,与同一请求同一路径下的 test 共享同一 Map 实例,此方法会在其他地方重载,常规方式重载无效
|
|
1315
|
+
*/
|
|
1316
|
+
|
|
1317
|
+
|
|
1318
|
+
get size() {
|
|
1319
|
+
return 0;
|
|
1320
|
+
}
|
|
1321
|
+
/**
|
|
1322
|
+
* @description 映射的 Map 实例的 set 方法,与同一请求同一路径下的 Guard 实例共享同一 Map 实例,此方法会在其他地方重载,常规方式重载无效
|
|
1323
|
+
*/
|
|
1324
|
+
|
|
1325
|
+
|
|
1326
|
+
static set(k, v) {
|
|
1327
|
+
return this;
|
|
1328
|
+
}
|
|
1329
|
+
/**
|
|
1330
|
+
* @description 映射的 Map 实例的 get 方法,与同一请求同一路径下的 Guard 实例共享同一 Map 实例,此方法会在其他地方重载,常规方式重载无效
|
|
1331
|
+
*/
|
|
1332
|
+
|
|
1333
|
+
|
|
1334
|
+
static get(k) {
|
|
1335
|
+
return undefined;
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* @description 映射的 Map 实例的 delete 方法,与同一请求同一路径下的 Guard 实例共享同一 Map 实例,此方法会在其他地方重载,常规方式重载无效
|
|
1339
|
+
*/
|
|
1340
|
+
|
|
1341
|
+
|
|
1342
|
+
static delete(k) {
|
|
1343
|
+
return false;
|
|
1344
|
+
}
|
|
1345
|
+
/**
|
|
1346
|
+
* @description 映射的 Map 实例的 has 方法,与同一请求同一路径下的 Guard 实例共享同一 Map 实例,此方法会在其他地方重载,常规方式重载无效
|
|
1347
|
+
*/
|
|
1348
|
+
|
|
1349
|
+
|
|
1350
|
+
static has(k) {
|
|
1351
|
+
return false;
|
|
1352
|
+
}
|
|
1353
|
+
/**
|
|
1354
|
+
* @description 映射的 Map 实例的 keys 方法,与同一请求同一路径下的 Guard 实例共享同一 Map 实例,此方法会在其他地方重载,常规方式重载无效
|
|
1355
|
+
*/
|
|
1356
|
+
|
|
1357
|
+
|
|
1358
|
+
static *keys() {}
|
|
1359
|
+
/**
|
|
1360
|
+
* @description 映射的 Map 实例的 clear 方法,与同一请求同一路径下的 Guard 实例共享同一 Map 实例,此方法会在其他地方重载,常规方式重载无效
|
|
1361
|
+
*/
|
|
1362
|
+
|
|
1363
|
+
|
|
1364
|
+
static clear() {}
|
|
1365
|
+
/**
|
|
1366
|
+
* @description 映射的 Map 实例的 size 属性,与同一请求同一路径下的 Guard 实例共享同一 Map 实例,此方法会在其他地方重载,常规方式重载无效
|
|
1367
|
+
*/
|
|
1368
|
+
|
|
1369
|
+
|
|
1370
|
+
static get size() {
|
|
1371
|
+
return 0;
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
(function (_Guard) {})(Guard || (Guard = {}));
|
|
1377
|
+
|
|
1378
|
+
var Guard$1 = Guard;
|
|
1379
|
+
|
|
1380
|
+
class ExitSignal extends Error {
|
|
1381
|
+
/**
|
|
1382
|
+
* 忽略对退出信号的捕获
|
|
1383
|
+
* @description 用于 try { } catch(e) {} 的 catch 中忽略退出信号
|
|
1384
|
+
* @example
|
|
1385
|
+
* try {
|
|
1386
|
+
* doSomething();
|
|
1387
|
+
* } catch (e) {
|
|
1388
|
+
* ExitSignal.assert(e);
|
|
1389
|
+
* customProcess(e);
|
|
1390
|
+
* }
|
|
1391
|
+
*/
|
|
1392
|
+
static assert(v) {
|
|
1393
|
+
if (v instanceof ExitSignal) {
|
|
1394
|
+
throw v;
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
class Plugin {
|
|
1401
|
+
/** 包名 */
|
|
1402
|
+
|
|
1403
|
+
/** 版本 */
|
|
1404
|
+
|
|
1405
|
+
/** 作者 */
|
|
1406
|
+
|
|
1407
|
+
/** 开源协议 */
|
|
1408
|
+
constructor(name,
|
|
1409
|
+
/** 版本 */
|
|
1410
|
+
version, {
|
|
1411
|
+
author,
|
|
1412
|
+
license
|
|
1413
|
+
} = {}) {
|
|
1414
|
+
this.name = name;
|
|
1415
|
+
this.version = typeof version === 'string' ? version : '';
|
|
1416
|
+
this.author = typeof author === 'string' ? author : '';
|
|
1417
|
+
this.license = typeof license === 'string' ? license : '';
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
_initRouter(router) {}
|
|
1421
|
+
|
|
1422
|
+
initRouter() {
|
|
1423
|
+
if (this.__initRouterPromise) {
|
|
1424
|
+
return this.__initRouterPromise;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
const {
|
|
1428
|
+
router
|
|
1429
|
+
} = this;
|
|
1430
|
+
return this.__initRouterPromise = Promise.resolve().then(() => this._initRouter(router)).then(() => router);
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
get router() {
|
|
1434
|
+
const router = new Router();
|
|
1435
|
+
Reflect.defineProperty(this, 'router', {
|
|
1436
|
+
value: router,
|
|
1437
|
+
configurable: true
|
|
1438
|
+
});
|
|
1439
|
+
this.initRouter();
|
|
1440
|
+
return router;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
get disabled() {
|
|
1444
|
+
return this.router.disabled;
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
set disabled(t) {
|
|
1448
|
+
this.router.disabled = t;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
function relateMap(obj, maps, key) {
|
|
1454
|
+
let map = maps.get(key);
|
|
1455
|
+
|
|
1456
|
+
if (!map) {
|
|
1457
|
+
map = new Map();
|
|
1458
|
+
maps.set(key, map);
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
Object.defineProperties(obj, {
|
|
1462
|
+
set: {
|
|
1463
|
+
configurable: true,
|
|
1464
|
+
|
|
1465
|
+
value(k, v) {
|
|
1466
|
+
map.set(k, v);
|
|
1467
|
+
return this;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
},
|
|
1471
|
+
get: {
|
|
1472
|
+
configurable: true,
|
|
1473
|
+
value: k => map.get(k)
|
|
1474
|
+
},
|
|
1475
|
+
delete: {
|
|
1476
|
+
configurable: true,
|
|
1477
|
+
value: k => map.delete(k)
|
|
1478
|
+
},
|
|
1479
|
+
has: {
|
|
1480
|
+
configurable: true,
|
|
1481
|
+
value: k => map.has(k)
|
|
1482
|
+
},
|
|
1483
|
+
keys: {
|
|
1484
|
+
configurable: true,
|
|
1485
|
+
value: () => map.keys()
|
|
1486
|
+
},
|
|
1487
|
+
clear: {
|
|
1488
|
+
configurable: true,
|
|
1489
|
+
value: () => map.clear()
|
|
1490
|
+
},
|
|
1491
|
+
size: {
|
|
1492
|
+
configurable: true,
|
|
1493
|
+
get: () => map.size
|
|
1494
|
+
}
|
|
1495
|
+
});
|
|
1496
|
+
return obj;
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
async function preprocess(guards, data, params) {
|
|
1500
|
+
for (let p of guards) {
|
|
1501
|
+
const pClass = relateMap(Object.create(p), data, p);
|
|
1502
|
+
|
|
1503
|
+
try {
|
|
1504
|
+
if (!(await pClass.test(params))) {
|
|
1505
|
+
return false;
|
|
1506
|
+
}
|
|
1507
|
+
} catch {
|
|
1508
|
+
return false;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
return true;
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
function methodVerify(methods, method) {
|
|
1516
|
+
if (!methods.length) {
|
|
1517
|
+
return true;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
if (methods.includes(method)) {
|
|
1521
|
+
return true;
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
return false;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
async function runTest({
|
|
1528
|
+
test
|
|
1529
|
+
}, params) {
|
|
1530
|
+
if (typeof test !== 'function') {
|
|
1531
|
+
return true;
|
|
1532
|
+
} // 有效性验证
|
|
1533
|
+
|
|
1534
|
+
|
|
1535
|
+
try {
|
|
1536
|
+
return await test(params);
|
|
1537
|
+
} catch {
|
|
1538
|
+
return false;
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
async function matchRoute(route, method, path, baseParams, parentPath, key) {
|
|
1543
|
+
if (!methodVerify(route.methods, method)) {
|
|
1544
|
+
return null;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
const {
|
|
1548
|
+
match
|
|
1549
|
+
} = route;
|
|
1550
|
+
const result = match(path, parentPath, key);
|
|
1551
|
+
|
|
1552
|
+
if (!result) {
|
|
1553
|
+
return null;
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
const params = match.isRoot ? result : { ...baseParams,
|
|
1557
|
+
...result
|
|
1558
|
+
};
|
|
1559
|
+
|
|
1560
|
+
if (false === (await runTest(route, params))) {
|
|
1561
|
+
return null;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
return params;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
async function find(router, method, path, throughData, baseParams, routers, parentPath, key) {
|
|
1568
|
+
if (router.disabled) {
|
|
1569
|
+
return null;
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
const {
|
|
1573
|
+
match
|
|
1574
|
+
} = router;
|
|
1575
|
+
const result = match(path, parentPath, key);
|
|
1576
|
+
|
|
1577
|
+
if (!result) {
|
|
1578
|
+
return null;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
const params = match.isRoot ? result : { ...baseParams,
|
|
1582
|
+
...result
|
|
1583
|
+
}; // 预处理
|
|
1584
|
+
|
|
1585
|
+
if (!preprocess([...router.guards], throughData, params)) {
|
|
1586
|
+
return null;
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
const newRouters = [...routers, router];
|
|
1590
|
+
const keyLen = match.isRoot ? match.keyLen : match.keyLen + key;
|
|
1591
|
+
const thisPath = result.$path;
|
|
1592
|
+
|
|
1593
|
+
for (const item of Array.from(router.__routes)) {
|
|
1594
|
+
if (item instanceof Router) {
|
|
1595
|
+
const res = await find(item, method, path, throughData, params, newRouters, thisPath, keyLen);
|
|
1596
|
+
|
|
1597
|
+
if (res) {
|
|
1598
|
+
return res;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
continue;
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
const pathParams = await matchRoute(item, method, path, params, thisPath, keyLen);
|
|
1605
|
+
|
|
1606
|
+
if (!pathParams) {
|
|
1607
|
+
continue;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
return {
|
|
1611
|
+
route: item,
|
|
1612
|
+
routers: newRouters,
|
|
1613
|
+
params: pathParams
|
|
1614
|
+
};
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
return null;
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
function buff2str(buffer) {
|
|
1621
|
+
const code = new Uint8Array(buffer);
|
|
1622
|
+
let ret = [];
|
|
1623
|
+
let index = 0;
|
|
1624
|
+
|
|
1625
|
+
while (index < code.length) {
|
|
1626
|
+
let c = code[index++] | 0;
|
|
1627
|
+
|
|
1628
|
+
if (c > 0b11100000) {
|
|
1629
|
+
c = (c & 0xF) << 12;
|
|
1630
|
+
c |= (code[index++] & 0x3F) << 6;
|
|
1631
|
+
c |= code[index++] & 0x3F;
|
|
1632
|
+
} else if (c > 0b11000000) {
|
|
1633
|
+
c = (c & 0x1F) << 12;
|
|
1634
|
+
c |= code[index++] & 0x3F;
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
ret.push(c);
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
return ret.map(x => String.fromCharCode(x)).join('');
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
function mergeArrayBuffer(data, length = data.reduce((a, b) => a + b.byteLength, 0)) {
|
|
1644
|
+
if (data.length === 1) {
|
|
1645
|
+
return data[0];
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
const array = new Uint8Array(length);
|
|
1649
|
+
let offset = 0;
|
|
1650
|
+
|
|
1651
|
+
for (const b of data) {
|
|
1652
|
+
for (let k of new Uint8Array(b)) {
|
|
1653
|
+
array[offset++] = k;
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
return array.buffer;
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
function getBuffer(encoding, data, size) {
|
|
1661
|
+
if (!size) {
|
|
1662
|
+
const buffer = mergeArrayBuffer(data);
|
|
1663
|
+
return encoding ? buff2str(buffer) : buffer;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
let length = 0;
|
|
1667
|
+
|
|
1668
|
+
for (let it; it = data.shift();) {
|
|
1669
|
+
if (length + it.byteLength > size) {
|
|
1670
|
+
const buffer = it.slice(0, size - length);
|
|
1671
|
+
length += buffer.byteLength;
|
|
1672
|
+
data.unshift(it.slice(buffer.byteLength));
|
|
1673
|
+
break;
|
|
1674
|
+
}
|
|
1675
|
+
length += it.byteLength;
|
|
1676
|
+
|
|
1677
|
+
if (length === size) {
|
|
1678
|
+
break;
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
const buffer = mergeArrayBuffer(data, length);
|
|
1683
|
+
return encoding ? buff2str(buffer) : buffer;
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
function str2buff(str) {
|
|
1687
|
+
let out = [];
|
|
1688
|
+
|
|
1689
|
+
for (let c of str.split('').map(ch => ch.charCodeAt(0))) {
|
|
1690
|
+
if (c < 0x80) {
|
|
1691
|
+
out.push(c);
|
|
1692
|
+
} else if (c < 0x800) {
|
|
1693
|
+
out.push(0xC0 | 0x1F & c >> 6);
|
|
1694
|
+
out.push(0x80 | 0x3F & c);
|
|
1695
|
+
} else {
|
|
1696
|
+
out.push(0xE0 | 0x0F & c >> 12);
|
|
1697
|
+
out.push(0x80 | 0x3F & c >> 6);
|
|
1698
|
+
out.push(0x80 | 0x3F & c);
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
return new Uint8Array(out).buffer;
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
function toBuffer(chunk) {
|
|
1706
|
+
if (typeof chunk === 'string') {
|
|
1707
|
+
return str2buff(chunk);
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
if (ArrayBuffer.isView(chunk)) {
|
|
1711
|
+
return chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength);
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
return chunk;
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
function isBaseWriteType$1(chunk) {
|
|
1718
|
+
if (chunk instanceof ArrayBuffer) {
|
|
1719
|
+
return true;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
if (ArrayBuffer.isView(chunk)) {
|
|
1723
|
+
return true;
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
try {
|
|
1727
|
+
if (chunk instanceof SharedArrayBuffer) {
|
|
1728
|
+
return true;
|
|
1729
|
+
}
|
|
1730
|
+
} catch {}
|
|
1731
|
+
|
|
1732
|
+
return false;
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
async function* toAsyncIterable(chunk) {
|
|
1736
|
+
if (!chunk) {
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
if (typeof chunk === 'string') {
|
|
1741
|
+
return yield chunk;
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
if (typeof chunk !== 'object') {
|
|
1745
|
+
return;
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
if (isBaseWriteType$1(chunk)) {
|
|
1749
|
+
return yield chunk;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
if (!(Symbol.asyncIterator in chunk || Symbol.iterator in chunk)) {
|
|
1753
|
+
return;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
for await (const data of chunk) {
|
|
1757
|
+
yield* toAsyncIterable(data);
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
async function main$1(req, getNext) {
|
|
1762
|
+
const data = [];
|
|
1763
|
+
let length = 0;
|
|
1764
|
+
let [size, encoding, cb] = await getNext();
|
|
1765
|
+
|
|
1766
|
+
for await (const v of toAsyncIterable(req)) {
|
|
1767
|
+
const buffer = toBuffer(v);
|
|
1768
|
+
data.push(buffer);
|
|
1769
|
+
length += buffer.byteLength;
|
|
1770
|
+
|
|
1771
|
+
if (size <= 0) {
|
|
1772
|
+
length = 0;
|
|
1773
|
+
cb(getBuffer(encoding, data));
|
|
1774
|
+
[size, encoding, cb] = await getNext();
|
|
1775
|
+
continue;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
if (length >= size) {
|
|
1779
|
+
length -= size;
|
|
1780
|
+
cb(getBuffer(encoding, data, size));
|
|
1781
|
+
[size, encoding, cb] = await getNext();
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
while (length && (size <= 0 || size <= length)) {
|
|
1785
|
+
if (size <= 0) {
|
|
1786
|
+
length = 0;
|
|
1787
|
+
cb(getBuffer(encoding, data));
|
|
1788
|
+
[size, encoding, cb] = await getNext();
|
|
1789
|
+
break;
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
length -= size;
|
|
1793
|
+
cb(getBuffer(encoding, data, size));
|
|
1794
|
+
[size, encoding, cb] = await getNext();
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
if (length) {
|
|
1799
|
+
cb(getBuffer(encoding, data));
|
|
1800
|
+
[size, encoding, cb] = await getNext();
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
cb(null);
|
|
1804
|
+
|
|
1805
|
+
for (;;) {
|
|
1806
|
+
[size, encoding, cb] = await getNext();
|
|
1807
|
+
cb(null);
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
function createRead(req) {
|
|
1812
|
+
if (!req) {
|
|
1813
|
+
return () => Promise.resolve(null);
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
const list = [];
|
|
1817
|
+
let next = null;
|
|
1818
|
+
main$1(req, function getNext() {
|
|
1819
|
+
return new Promise(r => {
|
|
1820
|
+
const t = list.shift();
|
|
1821
|
+
|
|
1822
|
+
if (t) {
|
|
1823
|
+
return r(t);
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
next = v => {
|
|
1827
|
+
next = null;
|
|
1828
|
+
r(v);
|
|
1829
|
+
};
|
|
1830
|
+
});
|
|
1831
|
+
});
|
|
1832
|
+
|
|
1833
|
+
function read(size = 0, encoding = false) {
|
|
1834
|
+
return new Promise(resolve => {
|
|
1835
|
+
size = Math.max(size, 0);
|
|
1836
|
+
|
|
1837
|
+
if (next) {
|
|
1838
|
+
next([size, encoding, resolve]);
|
|
1839
|
+
return;
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
list.push([size, encoding, resolve]);
|
|
1843
|
+
});
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
return read;
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
const urlRegex = /^(?:(?:https?:)?\/\/(?:(?:[^/?#]*@)?)(?:\d+|(?:\[[0-9a-f:]+\])|(?:\d{1,3}\.){3}\d{1,3}|(?:(?:[a-z0-9\u0100-\uffff]+-*)+\.)+[a-z]+)(?::\d+)?)?((?:\/?[^?#]*)?)((?:\?[^#]*)?)(?:#.*)?$/i;
|
|
1850
|
+
|
|
1851
|
+
function getNameValue(s) {
|
|
1852
|
+
const index = s.indexOf('=');
|
|
1853
|
+
|
|
1854
|
+
if (index < 0) {
|
|
1855
|
+
return [decodeURIComponent(s), ''];
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
return [decodeURIComponent(s.substring(0, index)), decodeURIComponent(s.substring(index + 1))];
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
function parseQuery(s) {
|
|
1862
|
+
const query = {};
|
|
1863
|
+
|
|
1864
|
+
for (const k of s.split('&').filter(Boolean)) {
|
|
1865
|
+
const [index, value] = getNameValue(k);
|
|
1866
|
+
|
|
1867
|
+
if (index in query) {
|
|
1868
|
+
query[index] = [query[index], value].flat();
|
|
1869
|
+
} else {
|
|
1870
|
+
query[index] = [value];
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
return query;
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
function parseUrl(uri) {
|
|
1878
|
+
const result = urlRegex.exec(uri);
|
|
1879
|
+
|
|
1880
|
+
if (!result) {
|
|
1881
|
+
return ['/', ''];
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
let [, pathname, search] = result;
|
|
1885
|
+
const path = [];
|
|
1886
|
+
|
|
1887
|
+
for (const p of pathname.replace(/^[\\/]+/, '').replace(/[\\/]+/g, '/').split('/')) {
|
|
1888
|
+
if (p === '.') {
|
|
1889
|
+
continue;
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
if (p === '..') {
|
|
1893
|
+
path.pop();
|
|
1894
|
+
continue;
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
path.push(p);
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
return [`/${path.join('/')}`, search];
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
function createRequest(method, path, body, headers = {}) {
|
|
1904
|
+
const [pathname, search] = parseUrl(path);
|
|
1905
|
+
return {
|
|
1906
|
+
method,
|
|
1907
|
+
url: `${pathname}${search}`,
|
|
1908
|
+
headers,
|
|
1909
|
+
pathname,
|
|
1910
|
+
search,
|
|
1911
|
+
query: parseQuery(search.substring(1)),
|
|
1912
|
+
read: typeof body === 'function' ? body : createRead(body)
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
function createWrite() {
|
|
1917
|
+
let list = [];
|
|
1918
|
+
let ended = false;
|
|
1919
|
+
let endCb = null;
|
|
1920
|
+
let next = null;
|
|
1921
|
+
|
|
1922
|
+
function run() {
|
|
1923
|
+
if (!next) {
|
|
1924
|
+
return;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
next(list.shift() || null);
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
function write(data) {
|
|
1931
|
+
return new Promise(cb => {
|
|
1932
|
+
if (endCb || ended) {
|
|
1933
|
+
return cb(false);
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
list.push([data, cb]);
|
|
1937
|
+
run();
|
|
1938
|
+
});
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
let endPromise = null;
|
|
1942
|
+
|
|
1943
|
+
function end() {
|
|
1944
|
+
if (!endPromise) {
|
|
1945
|
+
endPromise = new Promise(cb => {
|
|
1946
|
+
if (ended) {
|
|
1947
|
+
return cb();
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
endCb = cb;
|
|
1951
|
+
run();
|
|
1952
|
+
});
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
return endPromise;
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
function getEndFn() {
|
|
1959
|
+
return endCb;
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
function get() {
|
|
1963
|
+
return new Promise(r => {
|
|
1964
|
+
const value = list.shift();
|
|
1965
|
+
|
|
1966
|
+
if (value) {
|
|
1967
|
+
return r(value);
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
if (endCb) {
|
|
1971
|
+
return r(null);
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
next = v => {
|
|
1975
|
+
next = null;
|
|
1976
|
+
r(v);
|
|
1977
|
+
};
|
|
1978
|
+
});
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
const asyncIterable = async function* () {
|
|
1982
|
+
try {
|
|
1983
|
+
for (;;) {
|
|
1984
|
+
const value = await get();
|
|
1985
|
+
|
|
1986
|
+
if (value) {
|
|
1987
|
+
const [data, cb] = value;
|
|
1988
|
+
|
|
1989
|
+
try {
|
|
1990
|
+
yield data;
|
|
1991
|
+
cb(true);
|
|
1992
|
+
} catch {
|
|
1993
|
+
cb(false);
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
continue;
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
if (getEndFn()) {
|
|
2000
|
+
break;
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
} finally {
|
|
2004
|
+
ended = true; // eslint-disable-next-line no-cond-assign
|
|
2005
|
+
|
|
2006
|
+
for (let value; value = list.shift();) {
|
|
2007
|
+
const [, cb] = value;
|
|
2008
|
+
cb(false);
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
const endFn = getEndFn();
|
|
2012
|
+
|
|
2013
|
+
if (endFn) {
|
|
2014
|
+
endFn();
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
}();
|
|
2018
|
+
|
|
2019
|
+
return [write, end, asyncIterable, () => ended];
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
function isServiceFunc(t) {
|
|
2023
|
+
return typeof Service$1 === 'function';
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
function isServiceConstructor(t) {
|
|
2027
|
+
return Service$1.isPrototypeOf(t);
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
function runService(services, throughData, context, Service, p) {
|
|
2031
|
+
if (!isServiceConstructor(Service)) {
|
|
2032
|
+
if (isServiceFunc()) {
|
|
2033
|
+
return Service(context, ...p);
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
throw new TypeError('the object not is service class or function');
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
let service = services.get(Service);
|
|
2040
|
+
|
|
2041
|
+
if (service) {
|
|
2042
|
+
return service.export(...p);
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
service = new Service(context);
|
|
2046
|
+
services.set(Service, service);
|
|
2047
|
+
|
|
2048
|
+
if (Guard$1.isPrototypeOf(Service)) {
|
|
2049
|
+
relateMap(service, throughData, Service);
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
return service.export(...p);
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
function isBaseWriteType(chunk) {
|
|
2056
|
+
if (chunk instanceof ArrayBuffer) {
|
|
2057
|
+
return true;
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
if (ArrayBuffer.isView(chunk)) {
|
|
2061
|
+
return true;
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
try {
|
|
2065
|
+
if (chunk instanceof SharedArrayBuffer) {
|
|
2066
|
+
return true;
|
|
2067
|
+
}
|
|
2068
|
+
} catch {}
|
|
2069
|
+
|
|
2070
|
+
return false;
|
|
2071
|
+
}
|
|
2072
|
+
/**
|
|
2073
|
+
* 向可写流中写入数据
|
|
2074
|
+
* @param writable 可写流
|
|
2075
|
+
* @param chunk 要写入的数据
|
|
2076
|
+
* @param encoding 如果要写入的数据是字符串,则可用此参数指定编码
|
|
2077
|
+
*/
|
|
2078
|
+
|
|
2079
|
+
|
|
2080
|
+
async function writeData(write, isEnd, chunk) {
|
|
2081
|
+
if (!chunk) {
|
|
2082
|
+
return false;
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
if (isEnd()) {
|
|
2086
|
+
return true;
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
if (typeof chunk === 'string') {
|
|
2090
|
+
return write(chunk);
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
if (typeof chunk !== 'object') {
|
|
2094
|
+
return false;
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
if (isBaseWriteType(chunk)) {
|
|
2098
|
+
return write(chunk);
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
if (!(Symbol.asyncIterator in chunk || Symbol.iterator in chunk)) {
|
|
2102
|
+
return false;
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
for await (const data of chunk) {
|
|
2106
|
+
if (isEnd()) {
|
|
2107
|
+
return true;
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
if (!(await writeData(write, isEnd, data))) {
|
|
2111
|
+
return false;
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
return true;
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
function clearCookie(sentCookies, cookies, name, opt) {
|
|
2119
|
+
let expire = 'Fri, 31 Dec 1999 16:00:00 GMT';
|
|
2120
|
+
|
|
2121
|
+
if (typeof name === 'string') {
|
|
2122
|
+
if (!name) {
|
|
2123
|
+
return;
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
const {
|
|
2127
|
+
domain,
|
|
2128
|
+
path,
|
|
2129
|
+
secure,
|
|
2130
|
+
httpOnly
|
|
2131
|
+
} = opt !== true && opt || {};
|
|
2132
|
+
sentCookies.push({
|
|
2133
|
+
name,
|
|
2134
|
+
value: 'delete',
|
|
2135
|
+
expire,
|
|
2136
|
+
domain,
|
|
2137
|
+
path,
|
|
2138
|
+
secure,
|
|
2139
|
+
httpOnly
|
|
2140
|
+
});
|
|
2141
|
+
} else {
|
|
2142
|
+
const {
|
|
2143
|
+
domain,
|
|
2144
|
+
path,
|
|
2145
|
+
secure,
|
|
2146
|
+
httpOnly
|
|
2147
|
+
} = name || {};
|
|
2148
|
+
sentCookies.length = 0;
|
|
2149
|
+
|
|
2150
|
+
if (opt) {
|
|
2151
|
+
for (let name in cookies) {
|
|
2152
|
+
sentCookies.push({
|
|
2153
|
+
name,
|
|
2154
|
+
value: 'delete',
|
|
2155
|
+
expire,
|
|
2156
|
+
domain,
|
|
2157
|
+
path,
|
|
2158
|
+
secure,
|
|
2159
|
+
httpOnly
|
|
2160
|
+
});
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
function* getCookie(sentCookies, name) {
|
|
2167
|
+
const list = sentCookies;
|
|
2168
|
+
|
|
2169
|
+
for (const item of list) {
|
|
2170
|
+
if (name && item.name !== name) {
|
|
2171
|
+
continue;
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
yield { ...item
|
|
2175
|
+
};
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
function getRequestCookies(cookie) {
|
|
2180
|
+
let cookies = {};
|
|
2181
|
+
|
|
2182
|
+
for (const item of cookie.replace(/\s/g, '').split(';')) {
|
|
2183
|
+
const v = item.split('=');
|
|
2184
|
+
const name = decodeURIComponent(v.shift());
|
|
2185
|
+
cookies[name] = decodeURIComponent(v.join('='));
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2188
|
+
return cookies;
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
function getCookieHeader(list) {
|
|
2192
|
+
return list.map(({
|
|
2193
|
+
name,
|
|
2194
|
+
value,
|
|
2195
|
+
expire,
|
|
2196
|
+
domain,
|
|
2197
|
+
path,
|
|
2198
|
+
secure,
|
|
2199
|
+
httpOnly
|
|
2200
|
+
}) => name && [`${encodeURI(name)}=${encodeURI(value || '')}`, expire && `Expires=${expire}`, domain && `Domain=${encodeURI(domain)}`, path && `Path=${encodeURI(path)}`, secure && 'Secure', httpOnly && 'HttpOnly'].filter(Boolean).join('; ')).filter(Boolean);
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
const hostRegex = /^(\[[^\]]+\]|^:):(\d+)$/;
|
|
2204
|
+
function createContext(app, params, plugin, throughData, {
|
|
2205
|
+
method,
|
|
2206
|
+
url,
|
|
2207
|
+
pathname,
|
|
2208
|
+
search,
|
|
2209
|
+
query,
|
|
2210
|
+
read,
|
|
2211
|
+
headers: { ...headers
|
|
2212
|
+
}
|
|
2213
|
+
}) {
|
|
2214
|
+
const [write, end, asyncIterable, ended] = createWrite();
|
|
2215
|
+
let headersSent = false;
|
|
2216
|
+
let statusCode = 200;
|
|
2217
|
+
let resHeaders = {};
|
|
2218
|
+
let resolve;
|
|
2219
|
+
let value;
|
|
2220
|
+
|
|
2221
|
+
function send() {
|
|
2222
|
+
if (headersSent) {
|
|
2223
|
+
return;
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
headersSent = true;
|
|
2227
|
+
value = {
|
|
2228
|
+
get statusCode() {
|
|
2229
|
+
return statusCode;
|
|
2230
|
+
},
|
|
2231
|
+
|
|
2232
|
+
get finished() {
|
|
2233
|
+
return ended();
|
|
2234
|
+
},
|
|
2235
|
+
|
|
2236
|
+
headers: Object.freeze({ ...resHeaders
|
|
2237
|
+
}),
|
|
2238
|
+
|
|
2239
|
+
[Symbol.asyncIterator]() {
|
|
2240
|
+
return asyncIterable;
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2243
|
+
};
|
|
2244
|
+
|
|
2245
|
+
if (resolve) {
|
|
2246
|
+
resolve(value);
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2250
|
+
Object.freeze(headers);
|
|
2251
|
+
const host = headers.host || '';
|
|
2252
|
+
const hostInfo = hostRegex.exec(host);
|
|
2253
|
+
const [hostname, port] = hostInfo ? [hostInfo[1], hostInfo[2]] : [host, ''];
|
|
2254
|
+
const sentCookies = [];
|
|
2255
|
+
const cookies = getRequestCookies(headers['cookie'] || '');
|
|
2256
|
+
const services = new Map();
|
|
2257
|
+
let destroyed = false;
|
|
2258
|
+
|
|
2259
|
+
function isEnd() {
|
|
2260
|
+
return destroyed || ended();
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2263
|
+
let body;
|
|
2264
|
+
let data;
|
|
2265
|
+
|
|
2266
|
+
function setData(d) {
|
|
2267
|
+
data = d;
|
|
2268
|
+
}
|
|
2269
|
+
|
|
2270
|
+
const context = {
|
|
2271
|
+
get body() {
|
|
2272
|
+
return body;
|
|
2273
|
+
},
|
|
2274
|
+
|
|
2275
|
+
set body(b) {
|
|
2276
|
+
body = b;
|
|
2277
|
+
},
|
|
2278
|
+
|
|
2279
|
+
get data() {
|
|
2280
|
+
return data;
|
|
2281
|
+
},
|
|
2282
|
+
|
|
2283
|
+
app,
|
|
2284
|
+
settings: plugin ? app.settings(plugin, true) : app.settings,
|
|
2285
|
+
assets: plugin ? app.assets(plugin, true) : app.assets,
|
|
2286
|
+
logs: plugin ? app.logs(plugin, true) : app.logs,
|
|
2287
|
+
plugin,
|
|
2288
|
+
params,
|
|
2289
|
+
url,
|
|
2290
|
+
method,
|
|
2291
|
+
pathname,
|
|
2292
|
+
search,
|
|
2293
|
+
query,
|
|
2294
|
+
headers,
|
|
2295
|
+
referer: headers.referer || '',
|
|
2296
|
+
host,
|
|
2297
|
+
hostname,
|
|
2298
|
+
port,
|
|
2299
|
+
userAgent: headers['user-agent'] || '',
|
|
2300
|
+
accept: (headers.accept || '').split(/,\s*/).filter(Boolean),
|
|
2301
|
+
acceptLanguage: (headers['accept-language'] || '').split(/,\s*/).filter(Boolean),
|
|
2302
|
+
cookies,
|
|
2303
|
+
read,
|
|
2304
|
+
|
|
2305
|
+
/** 当前对象是否已经被销毁 */
|
|
2306
|
+
get destroyed() {
|
|
2307
|
+
return destroyed;
|
|
2308
|
+
},
|
|
2309
|
+
|
|
2310
|
+
/** 相应是否已结束 */
|
|
2311
|
+
get finished() {
|
|
2312
|
+
return ended();
|
|
2313
|
+
},
|
|
2314
|
+
|
|
2315
|
+
/** 响应头是否已经被发送 */
|
|
2316
|
+
get headersSent() {
|
|
2317
|
+
return headersSent;
|
|
2318
|
+
},
|
|
2319
|
+
|
|
2320
|
+
/** 状态码 */
|
|
2321
|
+
get status() {
|
|
2322
|
+
return statusCode;
|
|
2323
|
+
},
|
|
2324
|
+
|
|
2325
|
+
set status(v) {
|
|
2326
|
+
if (headersSent) {
|
|
2327
|
+
return;
|
|
2328
|
+
}
|
|
2329
|
+
|
|
2330
|
+
statusCode = v;
|
|
2331
|
+
},
|
|
2332
|
+
|
|
2333
|
+
/**
|
|
2334
|
+
* 获取已设置的 cookie 信息
|
|
2335
|
+
*/
|
|
2336
|
+
getCookie(name) {
|
|
2337
|
+
return getCookie(sentCookies, name);
|
|
2338
|
+
},
|
|
2339
|
+
|
|
2340
|
+
/**
|
|
2341
|
+
* 设置 cookie
|
|
2342
|
+
* @param name cookie 名称
|
|
2343
|
+
* @param value cookie 内容
|
|
2344
|
+
* @param option 选项
|
|
2345
|
+
*/
|
|
2346
|
+
setCookie(name, value, {
|
|
2347
|
+
expire,
|
|
2348
|
+
domain,
|
|
2349
|
+
path,
|
|
2350
|
+
secure,
|
|
2351
|
+
httpOnly
|
|
2352
|
+
} = {}) {
|
|
2353
|
+
if (headersSent) {
|
|
2354
|
+
return;
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
sentCookies.push({
|
|
2358
|
+
name,
|
|
2359
|
+
value,
|
|
2360
|
+
expire,
|
|
2361
|
+
domain,
|
|
2362
|
+
path,
|
|
2363
|
+
secure,
|
|
2364
|
+
httpOnly
|
|
2365
|
+
});
|
|
2366
|
+
resHeaders['set-cookie'] = getCookieHeader(sentCookies);
|
|
2367
|
+
},
|
|
2368
|
+
|
|
2369
|
+
clearCookie(name, opt) {
|
|
2370
|
+
if (headersSent) {
|
|
2371
|
+
return;
|
|
2372
|
+
}
|
|
2373
|
+
|
|
2374
|
+
clearCookie(sentCookies, cookies, name, opt);
|
|
2375
|
+
resHeaders['set-cookie'] = getCookieHeader(sentCookies);
|
|
2376
|
+
},
|
|
2377
|
+
|
|
2378
|
+
service(Service, ...p) {
|
|
2379
|
+
if (destroyed) {
|
|
2380
|
+
throw new Error('This controller is destroyed');
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2383
|
+
return runService(services, throughData, context, Service, p);
|
|
2384
|
+
},
|
|
2385
|
+
|
|
2386
|
+
/** 获取请求头中的 contentType */
|
|
2387
|
+
get requestType() {
|
|
2388
|
+
return headers['content-type'] || '';
|
|
2389
|
+
},
|
|
2390
|
+
|
|
2391
|
+
/** 相应头中的 contentType */
|
|
2392
|
+
get responseType() {
|
|
2393
|
+
return resHeaders['content-type'] || '';
|
|
2394
|
+
},
|
|
2395
|
+
|
|
2396
|
+
set responseType(v) {
|
|
2397
|
+
if (!headersSent) {
|
|
2398
|
+
resHeaders['content-type'] = v;
|
|
2399
|
+
}
|
|
2400
|
+
},
|
|
2401
|
+
|
|
2402
|
+
hasHeader(n) {
|
|
2403
|
+
return n in resHeaders;
|
|
2404
|
+
},
|
|
2405
|
+
|
|
2406
|
+
getHeaderNames() {
|
|
2407
|
+
return Object.keys(resHeaders);
|
|
2408
|
+
},
|
|
2409
|
+
|
|
2410
|
+
getHeaders() {
|
|
2411
|
+
return { ...resHeaders
|
|
2412
|
+
};
|
|
2413
|
+
},
|
|
2414
|
+
|
|
2415
|
+
getHeader(n) {
|
|
2416
|
+
return resHeaders[n];
|
|
2417
|
+
},
|
|
2418
|
+
|
|
2419
|
+
removeHeader(n) {
|
|
2420
|
+
if (!headersSent) {
|
|
2421
|
+
delete resHeaders[n];
|
|
2422
|
+
}
|
|
2423
|
+
},
|
|
2424
|
+
|
|
2425
|
+
setHeader(n, v) {
|
|
2426
|
+
if (headersSent) {
|
|
2427
|
+
return;
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2430
|
+
if (v === undefined) {
|
|
2431
|
+
delete resHeaders[n];
|
|
2432
|
+
} else {
|
|
2433
|
+
resHeaders[n] = v;
|
|
2434
|
+
}
|
|
2435
|
+
},
|
|
2436
|
+
|
|
2437
|
+
async write(chunk) {
|
|
2438
|
+
if (!chunk) {
|
|
2439
|
+
return true;
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
send();
|
|
2443
|
+
|
|
2444
|
+
if (isEnd()) {
|
|
2445
|
+
return true;
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
return writeData(write, isEnd, chunk);
|
|
2449
|
+
},
|
|
2450
|
+
|
|
2451
|
+
exit(status) {
|
|
2452
|
+
if (typeof status === 'number' && status >= 100 && status < 700) {
|
|
2453
|
+
statusCode = status;
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2456
|
+
throw new ExitSignal();
|
|
2457
|
+
},
|
|
2458
|
+
|
|
2459
|
+
transfer(url, is301) {
|
|
2460
|
+
statusCode = is301 ? 301 : 302;
|
|
2461
|
+
|
|
2462
|
+
if (!headersSent) {
|
|
2463
|
+
resHeaders['location'] = url;
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2466
|
+
throw new ExitSignal();
|
|
2467
|
+
},
|
|
2468
|
+
|
|
2469
|
+
request(method, path, {
|
|
2470
|
+
headers,
|
|
2471
|
+
body
|
|
2472
|
+
} = {}) {
|
|
2473
|
+
return app.request(createRequest(method, path, body, headers));
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
};
|
|
2477
|
+
|
|
2478
|
+
async function destroy() {
|
|
2479
|
+
if (destroyed) {
|
|
2480
|
+
return;
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
destroyed = true;
|
|
2484
|
+
|
|
2485
|
+
for (const c of [...services.values()]) {
|
|
2486
|
+
try {
|
|
2487
|
+
await c.destroy();
|
|
2488
|
+
} catch (e) {
|
|
2489
|
+
app.logs.error(e);
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2493
|
+
send();
|
|
2494
|
+
return end();
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
const response = new Promise(r => {
|
|
2498
|
+
if (headersSent && value) {
|
|
2499
|
+
r(value);
|
|
2500
|
+
} else {
|
|
2501
|
+
resolve = r;
|
|
2502
|
+
}
|
|
2503
|
+
});
|
|
2504
|
+
|
|
2505
|
+
async function runGuards(guards) {
|
|
2506
|
+
for (const Guard of guards) {
|
|
2507
|
+
let guard = services.get(Guard);
|
|
2508
|
+
|
|
2509
|
+
if (!guard) {
|
|
2510
|
+
guard = new Guard(context);
|
|
2511
|
+
relateMap(guard, throughData, Guard);
|
|
2512
|
+
services.set(Guard, guard);
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
if (false === (await guard.decide())) {
|
|
2516
|
+
return false;
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
return true;
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
return {
|
|
2524
|
+
context,
|
|
2525
|
+
destroy,
|
|
2526
|
+
setData,
|
|
2527
|
+
response,
|
|
2528
|
+
runGuards
|
|
2529
|
+
};
|
|
2530
|
+
}
|
|
2531
|
+
|
|
2532
|
+
function findController(routers, {
|
|
2533
|
+
controller
|
|
2534
|
+
}) {
|
|
2535
|
+
if (Controller$1.isControllerConstructor(controller)) {
|
|
2536
|
+
return controller;
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
for (const {
|
|
2540
|
+
controller
|
|
2541
|
+
} of [...routers].reverse()) {
|
|
2542
|
+
if (Controller$1.isControllerConstructor(controller)) {
|
|
2543
|
+
return controller;
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
|
|
2547
|
+
return Controller$1;
|
|
2548
|
+
}
|
|
2549
|
+
|
|
2550
|
+
function* getGuards(routers) {
|
|
2551
|
+
for (const {
|
|
2552
|
+
guards
|
|
2553
|
+
} of [...routers]) {
|
|
2554
|
+
yield* guards;
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
function returnResult(result, controller, context) {
|
|
2559
|
+
if (context.finished) {
|
|
2560
|
+
return;
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
if (!result) {
|
|
2564
|
+
return;
|
|
2565
|
+
}
|
|
2566
|
+
|
|
2567
|
+
if (context === result) {
|
|
2568
|
+
return;
|
|
2569
|
+
}
|
|
2570
|
+
|
|
2571
|
+
if (controller === result) {
|
|
2572
|
+
return;
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2575
|
+
return controller[returnSymbol](result);
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2578
|
+
async function exec(handle, controller, context, data) {
|
|
2579
|
+
if (typeof handle === 'function') {
|
|
2580
|
+
const result = await handle.call(context, data);
|
|
2581
|
+
return returnResult(result, controller, context);
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2584
|
+
if (typeof handle === 'string') {
|
|
2585
|
+
const fn = controller[handle];
|
|
2586
|
+
|
|
2587
|
+
if (typeof fn !== 'function') {
|
|
2588
|
+
return;
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
const result = await fn.call(controller);
|
|
2592
|
+
return returnResult(result, controller, context);
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2595
|
+
if (handle === optionsSymbol) {
|
|
2596
|
+
const result = await controller[optionsSymbol]();
|
|
2597
|
+
return returnResult(result, controller, context);
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
|
|
2601
|
+
async function catchError(app, controller, e) {
|
|
2602
|
+
if (e instanceof ExitSignal) {
|
|
2603
|
+
return;
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
try {
|
|
2607
|
+
await controller[catchSymbol](e);
|
|
2608
|
+
} catch (e) {
|
|
2609
|
+
app.logs.error(e);
|
|
2610
|
+
}
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2613
|
+
async function main(app, route, controller, context, runGuards, routers, destroy, setData) {
|
|
2614
|
+
try {
|
|
2615
|
+
// 初始化
|
|
2616
|
+
await controller[initSymbol]();
|
|
2617
|
+
|
|
2618
|
+
if (!(await runGuards(getGuards(routers)))) {
|
|
2619
|
+
return;
|
|
2620
|
+
}
|
|
2621
|
+
|
|
2622
|
+
const data = await controller[dataSymbol]();
|
|
2623
|
+
setData(data);
|
|
2624
|
+
await exec(route.handle, controller, context, data);
|
|
2625
|
+
} catch (e) {
|
|
2626
|
+
await catchError(app, controller, e);
|
|
2627
|
+
} finally {
|
|
2628
|
+
try {
|
|
2629
|
+
await controller[finallySymbol]();
|
|
2630
|
+
} catch (e) {
|
|
2631
|
+
app.logs.error(e);
|
|
2632
|
+
} // 销毁与回收处理
|
|
2633
|
+
|
|
2634
|
+
|
|
2635
|
+
await destroy();
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
function run(app, throughData, routers, route, request, params) {
|
|
2640
|
+
const {
|
|
2641
|
+
context,
|
|
2642
|
+
destroy,
|
|
2643
|
+
setData,
|
|
2644
|
+
response,
|
|
2645
|
+
runGuards
|
|
2646
|
+
} = createContext(app, params, route.plugin, throughData, request);
|
|
2647
|
+
const ThisController = findController(routers, route);
|
|
2648
|
+
const controller = new ThisController(context);
|
|
2649
|
+
main(app, route, controller, context, runGuards, routers, destroy, setData);
|
|
2650
|
+
return response;
|
|
2651
|
+
}
|
|
2652
|
+
|
|
2653
|
+
/** 查找请求的处理函数 */
|
|
2654
|
+
|
|
2655
|
+
async function callback(request) {
|
|
2656
|
+
const throughData = new Map();
|
|
2657
|
+
const it = await find(this, request.method, request.pathname, throughData, {}, [], '', 0);
|
|
2658
|
+
|
|
2659
|
+
if (!it) {
|
|
2660
|
+
return null;
|
|
2661
|
+
}
|
|
2662
|
+
|
|
2663
|
+
return run(this, throughData, it.routers, it.route, request, it.params);
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
const dotRegex = /^\.+$/;
|
|
2667
|
+
|
|
2668
|
+
function resolvePath(...paths) {
|
|
2669
|
+
const list = [];
|
|
2670
|
+
|
|
2671
|
+
for (const k of paths.map(p => p.split('/')).flat()) {
|
|
2672
|
+
if (!k || k === '.') {
|
|
2673
|
+
continue;
|
|
2674
|
+
}
|
|
2675
|
+
|
|
2676
|
+
if (dotRegex.test(k)) {
|
|
2677
|
+
list.length = Math.max(0, list.length - k.length + 1);
|
|
2678
|
+
continue;
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
list.push(k);
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
return `${list.join('/')}`;
|
|
2685
|
+
}
|
|
2686
|
+
/** 自扩展接口 */
|
|
2687
|
+
|
|
2688
|
+
|
|
2689
|
+
function subInterface(interfaces, extendsInterfaces, mark, basePath, path, setMark) {
|
|
2690
|
+
if (path === undefined) {
|
|
2691
|
+
return basePath;
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2694
|
+
if (path === '~') {
|
|
2695
|
+
path = mark;
|
|
2696
|
+
} else if (path.substr(0, 2) === '~/') {
|
|
2697
|
+
path = `${mark}/${path.substr(2)}`;
|
|
2698
|
+
} else if (path.substr(0, 2) === '\\~') {
|
|
2699
|
+
path = path.substr(1);
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2702
|
+
return Interface(interfaces, extendsInterfaces, setMark ? resolvePath(path) : mark, setMark ? '' : path, basePath);
|
|
2703
|
+
}
|
|
2704
|
+
/** 自扩展接口 */
|
|
2705
|
+
|
|
2706
|
+
|
|
2707
|
+
function Interface(interfaces, extendsInterfaces, mark = '', path = '', basePath = '') {
|
|
2708
|
+
basePath = resolvePath(basePath, path);
|
|
2709
|
+
const ret = subInterface.bind(null, interfaces, extendsInterfaces, mark, basePath);
|
|
2710
|
+
|
|
2711
|
+
for (const k in interfaces) {
|
|
2712
|
+
const v = interfaces[k];
|
|
2713
|
+
ret[k] = typeof v === 'function' ? (path, ...p) => v(resolvePath(basePath, path), ...p) : v;
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2716
|
+
if (!extendsInterfaces) {
|
|
2717
|
+
return ret;
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
for (const k in extendsInterfaces) {
|
|
2721
|
+
ret[k] = extendsInterfaces[k];
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
return ret;
|
|
2725
|
+
}
|
|
2726
|
+
|
|
2727
|
+
/**
|
|
2728
|
+
* 包装日志文本
|
|
2729
|
+
* @param log 原始的日志
|
|
2730
|
+
* @param opt 包装选项
|
|
2731
|
+
*/
|
|
2732
|
+
|
|
2733
|
+
function pack(log, {
|
|
2734
|
+
tags,
|
|
2735
|
+
indent
|
|
2736
|
+
}) {
|
|
2737
|
+
let extendInfo = '';
|
|
2738
|
+
|
|
2739
|
+
if (tags) {
|
|
2740
|
+
if (!Array.isArray(tags)) {
|
|
2741
|
+
tags = [tags];
|
|
2742
|
+
}
|
|
2743
|
+
|
|
2744
|
+
extendInfo = tags.map(tag => `[${tag}]`).join(' ');
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2747
|
+
extendInfo = `${new Date().toISOString()} ${extendInfo}`;
|
|
2748
|
+
|
|
2749
|
+
if (!log.includes('\n')) {
|
|
2750
|
+
return `${extendInfo} ${log}`;
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2753
|
+
if (typeof indent === 'number') {
|
|
2754
|
+
indent = Math.floor(indent);
|
|
2755
|
+
|
|
2756
|
+
if (isFinite(indent) && indent > 0) {
|
|
2757
|
+
indent = Array(indent).fill(' ').join('');
|
|
2758
|
+
}
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2761
|
+
if (!indent || typeof indent !== 'string') {
|
|
2762
|
+
indent = ' ';
|
|
2763
|
+
}
|
|
2764
|
+
|
|
2765
|
+
log = `${extendInfo}\n${log}`;
|
|
2766
|
+
log = log.split('\n').join(`\n${indent}`);
|
|
2767
|
+
return log;
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
function getErrorLog(log) {
|
|
2771
|
+
if (typeof log === 'string') {
|
|
2772
|
+
return log;
|
|
2773
|
+
}
|
|
2774
|
+
|
|
2775
|
+
if (log instanceof Error) {
|
|
2776
|
+
return log.stack || `${log.name}:${log.message}`;
|
|
2777
|
+
}
|
|
2778
|
+
|
|
2779
|
+
return String(log);
|
|
2780
|
+
}
|
|
2781
|
+
const regex1 = /(?:^|\/)(debug|error|warn|info)\/?$/;
|
|
2782
|
+
const regex2 = /^\/?(debug|error|warn|info)(?:\/|$)/;
|
|
2783
|
+
|
|
2784
|
+
function getType(path) {
|
|
2785
|
+
const v1 = regex1.exec(path);
|
|
2786
|
+
|
|
2787
|
+
if (v1) {
|
|
2788
|
+
return v1[1];
|
|
2789
|
+
}
|
|
2790
|
+
|
|
2791
|
+
const v2 = regex2.exec(path);
|
|
2792
|
+
|
|
2793
|
+
if (v2) {
|
|
2794
|
+
return v2[1];
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2797
|
+
return '';
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
async function defaultRead$2() {
|
|
2801
|
+
return '';
|
|
2802
|
+
}
|
|
2803
|
+
|
|
2804
|
+
function defaultWriteInPath(path, log) {
|
|
2805
|
+
console.group(`log @ ${path}`);
|
|
2806
|
+
|
|
2807
|
+
switch (getType(path)) {
|
|
2808
|
+
case 'debug':
|
|
2809
|
+
console.debug(log);
|
|
2810
|
+
break;
|
|
2811
|
+
|
|
2812
|
+
case 'info':
|
|
2813
|
+
console.info(log);
|
|
2814
|
+
break;
|
|
2815
|
+
|
|
2816
|
+
case 'warn':
|
|
2817
|
+
console.warn(log);
|
|
2818
|
+
break;
|
|
2819
|
+
|
|
2820
|
+
case 'error':
|
|
2821
|
+
console.error(log);
|
|
2822
|
+
break;
|
|
2823
|
+
|
|
2824
|
+
default:
|
|
2825
|
+
console.log(log);
|
|
2826
|
+
break;
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
console.groupEnd();
|
|
2830
|
+
}
|
|
2831
|
+
|
|
2832
|
+
async function defaultWrite$2(path, log) {
|
|
2833
|
+
switch (path) {
|
|
2834
|
+
case 'debug':
|
|
2835
|
+
console.debug(log);
|
|
2836
|
+
break;
|
|
2837
|
+
|
|
2838
|
+
case 'info':
|
|
2839
|
+
console.info(log);
|
|
2840
|
+
break;
|
|
2841
|
+
|
|
2842
|
+
case 'warn':
|
|
2843
|
+
console.warn(log);
|
|
2844
|
+
break;
|
|
2845
|
+
|
|
2846
|
+
case 'error':
|
|
2847
|
+
console.error(log);
|
|
2848
|
+
break;
|
|
2849
|
+
|
|
2850
|
+
default:
|
|
2851
|
+
defaultWriteInPath(path, log);
|
|
2852
|
+
break;
|
|
2853
|
+
}
|
|
2854
|
+
|
|
2855
|
+
return true;
|
|
2856
|
+
}
|
|
2857
|
+
|
|
2858
|
+
async function defaultClear() {}
|
|
2859
|
+
|
|
2860
|
+
function initLog({
|
|
2861
|
+
read = defaultRead$2,
|
|
2862
|
+
write = defaultWrite$2,
|
|
2863
|
+
clear = defaultClear
|
|
2864
|
+
} = {}) {
|
|
2865
|
+
function readLog(path) {
|
|
2866
|
+
return read(path);
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
function clearLog(path) {
|
|
2870
|
+
return clear(path);
|
|
2871
|
+
}
|
|
2872
|
+
|
|
2873
|
+
function writeLog(path, log, opt) {
|
|
2874
|
+
if (opt) {
|
|
2875
|
+
log = pack(log, opt);
|
|
2876
|
+
}
|
|
2877
|
+
|
|
2878
|
+
if (log[log.length - 1] !== '\n') {
|
|
2879
|
+
log += '\n';
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2882
|
+
return write(path, log);
|
|
2883
|
+
}
|
|
2884
|
+
|
|
2885
|
+
return Interface({
|
|
2886
|
+
read: readLog,
|
|
2887
|
+
write: writeLog,
|
|
2888
|
+
clear: clearLog
|
|
2889
|
+
}, {
|
|
2890
|
+
async debug(log, opt) {
|
|
2891
|
+
return writeLog('debug', log, opt);
|
|
2892
|
+
},
|
|
2893
|
+
|
|
2894
|
+
async info(log, opt) {
|
|
2895
|
+
return writeLog('info', log, opt);
|
|
2896
|
+
},
|
|
2897
|
+
|
|
2898
|
+
async warn(log, opt) {
|
|
2899
|
+
return writeLog('warn', getErrorLog(log), opt);
|
|
2900
|
+
},
|
|
2901
|
+
|
|
2902
|
+
async error(log, opt) {
|
|
2903
|
+
return writeLog('error', getErrorLog(log), opt);
|
|
2904
|
+
}
|
|
2905
|
+
|
|
2906
|
+
});
|
|
2907
|
+
}
|
|
2908
|
+
|
|
2909
|
+
const idRegexText = '[a-zA-Z][a-zA-Z0-9_-]*';
|
|
2910
|
+
const kRegexText = `${idRegexText}(?:.${idRegexText})*`;
|
|
2911
|
+
const regexText = `^/plugins/((?:@${kRegexText}/)?${kRegexText})/(.+)$`;
|
|
2912
|
+
const regex = new RegExp(regexText);
|
|
2913
|
+
function getPluginPath(path, plugins) {
|
|
2914
|
+
if (!plugins) {
|
|
2915
|
+
return null;
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
const r = regex.exec(path);
|
|
2919
|
+
|
|
2920
|
+
if (!r) {
|
|
2921
|
+
return null;
|
|
2922
|
+
}
|
|
2923
|
+
|
|
2924
|
+
const plugin = plugins[r[1]];
|
|
2925
|
+
|
|
2926
|
+
if (!plugin) {
|
|
2927
|
+
return null;
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2930
|
+
return [plugin, r[2]];
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2933
|
+
async function defaultRead$1() {
|
|
2934
|
+
return undefined;
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2937
|
+
async function defaultWrite$1() {
|
|
2938
|
+
return false;
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
function initSettings({
|
|
2942
|
+
read = defaultRead$1,
|
|
2943
|
+
write = defaultWrite$1
|
|
2944
|
+
} = {}, plugins) {
|
|
2945
|
+
async function readSetting(path) {
|
|
2946
|
+
const ret = await read(path);
|
|
2947
|
+
|
|
2948
|
+
if (ret) {
|
|
2949
|
+
return ret;
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2952
|
+
const p = getPluginPath(path, plugins);
|
|
2953
|
+
|
|
2954
|
+
if (!p) {
|
|
2955
|
+
return null;
|
|
2956
|
+
}
|
|
2957
|
+
|
|
2958
|
+
const [plugin, pluginPath] = p;
|
|
2959
|
+
return plugin.readSettings(pluginPath);
|
|
2960
|
+
}
|
|
2961
|
+
|
|
2962
|
+
function writeSetting(path, cfg) {
|
|
2963
|
+
return write(path, cfg);
|
|
2964
|
+
}
|
|
2965
|
+
|
|
2966
|
+
return Interface({
|
|
2967
|
+
read: readSetting,
|
|
2968
|
+
write: writeSetting
|
|
2969
|
+
}, {});
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
async function defaultRead() {
|
|
2973
|
+
return null;
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2976
|
+
async function defaultWrite() {
|
|
2977
|
+
return false;
|
|
2978
|
+
}
|
|
2979
|
+
|
|
2980
|
+
function initAssets({
|
|
2981
|
+
read = defaultRead,
|
|
2982
|
+
write = defaultWrite,
|
|
2983
|
+
delete: unlink = defaultWrite,
|
|
2984
|
+
stat = defaultRead
|
|
2985
|
+
} = {}, plugins) {
|
|
2986
|
+
async function readAsset(path, encoding) {
|
|
2987
|
+
const ret = await read(path, encoding);
|
|
2988
|
+
|
|
2989
|
+
if (ret !== null) {
|
|
2990
|
+
return ret;
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
const p = getPluginPath(path, plugins);
|
|
2994
|
+
|
|
2995
|
+
if (!p) {
|
|
2996
|
+
return null;
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
const [plugin, pluginPath] = p;
|
|
3000
|
+
return plugin.readAsset(pluginPath, encoding);
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
function writeAsset(path, data) {
|
|
3004
|
+
return write(path, data);
|
|
3005
|
+
}
|
|
3006
|
+
|
|
3007
|
+
function deleteAsset(path) {
|
|
3008
|
+
return unlink(path);
|
|
3009
|
+
}
|
|
3010
|
+
|
|
3011
|
+
async function statAsset(path) {
|
|
3012
|
+
return stat(path);
|
|
3013
|
+
}
|
|
3014
|
+
|
|
3015
|
+
return Interface({
|
|
3016
|
+
read: readAsset,
|
|
3017
|
+
write: writeAsset,
|
|
3018
|
+
delete: deleteAsset,
|
|
3019
|
+
stat: statAsset
|
|
3020
|
+
}, {});
|
|
3021
|
+
}
|
|
3022
|
+
|
|
3023
|
+
class App extends Router {
|
|
3024
|
+
/** 连接的处理函数 */
|
|
3025
|
+
|
|
3026
|
+
/** 设置接口 */
|
|
3027
|
+
|
|
3028
|
+
/** 资产接口 */
|
|
3029
|
+
|
|
3030
|
+
/** 日志接口 */
|
|
3031
|
+
constructor({
|
|
3032
|
+
router,
|
|
3033
|
+
settingApi,
|
|
3034
|
+
assetApi,
|
|
3035
|
+
logApi,
|
|
3036
|
+
path
|
|
3037
|
+
} = {}, plugins = Object.create(null)) {
|
|
3038
|
+
super(path);
|
|
3039
|
+
this.settings = initSettings(settingApi, plugins);
|
|
3040
|
+
this.assets = initAssets(assetApi, plugins);
|
|
3041
|
+
this.logs = initLog(logApi);
|
|
3042
|
+
this.plugins = plugins;
|
|
3043
|
+
|
|
3044
|
+
for (const plugin of Object.values(plugins)) {
|
|
3045
|
+
this.route(plugin.router);
|
|
3046
|
+
}
|
|
3047
|
+
|
|
3048
|
+
if (router instanceof Router) {
|
|
3049
|
+
this.route(router);
|
|
3050
|
+
}
|
|
3051
|
+
|
|
3052
|
+
this.request = callback.bind(this);
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
function set(handle, key, value) {
|
|
3058
|
+
if (value === undefined) {
|
|
3059
|
+
delete handle[key];
|
|
3060
|
+
}
|
|
3061
|
+
|
|
3062
|
+
handle[key] = value;
|
|
3063
|
+
return handle;
|
|
3064
|
+
}
|
|
3065
|
+
/** 设置配置 */
|
|
3066
|
+
|
|
3067
|
+
|
|
3068
|
+
function setTest(test) {
|
|
3069
|
+
return h => set(h, testSymbol, test);
|
|
3070
|
+
}
|
|
3071
|
+
/** 设置方法 */
|
|
3072
|
+
|
|
3073
|
+
function setMethods(...methods) {
|
|
3074
|
+
return h => set(h, methodsSymbol, methods.length ? methods : undefined);
|
|
3075
|
+
}
|
|
3076
|
+
/** 设置选项 */
|
|
3077
|
+
|
|
3078
|
+
function setOptions(options) {
|
|
3079
|
+
return h => set(h, optionsSymbol, options);
|
|
3080
|
+
}
|
|
3081
|
+
|
|
3082
|
+
export { App, Assets, Controller$1 as Controller, ExitSignal, Guard$1 as Guard, Handle, Log, Plugin, Router, Service$1 as Service, Settings, catchSymbol, dataSymbol, finallySymbol, initSymbol, methodsSymbol, optionsSymbol, returnSymbol, setMethods, setOptions, setTest, testSymbol };
|