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/node/index.mjs
ADDED
|
@@ -0,0 +1,1350 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* k99 v0.3.0-beta.1
|
|
3
|
+
* (c) 2019-2022 Fierflame
|
|
4
|
+
* @license MIT
|
|
5
|
+
*/
|
|
6
|
+
import * as fsFn from 'fs';
|
|
7
|
+
import * as pathFn from 'path';
|
|
8
|
+
import { Controller, Guard, Router, Plugin, App } from 'k99';
|
|
9
|
+
import { Http2ServerResponse } from 'http2';
|
|
10
|
+
import * as urlFn from 'url';
|
|
11
|
+
|
|
12
|
+
function _defineProperty(obj, key, value) {
|
|
13
|
+
if (key in obj) {
|
|
14
|
+
Object.defineProperty(obj, key, {
|
|
15
|
+
value: value,
|
|
16
|
+
enumerable: true,
|
|
17
|
+
configurable: true,
|
|
18
|
+
writable: true
|
|
19
|
+
});
|
|
20
|
+
} else {
|
|
21
|
+
obj[key] = value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return obj;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const registers = Object.create(null);
|
|
28
|
+
function setRegister({
|
|
29
|
+
extname,
|
|
30
|
+
type,
|
|
31
|
+
register
|
|
32
|
+
}, list = registers) {
|
|
33
|
+
const key = `${type || ''}.${extname}`;
|
|
34
|
+
|
|
35
|
+
if (!/^(?:[a-z]+)?\.[a-z]+$/.test(key)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (key in list) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (typeof register !== 'function') {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
list[key] = {
|
|
48
|
+
extname,
|
|
49
|
+
type,
|
|
50
|
+
register
|
|
51
|
+
};
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
/** 注册文件 */
|
|
55
|
+
|
|
56
|
+
async function register(file, router, list) {
|
|
57
|
+
const {
|
|
58
|
+
extname,
|
|
59
|
+
type
|
|
60
|
+
} = file;
|
|
61
|
+
const key = `${type || ''}.${extname}`;
|
|
62
|
+
const register = (list === null || list === void 0 ? void 0 : list[key]) || registers[key];
|
|
63
|
+
|
|
64
|
+
if (!register) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return register.register({ ...file
|
|
69
|
+
}, router);
|
|
70
|
+
}
|
|
71
|
+
setRegister({
|
|
72
|
+
extname: 'js',
|
|
73
|
+
|
|
74
|
+
async register({
|
|
75
|
+
root,
|
|
76
|
+
path,
|
|
77
|
+
plugin
|
|
78
|
+
}, router) {
|
|
79
|
+
const item = require(pathFn.join(root, path));
|
|
80
|
+
|
|
81
|
+
if (!item) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
router.register(item, {
|
|
86
|
+
root,
|
|
87
|
+
filePath: path,
|
|
88
|
+
plugin
|
|
89
|
+
});
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
});
|
|
94
|
+
setRegister({
|
|
95
|
+
extname: 'js',
|
|
96
|
+
type: 'resource',
|
|
97
|
+
|
|
98
|
+
async register({
|
|
99
|
+
root,
|
|
100
|
+
path,
|
|
101
|
+
plugin
|
|
102
|
+
}, router) {
|
|
103
|
+
const item = require(pathFn.join(root, path));
|
|
104
|
+
|
|
105
|
+
if (!item) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
router.resource(item, {
|
|
110
|
+
root,
|
|
111
|
+
filePath: path,
|
|
112
|
+
plugin
|
|
113
|
+
});
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
});
|
|
118
|
+
setRegister({
|
|
119
|
+
extname: 'js',
|
|
120
|
+
type: 'collection',
|
|
121
|
+
|
|
122
|
+
async register({
|
|
123
|
+
root,
|
|
124
|
+
path,
|
|
125
|
+
plugin
|
|
126
|
+
}, router) {
|
|
127
|
+
const item = require(pathFn.join(root, path));
|
|
128
|
+
|
|
129
|
+
if (!item) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
router.collection(item, {
|
|
134
|
+
root,
|
|
135
|
+
filePath: path,
|
|
136
|
+
plugin
|
|
137
|
+
});
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
});
|
|
142
|
+
setRegister({
|
|
143
|
+
extname: 'js',
|
|
144
|
+
type: 'members',
|
|
145
|
+
|
|
146
|
+
async register({
|
|
147
|
+
root,
|
|
148
|
+
path,
|
|
149
|
+
plugin
|
|
150
|
+
}, router) {
|
|
151
|
+
const item = require(pathFn.join(root, path));
|
|
152
|
+
|
|
153
|
+
if (!item) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
router.member(item, {
|
|
158
|
+
root,
|
|
159
|
+
filePath: path,
|
|
160
|
+
plugin
|
|
161
|
+
});
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
});
|
|
166
|
+
setRegister({
|
|
167
|
+
extname: 'js',
|
|
168
|
+
type: 'static',
|
|
169
|
+
|
|
170
|
+
async register({
|
|
171
|
+
root,
|
|
172
|
+
path,
|
|
173
|
+
plugin
|
|
174
|
+
}, router) {
|
|
175
|
+
const item = require(pathFn.join(root, path));
|
|
176
|
+
|
|
177
|
+
if (!item) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
router.collection(item, {
|
|
182
|
+
root,
|
|
183
|
+
filePath: path,
|
|
184
|
+
plugin
|
|
185
|
+
});
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
});
|
|
190
|
+
setRegister({
|
|
191
|
+
extname: 'js',
|
|
192
|
+
type: 'controller',
|
|
193
|
+
|
|
194
|
+
async register({
|
|
195
|
+
root,
|
|
196
|
+
path
|
|
197
|
+
}, router) {
|
|
198
|
+
const item = require(pathFn.join(root, path));
|
|
199
|
+
|
|
200
|
+
if (!item) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (typeof item.default !== 'function') {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (!Controller.isPrototypeOf(item.default)) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
router.controller = item.default;
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
});
|
|
217
|
+
setRegister({
|
|
218
|
+
extname: 'js',
|
|
219
|
+
type: 'guard',
|
|
220
|
+
|
|
221
|
+
async register({
|
|
222
|
+
root,
|
|
223
|
+
path
|
|
224
|
+
}, router) {
|
|
225
|
+
const item = require(pathFn.join(root, path));
|
|
226
|
+
|
|
227
|
+
if (!item) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (typeof item.default !== 'function') {
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (!Guard.isPrototypeOf(item.default)) {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
router.guards.add(item.default);
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
});
|
|
244
|
+
setRegister({
|
|
245
|
+
extname: 'js',
|
|
246
|
+
type: 'router',
|
|
247
|
+
|
|
248
|
+
async register({
|
|
249
|
+
root,
|
|
250
|
+
path
|
|
251
|
+
}, router) {
|
|
252
|
+
const item = require(pathFn.join(root, path));
|
|
253
|
+
|
|
254
|
+
if (!item) {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (typeof item.default !== 'function') {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (!Router.isPrototypeOf(item.default)) {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
router.route(item.default);
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
});
|
|
271
|
+
setRegister({
|
|
272
|
+
extname: 'mjs',
|
|
273
|
+
|
|
274
|
+
async register({
|
|
275
|
+
root,
|
|
276
|
+
path,
|
|
277
|
+
plugin
|
|
278
|
+
}, router) {
|
|
279
|
+
const item = await import(pathFn.join(root, path));
|
|
280
|
+
|
|
281
|
+
if (!item) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
router.register(item, {
|
|
286
|
+
root,
|
|
287
|
+
filePath: path,
|
|
288
|
+
plugin
|
|
289
|
+
});
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
});
|
|
294
|
+
setRegister({
|
|
295
|
+
extname: 'mjs',
|
|
296
|
+
type: 'resource',
|
|
297
|
+
|
|
298
|
+
async register({
|
|
299
|
+
root,
|
|
300
|
+
path,
|
|
301
|
+
plugin
|
|
302
|
+
}, router) {
|
|
303
|
+
const item = await import(pathFn.join(root, path));
|
|
304
|
+
|
|
305
|
+
if (!item) {
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
router.resource(item, {
|
|
310
|
+
root,
|
|
311
|
+
filePath: path,
|
|
312
|
+
plugin
|
|
313
|
+
});
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
});
|
|
318
|
+
setRegister({
|
|
319
|
+
extname: 'mjs',
|
|
320
|
+
type: 'collection',
|
|
321
|
+
|
|
322
|
+
async register({
|
|
323
|
+
root,
|
|
324
|
+
path,
|
|
325
|
+
plugin
|
|
326
|
+
}, router) {
|
|
327
|
+
const item = await import(pathFn.join(root, path));
|
|
328
|
+
|
|
329
|
+
if (!item) {
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
router.collection(item, {
|
|
334
|
+
root,
|
|
335
|
+
filePath: path,
|
|
336
|
+
plugin
|
|
337
|
+
});
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
});
|
|
342
|
+
setRegister({
|
|
343
|
+
extname: 'mjs',
|
|
344
|
+
type: 'members',
|
|
345
|
+
|
|
346
|
+
async register({
|
|
347
|
+
root,
|
|
348
|
+
path,
|
|
349
|
+
plugin
|
|
350
|
+
}, router) {
|
|
351
|
+
const item = await import(pathFn.join(root, path));
|
|
352
|
+
|
|
353
|
+
if (!item) {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
router.member(item, {
|
|
358
|
+
root,
|
|
359
|
+
filePath: path,
|
|
360
|
+
plugin
|
|
361
|
+
});
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
});
|
|
366
|
+
setRegister({
|
|
367
|
+
extname: 'mjs',
|
|
368
|
+
type: 'static',
|
|
369
|
+
|
|
370
|
+
async register({
|
|
371
|
+
root,
|
|
372
|
+
path,
|
|
373
|
+
plugin
|
|
374
|
+
}, router) {
|
|
375
|
+
const item = await import(pathFn.join(root, path));
|
|
376
|
+
|
|
377
|
+
if (!item) {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
router.collection(item, {
|
|
382
|
+
root,
|
|
383
|
+
filePath: path,
|
|
384
|
+
plugin
|
|
385
|
+
});
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
});
|
|
390
|
+
setRegister({
|
|
391
|
+
extname: 'mjs',
|
|
392
|
+
type: 'controller',
|
|
393
|
+
|
|
394
|
+
async register({
|
|
395
|
+
root,
|
|
396
|
+
path
|
|
397
|
+
}, router) {
|
|
398
|
+
const item = await import(pathFn.join(root, path));
|
|
399
|
+
|
|
400
|
+
if (!item) {
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (typeof item.default !== 'function') {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (!Controller.isPrototypeOf(item.default)) {
|
|
409
|
+
return false;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
router.controller = item.default;
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
});
|
|
417
|
+
setRegister({
|
|
418
|
+
extname: 'mjs',
|
|
419
|
+
type: 'guard',
|
|
420
|
+
|
|
421
|
+
async register({
|
|
422
|
+
root,
|
|
423
|
+
path
|
|
424
|
+
}, router) {
|
|
425
|
+
const item = await import(pathFn.join(root, path));
|
|
426
|
+
|
|
427
|
+
if (!item) {
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (typeof item.default !== 'function') {
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (!Guard.isPrototypeOf(item.default)) {
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
router.guards.add(item.default);
|
|
440
|
+
return true;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
});
|
|
444
|
+
setRegister({
|
|
445
|
+
extname: 'mjs',
|
|
446
|
+
type: 'router',
|
|
447
|
+
|
|
448
|
+
async register({
|
|
449
|
+
root,
|
|
450
|
+
path
|
|
451
|
+
}, router) {
|
|
452
|
+
const item = await import(pathFn.join(root, path));
|
|
453
|
+
|
|
454
|
+
if (!item) {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (typeof item.default !== 'function') {
|
|
459
|
+
return false;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (!Router.isPrototypeOf(item.default)) {
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
router.route(item.default);
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
const dirRegex = /^((?:\d+\.)?)([:$]?)([a-zA-Z0-9_-]+)(\${0,3}|[?*+])$/;
|
|
473
|
+
const fileRegex = /^((?:\d+\.)?)([:$]?)([a-zA-Z0-9_-]+)(\${0,3}|[?*+])((?:\.[a-z]+)?)(\.[a-z]+)$/;
|
|
474
|
+
function getPathSortInfo(filename) {
|
|
475
|
+
const dir = dirRegex.exec(filename);
|
|
476
|
+
|
|
477
|
+
if (dir) {
|
|
478
|
+
const no = Number.parseInt(dir[1]);
|
|
479
|
+
const tuple = Boolean(dir[2]);
|
|
480
|
+
const extend = dir[4].replace(/\${3}$/, '+').replace(/\${2}$/, '*').replace(/\${1}$/, '?');
|
|
481
|
+
const name = [tuple && ':', dir[3], extend].filter(Boolean).join('');
|
|
482
|
+
return {
|
|
483
|
+
dir: true,
|
|
484
|
+
filename,
|
|
485
|
+
no,
|
|
486
|
+
tuple,
|
|
487
|
+
name,
|
|
488
|
+
extend
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const file = fileRegex.exec(filename);
|
|
493
|
+
|
|
494
|
+
if (!file) {
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const no = Number.parseInt(file[1]);
|
|
499
|
+
const tuple = Boolean(file[2]);
|
|
500
|
+
const extend = file[4].replace(/\${3}$/, '+').replace(/\${2}$/, '*').replace(/\${1}$/, '?');
|
|
501
|
+
const name = !file[1] && !tuple && !extend && file[3] === 'index' ? '' : [tuple && ':', file[3], extend].filter(Boolean).join('');
|
|
502
|
+
const type = file[5].substr(1);
|
|
503
|
+
const extname = file[6].substr(1);
|
|
504
|
+
return {
|
|
505
|
+
filename,
|
|
506
|
+
no,
|
|
507
|
+
tuple,
|
|
508
|
+
name,
|
|
509
|
+
extend,
|
|
510
|
+
type,
|
|
511
|
+
extname
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function sortValid(a, b) {
|
|
516
|
+
if (a.name && !b.name) {
|
|
517
|
+
return 1;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (!a.name && b.name) {
|
|
521
|
+
return -1;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (!a.name && !b.name) {
|
|
525
|
+
return 0;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (Number.isFinite(a.no) && Number.isFinite(b.no) && a.no !== b.no) {
|
|
529
|
+
return a.no - b.no;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (Number.isFinite(a.no) && !Number.isFinite(b.no)) {
|
|
533
|
+
return -1;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (!Number.isFinite(a.no) && Number.isFinite(b.no)) {
|
|
537
|
+
return 1;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (a.tuple && !b.tuple) {
|
|
541
|
+
return 1;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (!a.tuple && b.tuple) {
|
|
545
|
+
return -1;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if (a.dir && !b.dir) {
|
|
549
|
+
return 1;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (!a.dir && b.dir) {
|
|
553
|
+
return -1;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
if (a.extend === b.extend) {
|
|
557
|
+
let aName = a.name.toLowerCase();
|
|
558
|
+
let bName = b.name.toLowerCase();
|
|
559
|
+
return aName > bName ? 1 : aName < bName ? -1 : a.name < b.name ? 1 : a.name > b.name ? -1 : 0;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
if (a.extend && !b.extend) {
|
|
563
|
+
return 1;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
if (!a.extend && b.extend) {
|
|
567
|
+
return -1;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (a.extend === '*') {
|
|
571
|
+
return 1;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (b.extend === '*') {
|
|
575
|
+
return -1;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
if (a.extend === '+') {
|
|
579
|
+
return 1;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
if (b.extend === '+') {
|
|
583
|
+
return -1;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
if (a.extend === '?') {
|
|
587
|
+
return 1;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
return -1;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
function isValidInfo(t) {
|
|
594
|
+
return Boolean(t);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
async function readdir$1(path) {
|
|
598
|
+
return new Promise(resolve => fsFn.readdir(path, {
|
|
599
|
+
encoding: 'utf-8'
|
|
600
|
+
}, (err, files) => err ? resolve([]) : resolve(files))).then(paths => paths.map(getPathSortInfo).filter(isValidInfo).sort(sortValid));
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
async function stat(path) {
|
|
604
|
+
return new Promise(resolve => fsFn.stat(path, (err, stat) => err ? resolve() : resolve(stat)));
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
async function isFile$1(path) {
|
|
608
|
+
const s = await stat(path);
|
|
609
|
+
return s && s.isFile();
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
async function isDir(path) {
|
|
613
|
+
const s = await stat(path);
|
|
614
|
+
return s && s.isDirectory();
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
async function scan(root, router, plugin, list, path = '', scope = []) {
|
|
618
|
+
const routers = Object.create(null);
|
|
619
|
+
|
|
620
|
+
function getRouter(name) {
|
|
621
|
+
if (!name) {
|
|
622
|
+
return router;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
let child = routers[name];
|
|
626
|
+
|
|
627
|
+
if (!child) {
|
|
628
|
+
child = router.route(name);
|
|
629
|
+
routers[name] = child;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
return child;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
for (let item of await readdir$1(pathFn.resolve(root, path))) {
|
|
636
|
+
const {
|
|
637
|
+
filename,
|
|
638
|
+
name
|
|
639
|
+
} = item;
|
|
640
|
+
const newPath = pathFn.join(path, filename);
|
|
641
|
+
|
|
642
|
+
if (item.dir) {
|
|
643
|
+
if (isDir(pathFn.resolve(root, newPath))) {
|
|
644
|
+
await scan(root, getRouter(name), plugin, list, newPath, [...scope, name]);
|
|
645
|
+
}
|
|
646
|
+
} else if (isFile$1(pathFn.resolve(root, newPath))) {
|
|
647
|
+
const {
|
|
648
|
+
extname,
|
|
649
|
+
type
|
|
650
|
+
} = item;
|
|
651
|
+
await register({
|
|
652
|
+
extname,
|
|
653
|
+
type,
|
|
654
|
+
root,
|
|
655
|
+
path: newPath,
|
|
656
|
+
plugin,
|
|
657
|
+
scope: name ? [...scope, name] : scope
|
|
658
|
+
}, getRouter(name), list);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
class Scanner {
|
|
664
|
+
constructor() {
|
|
665
|
+
_defineProperty(this, "__registers", Object.create(null));
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* 设置公共的文件注册器
|
|
670
|
+
* @param register 注册配置
|
|
671
|
+
*/
|
|
672
|
+
static setRegister(register) {
|
|
673
|
+
return setRegister(register);
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* 扫描指定路径,并将扫描到的文件进行注册
|
|
677
|
+
* @param root 要扫描的路径
|
|
678
|
+
* @param router 被注册的路由
|
|
679
|
+
*/
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
static scan(root, router, plugin) {
|
|
683
|
+
return scan(root, router, plugin);
|
|
684
|
+
}
|
|
685
|
+
/** 注册器列表 */
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* 扫描指定路径,并将扫描到的文件进行注册
|
|
690
|
+
* @param root 要扫描的路径
|
|
691
|
+
* @param router 被注册的路由
|
|
692
|
+
*/
|
|
693
|
+
scan(root, router, plugin) {
|
|
694
|
+
return scan(root, router, plugin, this.__registers);
|
|
695
|
+
}
|
|
696
|
+
/** 为当前路由设置注册器 */
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
setRegister(register) {
|
|
700
|
+
return setRegister(register, this.__registers);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
async function getRouters(router, routers) {
|
|
706
|
+
const r = await getRouter(router);
|
|
707
|
+
|
|
708
|
+
if (!Array.isArray(routers)) {
|
|
709
|
+
return r ? [r] : undefined;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
const list = r ? [r] : [];
|
|
713
|
+
|
|
714
|
+
for (const router of routers) {
|
|
715
|
+
const r = await getRouter(router);
|
|
716
|
+
|
|
717
|
+
if (r) {
|
|
718
|
+
list.push(r);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
if (list.length) {
|
|
723
|
+
return list;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
async function getRouter(router) {
|
|
728
|
+
if (typeof router === 'function') {
|
|
729
|
+
router = await router();
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
if (router instanceof Router) {
|
|
733
|
+
return router;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
class FsPlugin extends Plugin {
|
|
738
|
+
/** 路径 */
|
|
739
|
+
async readSettings(path) {
|
|
740
|
+
const p = pathFn.resolve(this.settingsPath, `${path}.json`);
|
|
741
|
+
|
|
742
|
+
try {
|
|
743
|
+
return JSON.parse((await new Promise((resolve, reject) => fsFn.readFile(p, 'utf-8', (e, d) => e ? reject(e) : resolve(d)))));
|
|
744
|
+
} catch {}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
readAsset(path, encoding) {
|
|
748
|
+
return new Promise(resolve => fsFn.readFile(pathFn.resolve(this.assetsPath, path), encoding ? 'utf-8' : null, (e, d) => e ? resolve(null) : resolve(typeof d === 'string' ? d : d.buffer)));
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
constructor(config, name) {
|
|
752
|
+
const {
|
|
753
|
+
path,
|
|
754
|
+
version,
|
|
755
|
+
author,
|
|
756
|
+
license,
|
|
757
|
+
assetsPath,
|
|
758
|
+
settingsPath,
|
|
759
|
+
logsPath
|
|
760
|
+
} = config;
|
|
761
|
+
super(name, version || '', {
|
|
762
|
+
author,
|
|
763
|
+
license
|
|
764
|
+
});
|
|
765
|
+
this._config = config;
|
|
766
|
+
this.assetsPath = pathFn.resolve(path, assetsPath || 'assets');
|
|
767
|
+
this.settingsPath = pathFn.resolve(path, settingsPath || 'settings');
|
|
768
|
+
this.logsPath = pathFn.resolve(path, logsPath || 'logs');
|
|
769
|
+
this.path = path;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
async _initRouter(pluginRouter) {
|
|
773
|
+
const {
|
|
774
|
+
_config
|
|
775
|
+
} = this;
|
|
776
|
+
const list = await getRouters(_config.router, _config.routers);
|
|
777
|
+
|
|
778
|
+
for (const router of list || []) {
|
|
779
|
+
pluginRouter.route(router);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
const {
|
|
783
|
+
appPath
|
|
784
|
+
} = _config;
|
|
785
|
+
|
|
786
|
+
if (list && !appPath) {
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
const {
|
|
791
|
+
path
|
|
792
|
+
} = _config;
|
|
793
|
+
await Scanner.scan(pathFn.resolve(path, appPath || 'app'), pluginRouter);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
function createFsLogApi(logsPath) {
|
|
799
|
+
const basePath = pathFn.resolve(logsPath, '.');
|
|
800
|
+
return {
|
|
801
|
+
async read(path) {
|
|
802
|
+
path = `${basePath}/${path}.log`;
|
|
803
|
+
return new Promise(resolve => fsFn.readFile(path, 'utf-8', (e, d) => resolve(e ? '' : d)));
|
|
804
|
+
},
|
|
805
|
+
|
|
806
|
+
async write(path, log) {
|
|
807
|
+
path = `${basePath}/${path}.log`;
|
|
808
|
+
await new Promise(r => fsFn.mkdir(pathFn.dirname(path), {
|
|
809
|
+
recursive: true
|
|
810
|
+
}, () => r()));
|
|
811
|
+
return new Promise(resolve => fsFn.appendFile(path, log, e => resolve(!e)));
|
|
812
|
+
},
|
|
813
|
+
|
|
814
|
+
async clear(path) {
|
|
815
|
+
path = `${basePath}/${path}.log`;
|
|
816
|
+
return new Promise(resolve => fsFn.writeFile(path, '', () => resolve()));
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
function createFsSettingsApi(settingsPath) {
|
|
823
|
+
const basePath = pathFn.resolve(settingsPath, '.');
|
|
824
|
+
return {
|
|
825
|
+
async read(path) {
|
|
826
|
+
const p = `${basePath}/${path}.json`;
|
|
827
|
+
const text = await new Promise(r => fsFn.readFile(p, 'utf8', (e, d) => e ? r('') : r(d)));
|
|
828
|
+
|
|
829
|
+
if (!text) {
|
|
830
|
+
return undefined;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
try {
|
|
834
|
+
return JSON.parse(text);
|
|
835
|
+
} catch {}
|
|
836
|
+
},
|
|
837
|
+
|
|
838
|
+
async write(path, cfg) {
|
|
839
|
+
const p = `${basePath}/${path}.json`;
|
|
840
|
+
|
|
841
|
+
if (cfg === undefined) {
|
|
842
|
+
return new Promise(r => fsFn.unlink(p, e => r(!e)));
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
await new Promise(r => fsFn.mkdir(pathFn.dirname(p), {
|
|
846
|
+
recursive: true
|
|
847
|
+
}, r));
|
|
848
|
+
const text = JSON.stringify(cfg);
|
|
849
|
+
return new Promise(r => fsFn.writeFile(p, text, e => r(!e)));
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
function getStat(s) {
|
|
856
|
+
return {
|
|
857
|
+
get isDirectory() {
|
|
858
|
+
return s.isDirectory();
|
|
859
|
+
},
|
|
860
|
+
|
|
861
|
+
size: s.size,
|
|
862
|
+
updateTime: s.mtime,
|
|
863
|
+
createTime: s.birthtime
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
function createFsAssetsApi(assetsPath) {
|
|
868
|
+
const basePath = pathFn.resolve(assetsPath, '.');
|
|
869
|
+
|
|
870
|
+
function read(path, encoding) {
|
|
871
|
+
const p = `${basePath}/${path}`;
|
|
872
|
+
const options = encoding ? 'utf8' : null;
|
|
873
|
+
return new Promise(r => fsFn.readFile(p, options, (e, d) => e ? r(null) : r(typeof d === 'string' ? d : d.buffer)));
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
return {
|
|
877
|
+
read,
|
|
878
|
+
|
|
879
|
+
async write(path, data) {
|
|
880
|
+
const p = `${basePath}/${path}`;
|
|
881
|
+
await new Promise(r => fsFn.mkdir(pathFn.dirname(p), {
|
|
882
|
+
recursive: true
|
|
883
|
+
}, r));
|
|
884
|
+
return new Promise(r => fsFn.writeFile(p, data, e => r(!e)));
|
|
885
|
+
},
|
|
886
|
+
|
|
887
|
+
delete(path) {
|
|
888
|
+
const p = `${basePath}/${path}`;
|
|
889
|
+
return new Promise(resolve => fsFn.unlink(p, e => resolve(!e)));
|
|
890
|
+
},
|
|
891
|
+
|
|
892
|
+
stat(path) {
|
|
893
|
+
const p = `${basePath}/${path}`;
|
|
894
|
+
return new Promise(r => fsFn.stat(p, (e, s) => e ? r(null) : r(getStat(s))));
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
class NodeApp extends App {
|
|
901
|
+
constructor({
|
|
902
|
+
path,
|
|
903
|
+
settingsPath,
|
|
904
|
+
assetsPath,
|
|
905
|
+
logsPath,
|
|
906
|
+
router
|
|
907
|
+
} = {}, plugins) {
|
|
908
|
+
const cwd = pathFn.resolve(path || process.cwd());
|
|
909
|
+
const newSettingsPath = pathFn.resolve(cwd, settingsPath || 'settings');
|
|
910
|
+
const newAssetsPath = pathFn.resolve(cwd, assetsPath || 'assets');
|
|
911
|
+
const newLogsPath = pathFn.resolve(cwd, logsPath || 'logs');
|
|
912
|
+
super({
|
|
913
|
+
path: cwd,
|
|
914
|
+
settingApi: createFsSettingsApi(newSettingsPath),
|
|
915
|
+
assetApi: createFsAssetsApi(newAssetsPath),
|
|
916
|
+
logApi: createFsLogApi(newLogsPath),
|
|
917
|
+
router
|
|
918
|
+
}, plugins);
|
|
919
|
+
this.cwd = cwd;
|
|
920
|
+
this.settingsPath = newSettingsPath;
|
|
921
|
+
this.assetsPath = newAssetsPath;
|
|
922
|
+
this.logsPath = newLogsPath;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
function createRead(req) {
|
|
928
|
+
let currentEncoding = false;
|
|
929
|
+
let current = 0;
|
|
930
|
+
let cb = null;
|
|
931
|
+
let end = false;
|
|
932
|
+
const dataList = [];
|
|
933
|
+
let dataSize = 0;
|
|
934
|
+
const list = [];
|
|
935
|
+
let running = false;
|
|
936
|
+
|
|
937
|
+
function get(size) {
|
|
938
|
+
const chunk = Buffer.concat(dataList, dataSize);
|
|
939
|
+
|
|
940
|
+
if (size && dataSize > size) {
|
|
941
|
+
dataList.length = 0;
|
|
942
|
+
dataList.push(chunk.slice(size));
|
|
943
|
+
dataSize -= size;
|
|
944
|
+
return chunk.slice(0, size);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
dataSize = 0;
|
|
948
|
+
dataList.length = 0;
|
|
949
|
+
return chunk;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
function add(data) {
|
|
953
|
+
const buffer = typeof data === 'string' ? Buffer.from(data) : data;
|
|
954
|
+
dataSize += buffer.length || 0;
|
|
955
|
+
dataList.push(buffer);
|
|
956
|
+
return dataSize;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
function nextData() {
|
|
960
|
+
return current ? req.read(current) : req.read();
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
function runCb(v) {
|
|
964
|
+
if (!cb) {
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
cb(v);
|
|
969
|
+
[current, currentEncoding, cb] = list.shift() || [0, false, null];
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
function runMain() {
|
|
973
|
+
for (;;) {
|
|
974
|
+
if (!cb) {
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
if (end) {
|
|
979
|
+
runCb(dataSize ? get(current) : null);
|
|
980
|
+
continue;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
if (!current && dataSize) {
|
|
984
|
+
runCb(get(current));
|
|
985
|
+
continue;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
const data = nextData();
|
|
989
|
+
|
|
990
|
+
if (data === null) {
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
if (current) {
|
|
995
|
+
if (add(data) < current) {
|
|
996
|
+
continue;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
runCb(get(current));
|
|
1000
|
+
continue;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
if (currentEncoding) {
|
|
1004
|
+
runCb(typeof data === 'string' ? data : String(data));
|
|
1005
|
+
} else {
|
|
1006
|
+
runCb(typeof data === 'string' ? Buffer.from(data) : data);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
let setEnd = false;
|
|
1012
|
+
|
|
1013
|
+
function run() {
|
|
1014
|
+
running = true;
|
|
1015
|
+
runMain();
|
|
1016
|
+
|
|
1017
|
+
if (setEnd) {
|
|
1018
|
+
end = true;
|
|
1019
|
+
runMain();
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
running = false;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
req.addListener('end', () => {
|
|
1026
|
+
if (end || setEnd) {
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
if (running) {
|
|
1031
|
+
setEnd = true;
|
|
1032
|
+
} else {
|
|
1033
|
+
end = true;
|
|
1034
|
+
run();
|
|
1035
|
+
}
|
|
1036
|
+
});
|
|
1037
|
+
|
|
1038
|
+
function read(size = 0, encoding = false) {
|
|
1039
|
+
return new Promise(resolve => {
|
|
1040
|
+
size = Math.max(size, 0);
|
|
1041
|
+
|
|
1042
|
+
if (cb) {
|
|
1043
|
+
list.push([size, encoding, resolve]);
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
currentEncoding = encoding;
|
|
1048
|
+
current = size;
|
|
1049
|
+
cb = resolve;
|
|
1050
|
+
run();
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
return read;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
function createRequest(req) {
|
|
1058
|
+
const urlInfo = urlFn.parse(req.url || '/', true);
|
|
1059
|
+
return {
|
|
1060
|
+
method: (req.method || 'GET').toUpperCase(),
|
|
1061
|
+
url: req.url || '/',
|
|
1062
|
+
headers: req.headers,
|
|
1063
|
+
pathname: 'pathname' in req && req['pathname'] || urlInfo.pathname || '/',
|
|
1064
|
+
search: 'search' in req && req['search'] || urlInfo.search || '',
|
|
1065
|
+
query: 'query' in req && req['query'] || urlInfo.query || {},
|
|
1066
|
+
read: createRead(req)
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
async function sendResponse(res, target) {
|
|
1071
|
+
res.statusCode = target.statusCode;
|
|
1072
|
+
|
|
1073
|
+
for (const [k, v] of Object.entries(target.headers)) {
|
|
1074
|
+
res.setHeader(k, v);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
const stream = res instanceof Http2ServerResponse ? res.stream : res;
|
|
1078
|
+
|
|
1079
|
+
for await (const data of target) {
|
|
1080
|
+
if (res.finished) {
|
|
1081
|
+
break;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
if (stream.write(data)) {
|
|
1085
|
+
continue;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
await new Promise(cb => stream.once('drain', cb));
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
res.end();
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
function createHttpCallback(app, notFound) {
|
|
1095
|
+
if (notFound) {
|
|
1096
|
+
return async function httpCallback(req, res, next) {
|
|
1097
|
+
const r = await app.request(createRequest(req));
|
|
1098
|
+
|
|
1099
|
+
if (r) {
|
|
1100
|
+
return sendResponse(res, r);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
return notFound(req, res, next);
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
return async function httpCallback(req, res, next) {
|
|
1108
|
+
const r = await app.request(createRequest(req));
|
|
1109
|
+
|
|
1110
|
+
if (r) {
|
|
1111
|
+
return sendResponse(res, r);
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
if (next) {
|
|
1115
|
+
return next();
|
|
1116
|
+
}
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
/** 判断是否为文件 */
|
|
1121
|
+
|
|
1122
|
+
async function readdir(path) {
|
|
1123
|
+
return new Promise(resolve => fsFn.readdir(path, {
|
|
1124
|
+
encoding: 'utf-8'
|
|
1125
|
+
}, (err, files) => err ? resolve([]) : resolve(files)));
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
/** 判断是否为文件 */
|
|
1129
|
+
|
|
1130
|
+
async function isFile(path) {
|
|
1131
|
+
return new Promise((resolve, reject) => fsFn.stat(path, (err, stats) => err ? reject(err) : resolve(stats))).then(s => s.isFile()).catch(() => false);
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
const configFileNames = ['k99.config.js', '.k99.config.js', 'k99.config.json', '.k99.config.json'];
|
|
1135
|
+
/**
|
|
1136
|
+
* 从 npm 包目录中查找
|
|
1137
|
+
* @param id 相对 node_modules 的路径
|
|
1138
|
+
* @param parent 父配置
|
|
1139
|
+
*/
|
|
1140
|
+
|
|
1141
|
+
async function readConfig(path) {
|
|
1142
|
+
// TODO: 获取原始路径
|
|
1143
|
+
for (let f of configFileNames) {
|
|
1144
|
+
const file = pathFn.resolve(path, f);
|
|
1145
|
+
|
|
1146
|
+
if (!(await isFile(file))) {
|
|
1147
|
+
continue;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
const config = (await import(file)).default;
|
|
1151
|
+
|
|
1152
|
+
if (config && typeof config === 'object') {
|
|
1153
|
+
return { ...config,
|
|
1154
|
+
path
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
/**
|
|
1161
|
+
* 从 npm 包目录中查找
|
|
1162
|
+
* @param id 相对 node_modules 的路径
|
|
1163
|
+
* @param parent 父配置
|
|
1164
|
+
*/
|
|
1165
|
+
|
|
1166
|
+
async function find(path, id, plugins) {
|
|
1167
|
+
for (const modulePath of getModulePaths(path)) {
|
|
1168
|
+
const pluginPath = pathFn.resolve(modulePath, id);
|
|
1169
|
+
const config = plugins[pluginPath] || (await readConfig(pluginPath));
|
|
1170
|
+
|
|
1171
|
+
if (config) {
|
|
1172
|
+
return config;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
function* getModulePaths(path) {
|
|
1178
|
+
for (;;) {
|
|
1179
|
+
yield pathFn.resolve(path, 'node_modules');
|
|
1180
|
+
const p = pathFn.dirname(path);
|
|
1181
|
+
|
|
1182
|
+
if (p === path) {
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
path = p;
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
const idRegex = '[a-zA-Z][a-zA-Z0-9_-]*(?:.[a-zA-Z][a-zA-Z0-9_-]*)*';
|
|
1191
|
+
const nsPluginRegex = new RegExp(`^(?:@${idRegex}/)?${idRegex}$`);
|
|
1192
|
+
const pluginRegex = new RegExp(`^${idRegex}$`);
|
|
1193
|
+
function isNsPluginName(id) {
|
|
1194
|
+
if (!id) {
|
|
1195
|
+
return false;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
if (typeof id !== 'string') {
|
|
1199
|
+
return false;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
return pluginRegex.test(id) || nsPluginRegex.test(id);
|
|
1203
|
+
}
|
|
1204
|
+
function isPluginName(id) {
|
|
1205
|
+
if (!id) {
|
|
1206
|
+
return false;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
if (typeof id !== 'string') {
|
|
1210
|
+
return false;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
return pluginRegex.test(id);
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
function getName(config) {
|
|
1217
|
+
if (isPluginName(config.name)) {
|
|
1218
|
+
return config.name;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
const name = pathFn.basename(config.path);
|
|
1222
|
+
|
|
1223
|
+
if (isPluginName(name)) {
|
|
1224
|
+
return name;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
return '';
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
async function findSubPackages(plugin, configs, plugins) {
|
|
1231
|
+
if (plugin.packages) {
|
|
1232
|
+
for (let name of plugin.packages) {
|
|
1233
|
+
if (!isNsPluginName(name)) {
|
|
1234
|
+
// TODO: 抛出错误
|
|
1235
|
+
continue;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
if (name in plugins) {
|
|
1239
|
+
continue;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
const config = await find(plugin.path, name, configs);
|
|
1243
|
+
|
|
1244
|
+
if (!config) {
|
|
1245
|
+
// TODO: 抛出错误
|
|
1246
|
+
continue;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
plugins[name] = new FsPlugin(config, name);
|
|
1250
|
+
|
|
1251
|
+
if (config.path in configs) {
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
configs[config.path] = config;
|
|
1256
|
+
findSubPackages(config, configs, plugins);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
for (const path of plugin.plugins || []) {
|
|
1261
|
+
const pluginPath = pathFn.resolve(plugin.path, path);
|
|
1262
|
+
const config = await readConfig(pluginPath);
|
|
1263
|
+
|
|
1264
|
+
if (!config) {
|
|
1265
|
+
// TODO: 抛出错误
|
|
1266
|
+
continue;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
const name = getName(config);
|
|
1270
|
+
|
|
1271
|
+
if (!name) {
|
|
1272
|
+
// TODO: 抛出错误
|
|
1273
|
+
continue;
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
if (name in plugins) {
|
|
1277
|
+
// TODO: 抛出错误
|
|
1278
|
+
continue;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
plugins[name] = new FsPlugin(config, name);
|
|
1282
|
+
configs[config.path] = config;
|
|
1283
|
+
findSubPackages(config, configs, plugins);
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
async function start() {
|
|
1288
|
+
const cwd = process.cwd();
|
|
1289
|
+
/** 入口模块 */
|
|
1290
|
+
|
|
1291
|
+
const main = (await readConfig(process.cwd())) || {
|
|
1292
|
+
scan: 'plugins',
|
|
1293
|
+
path: cwd
|
|
1294
|
+
};
|
|
1295
|
+
const mainPlugin = new FsPlugin(main, '');
|
|
1296
|
+
/** 插件映射 */
|
|
1297
|
+
|
|
1298
|
+
const configs = Object.create(null);
|
|
1299
|
+
const plugins = Object.create(null);
|
|
1300
|
+
configs[cwd] = main; // 递归 npm 包插件
|
|
1301
|
+
|
|
1302
|
+
findSubPackages(main, configs, plugins);
|
|
1303
|
+
|
|
1304
|
+
if (main.scan) {
|
|
1305
|
+
const scanPath = pathFn.join(cwd, main.scan);
|
|
1306
|
+
|
|
1307
|
+
for (let name of await readdir(scanPath)) {
|
|
1308
|
+
if (!isPluginName(name)) {
|
|
1309
|
+
continue;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
if (name in plugins) {
|
|
1313
|
+
continue;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
const pluginPath = pathFn.resolve(cwd, name);
|
|
1317
|
+
const config = await readConfig(pluginPath);
|
|
1318
|
+
|
|
1319
|
+
if (!config) {
|
|
1320
|
+
continue;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
configs[config.path] = config;
|
|
1324
|
+
plugins[name] = new FsPlugin(config, name);
|
|
1325
|
+
await findSubPackages(config, configs, plugins);
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
for (const plugin of Object.values(plugins)) {
|
|
1330
|
+
await plugin.initRouter();
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
await mainPlugin.initRouter();
|
|
1334
|
+
const app = new NodeApp(mainPlugin, plugins);
|
|
1335
|
+
return app;
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
var K99Node = /*#__PURE__*/Object.freeze({
|
|
1339
|
+
__proto__: null,
|
|
1340
|
+
FsPlugin: FsPlugin,
|
|
1341
|
+
NodeApp: NodeApp,
|
|
1342
|
+
createHttpCallback: createHttpCallback,
|
|
1343
|
+
Scanner: Scanner,
|
|
1344
|
+
start: start,
|
|
1345
|
+
createFsAssetsApi: createFsAssetsApi,
|
|
1346
|
+
createFsLogApi: createFsLogApi,
|
|
1347
|
+
createFsSettingsApi: createFsSettingsApi
|
|
1348
|
+
});
|
|
1349
|
+
|
|
1350
|
+
export { FsPlugin, NodeApp, Scanner, createFsAssetsApi, createFsLogApi, createFsSettingsApi, createHttpCallback, K99Node as default, start };
|