mm_machine 2.1.1 → 2.1.3
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/.prettierrc +8 -0
- package/README.md +583 -576
- package/app/test1/config_demo.json +11 -8
- package/app/test1/demo.json +8 -8
- package/app/test1/index.js +14 -14
- package/app/test2/after.js +6 -6
- package/app/test2/config_demo.json +11 -8
- package/app/test2/demo.json +8 -8
- package/app/test2/index.js +1 -2
- package/app/test2/main.js +8 -8
- package/debug_config.js +37 -0
- package/debug_detailed.js +75 -0
- package/debug_test.js +65 -0
- package/demo/test1/config_demo.json +33 -33
- package/demo/test1/demo.json +33 -33
- package/demo/test1/index.js +19 -16
- package/demo/test2/after.js +9 -9
- package/demo/test2/config_demo.json +70 -68
- package/demo/test2/demo.json +70 -68
- package/demo/test2/index.js +9 -9
- package/demo/test2/main.js +9 -9
- package/demo2/test1/demo.json +33 -33
- package/demo2/test1/index.js +19 -16
- package/demo2/test2/after.js +9 -9
- package/demo2/test2/demo.json +70 -68
- package/demo2/test2/main.js +9 -9
- package/eslint.config.js +209 -0
- package/index.js +640 -571
- package/item.js +684 -589
- package/methods_documentation.md +15 -4
- package/nodemon.json +25 -26
- package/package.json +49 -39
- package/test +3 -0
- package/test.js +124 -107
- package/test.json +9 -0
package/item.js
CHANGED
|
@@ -1,589 +1,684 @@
|
|
|
1
|
-
require('
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
*
|
|
208
|
-
* @param {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
*
|
|
354
|
-
*/
|
|
355
|
-
Item.prototype.
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
*
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
*
|
|
511
|
-
*/
|
|
512
|
-
Item.prototype.
|
|
513
|
-
|
|
514
|
-
};
|
|
515
|
-
|
|
516
|
-
/**
|
|
517
|
-
*
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
1
|
+
const util = require('util');
|
|
2
|
+
const { conf } = require('mm_config');
|
|
3
|
+
const { HotReload } = require('mm_hot_reload');
|
|
4
|
+
|
|
5
|
+
// 初始化全局对象
|
|
6
|
+
if (typeof global.$ === 'undefined') {
|
|
7
|
+
global.$ = {};
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (!$.mod) {
|
|
11
|
+
$.mod = new HotReload();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 增强require函数,支持热更新
|
|
16
|
+
* @param {string} file 文件路径
|
|
17
|
+
* @param {Function} func 回调函数
|
|
18
|
+
* @returns {object} 加载的模块
|
|
19
|
+
*/
|
|
20
|
+
$.require = function (file, func) {
|
|
21
|
+
return $.mod.load(file, func);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 增强JSON加载函数,支持热更新
|
|
26
|
+
* @param {string} file 文件路径
|
|
27
|
+
* @param {Function} func 回调函数
|
|
28
|
+
* @returns {object} 解析的JSON对象
|
|
29
|
+
*/
|
|
30
|
+
$.loadJson = function (file, func) {
|
|
31
|
+
return $.mod.load(file, func);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 驱动基础类
|
|
36
|
+
* @class
|
|
37
|
+
*/
|
|
38
|
+
class Item {
|
|
39
|
+
/**
|
|
40
|
+
* 构造函数
|
|
41
|
+
* @param {string} dir 当前目录
|
|
42
|
+
* @param {string} dir_base 模块目录
|
|
43
|
+
* @class
|
|
44
|
+
*/
|
|
45
|
+
constructor(dir, dir_base) {
|
|
46
|
+
// 当前路径
|
|
47
|
+
this.dir = dir;
|
|
48
|
+
|
|
49
|
+
// 默认文件
|
|
50
|
+
this.default_file = './sys.json';
|
|
51
|
+
|
|
52
|
+
// 当前文件
|
|
53
|
+
this.filename = null;
|
|
54
|
+
|
|
55
|
+
// 配置参数
|
|
56
|
+
this.config = {
|
|
57
|
+
// 名称, 由中英文和下"_"组成, 用于卸载接口 例如: demo
|
|
58
|
+
name: '',
|
|
59
|
+
// 标题, 介绍作用
|
|
60
|
+
title: '',
|
|
61
|
+
// 描述, 用于描述该有什么用的
|
|
62
|
+
description: '',
|
|
63
|
+
// 文件路径, 当调用函数不存在时,会先从文件中加载
|
|
64
|
+
func_file: './index.js',
|
|
65
|
+
// 回调函数名 用于决定调用脚本的哪个函数
|
|
66
|
+
func_name: '',
|
|
67
|
+
// 排序
|
|
68
|
+
sort: 10,
|
|
69
|
+
// 状态, 0表示未启用, 1表示启用
|
|
70
|
+
state: 1,
|
|
71
|
+
// 显示, 0表示不显示, 1表示显示
|
|
72
|
+
show: 0
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// 模块目录
|
|
76
|
+
this.dir_base = dir_base;
|
|
77
|
+
|
|
78
|
+
// 模式: 1.生产模式 2.热更新模式 3.热重载模式 4.热更新+重载模式 5.重载模式
|
|
79
|
+
this.mode = 1;
|
|
80
|
+
|
|
81
|
+
// 加载完成
|
|
82
|
+
this.complete = false;
|
|
83
|
+
|
|
84
|
+
this._logger = $.log || console;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 日志输出
|
|
90
|
+
* @param {string} level - 日志级别(debug/info/warn/error)
|
|
91
|
+
* @param {string} message - 日志消息
|
|
92
|
+
* @param {...*} args - 可选参数
|
|
93
|
+
*/
|
|
94
|
+
Item.prototype.log = function (level, message, ...args) {
|
|
95
|
+
this._logger[level](`[${this.config.name}] ${message}`, ...args);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 设置配置
|
|
100
|
+
* @param {object} config 配置对象
|
|
101
|
+
* @returns {Promise<void>}
|
|
102
|
+
*/
|
|
103
|
+
Item.prototype.setConfig = async function (config) {
|
|
104
|
+
if (!config) return;
|
|
105
|
+
|
|
106
|
+
// 如果func_file改变,重置加载状态
|
|
107
|
+
if (config.func_file !== this.config.func_file) {
|
|
108
|
+
this.complete = false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 合并配置并应用配置处理
|
|
112
|
+
const result = await conf({ ...this.config, ...config }, this.filename);
|
|
113
|
+
this.config = result;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 设置配置后钩子方法
|
|
118
|
+
*/
|
|
119
|
+
Item.prototype.setConfigAfter = function () {
|
|
120
|
+
// 空实现,供子类重写
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 新建脚本文件
|
|
125
|
+
* @param {string} file 目标文件路径
|
|
126
|
+
*/
|
|
127
|
+
Item.prototype.newScript = function (file) {
|
|
128
|
+
const template_file = './script.js'.fullname(this.dir_base);
|
|
129
|
+
if (template_file.hasFile()) {
|
|
130
|
+
template_file.copyFile(file);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* 移除模块
|
|
136
|
+
* @param {object | string} module 模块对象或路径
|
|
137
|
+
*/
|
|
138
|
+
Item.prototype._remove = function (module) {
|
|
139
|
+
if (!module) return;
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
if (this.mode === 3 || this.mode === 4) {
|
|
143
|
+
// 移除模块和监听
|
|
144
|
+
$.mod.unload(module);
|
|
145
|
+
} else {
|
|
146
|
+
// 移除模块缓存
|
|
147
|
+
const filename = require.resolve(module);
|
|
148
|
+
if (require.cache[filename]) {
|
|
149
|
+
require.cache[filename] = null;
|
|
150
|
+
delete require.cache[filename];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
} catch (err) {
|
|
154
|
+
this.log('error', `移除模块失败: `, err);
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* 卸载脚本
|
|
160
|
+
* @param {string} file 脚本文件路径
|
|
161
|
+
*/
|
|
162
|
+
Item.prototype.unloadScript = function (file) {
|
|
163
|
+
let target_file = file;
|
|
164
|
+
if (!target_file) {
|
|
165
|
+
const func_file = this.config.func_file;
|
|
166
|
+
if (func_file) {
|
|
167
|
+
target_file = func_file.fullname(this.dir);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (target_file) {
|
|
172
|
+
this._remove(target_file);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
this.complete = false;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* 重新加载脚本
|
|
180
|
+
*/
|
|
181
|
+
Item.prototype.reloadScript = function () {
|
|
182
|
+
this.unloadScript();
|
|
183
|
+
this.loadScript();
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* 卸载钩子方法
|
|
188
|
+
*/
|
|
189
|
+
Item.prototype.unload = async function () {
|
|
190
|
+
// 空实现,供子类重写
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* 卸载之后处理
|
|
195
|
+
* @param {boolean} remove 是否删除文件
|
|
196
|
+
*/
|
|
197
|
+
Item.prototype.unloadAfter = async function (remove) {
|
|
198
|
+
// 删除脚本
|
|
199
|
+
this.unloadScript();
|
|
200
|
+
if (remove) {
|
|
201
|
+
this.removeFile();
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* 加载脚本
|
|
207
|
+
* @param {string} file 文件路径
|
|
208
|
+
* @param {string} name 函数名
|
|
209
|
+
* @returns {object | null} 返回加载的模块对象
|
|
210
|
+
*/
|
|
211
|
+
Item.prototype.loadScript = function (file, name = '') {
|
|
212
|
+
const target_file = this._getScriptFile(file);
|
|
213
|
+
if (!target_file) return null;
|
|
214
|
+
|
|
215
|
+
const target_name = this._getScriptName(name);
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
const cs = this._loadScript(target_file, target_name);
|
|
219
|
+
this._setMainMethod(cs, target_name);
|
|
220
|
+
return cs;
|
|
221
|
+
} catch (err) {
|
|
222
|
+
this.log('error', `加载脚本失败: `, err);
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* 获取脚本文件路径
|
|
229
|
+
* @param {string} file 文件路径
|
|
230
|
+
* @returns {string | null} 完整文件路径
|
|
231
|
+
*/
|
|
232
|
+
Item.prototype._getScriptFile = function (file) {
|
|
233
|
+
if (file) return file;
|
|
234
|
+
|
|
235
|
+
const func_file = this.config.func_file;
|
|
236
|
+
if (!func_file) return null;
|
|
237
|
+
|
|
238
|
+
const target_file = func_file.fullname(this.dir);
|
|
239
|
+
if (!target_file.hasFile()) {
|
|
240
|
+
this.newScript(target_file);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return target_file;
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* 获取脚本函数名
|
|
248
|
+
* @param {string} name 函数名
|
|
249
|
+
* @returns {string} 函数名
|
|
250
|
+
*/
|
|
251
|
+
Item.prototype._getScriptName = function (name) {
|
|
252
|
+
return name || this.config.func_name;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* 加载脚本模块
|
|
257
|
+
* @param {string} file 文件路径
|
|
258
|
+
* @param {string} name 函数名
|
|
259
|
+
* @returns {object | null} 模块对象
|
|
260
|
+
*/
|
|
261
|
+
Item.prototype._loadScript = function (file, name) {
|
|
262
|
+
if (this.mode === 3 || this.mode === 4) {
|
|
263
|
+
return $.require(file, this._handleHotReload.bind(this, name));
|
|
264
|
+
}
|
|
265
|
+
return require(file);
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* 处理热重载回调
|
|
270
|
+
* @param {string} name 函数名
|
|
271
|
+
* @param {object} loaded_module 加载的模块
|
|
272
|
+
* @param {string} change_type 变更类型
|
|
273
|
+
*/
|
|
274
|
+
Item.prototype._handleHotReload = function (name, loaded_module, change_type) {
|
|
275
|
+
if (change_type === 'change' && loaded_module) {
|
|
276
|
+
this._setMainMethod(loaded_module, name);
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* 设置主方法
|
|
282
|
+
* @param {object} module 模块对象
|
|
283
|
+
* @param {string} name 函数名
|
|
284
|
+
*/
|
|
285
|
+
Item.prototype._setMainMethod = function (module, name) {
|
|
286
|
+
if (!module) return;
|
|
287
|
+
|
|
288
|
+
if (name) {
|
|
289
|
+
if (module[name]) {
|
|
290
|
+
this.main = module[name];
|
|
291
|
+
}
|
|
292
|
+
} else if ($.push) {
|
|
293
|
+
$.push(this, module, true);
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* 新建配置文件
|
|
299
|
+
* @param {string} file 目标文件路径
|
|
300
|
+
*/
|
|
301
|
+
Item.prototype.newConfig = function (file) {
|
|
302
|
+
const template_file = './config.tpl.json'.fullname(this.dir_base);
|
|
303
|
+
template_file.copyFile(file);
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* 加载配置文件
|
|
308
|
+
* @param {string} file 文件路径
|
|
309
|
+
* @param {string} name 配置项名称
|
|
310
|
+
* @returns {object | null} 配置对象
|
|
311
|
+
*/
|
|
312
|
+
Item.prototype.loadFile = function (file, name) {
|
|
313
|
+
try {
|
|
314
|
+
const full_path = file.fullname(this.dir);
|
|
315
|
+
let text = full_path.loadText();
|
|
316
|
+
|
|
317
|
+
// 如果文件不存在,创建新的配置文件
|
|
318
|
+
if (!text) {
|
|
319
|
+
this.newConfig(full_path);
|
|
320
|
+
text = full_path.loadText();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (!text) return null;
|
|
324
|
+
|
|
325
|
+
const config = this._loadHotReload(full_path);
|
|
326
|
+
const final_config = this._findConfigByName(config, name);
|
|
327
|
+
|
|
328
|
+
// 更新目录和文件名引用
|
|
329
|
+
this.dir = full_path.dirname();
|
|
330
|
+
this.filename = full_path;
|
|
331
|
+
return final_config;
|
|
332
|
+
} catch (err) {
|
|
333
|
+
this.log('error', `加载配置文件失败: `, err);
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* 根据模式加载配置(支持热更新)
|
|
340
|
+
* @param {string} full_path 完整文件路径
|
|
341
|
+
* @returns {object | Array | null} 配置对象
|
|
342
|
+
*/
|
|
343
|
+
Item.prototype._loadHotReload = function (full_path) {
|
|
344
|
+
if (this.mode === 2 || this.mode === 3 || this.mode === 4) {
|
|
345
|
+
return $.loadJson(full_path, this._handleHotReload.bind(this));
|
|
346
|
+
}
|
|
347
|
+
return full_path.loadJson();
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* 处理热更新回调
|
|
352
|
+
* @param {object | Array} loaded_config 加载的配置
|
|
353
|
+
* @param {string} change_type 变更类型
|
|
354
|
+
*/
|
|
355
|
+
Item.prototype._handleHotReload = function (loaded_config, change_type) {
|
|
356
|
+
if (change_type !== 'change' || !loaded_config) return;
|
|
357
|
+
|
|
358
|
+
try {
|
|
359
|
+
const target_config = this._findConfigByName(loaded_config, this.config.name);
|
|
360
|
+
if (target_config) {
|
|
361
|
+
this.setConfig(target_config);
|
|
362
|
+
this.setConfigAfter();
|
|
363
|
+
this._reloadIfNeeded();
|
|
364
|
+
}
|
|
365
|
+
} catch (err) {
|
|
366
|
+
this.log('error', `配置热更新失败: `, err);
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* 根据名称在配置数组中查找配置项
|
|
372
|
+
* @param {object | Array} config 配置对象或数组
|
|
373
|
+
* @param {string} name 配置项名称
|
|
374
|
+
* @returns {object | null} 匹配的配置项
|
|
375
|
+
*/
|
|
376
|
+
Item.prototype._findConfigByName = function (config, name) {
|
|
377
|
+
if (!name || !Array.isArray(config)) return config;
|
|
378
|
+
return config.find((item) => item.name === name) || null;
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* 根据模式决定是否重新加载脚本
|
|
383
|
+
*/
|
|
384
|
+
Item.prototype._reloadIfNeeded = function () {
|
|
385
|
+
if (this.mode === 3 || this.mode === 4) {
|
|
386
|
+
this.reloadScript();
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* 删除目录
|
|
392
|
+
*/
|
|
393
|
+
Item.prototype.delDir = function () {
|
|
394
|
+
const func_file = this.config.func_file;
|
|
395
|
+
if (func_file && $.dir && $.dir.del) {
|
|
396
|
+
$.dir.del(this.dir);
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* 删除配置和脚本文件
|
|
402
|
+
* @returns {string | null} 错误消息,如果没有错误则返回null
|
|
403
|
+
*/
|
|
404
|
+
Item.prototype.removeFile = function () {
|
|
405
|
+
const name = this.config.name;
|
|
406
|
+
const file = this.filename;
|
|
407
|
+
|
|
408
|
+
let error_message = null;
|
|
409
|
+
try {
|
|
410
|
+
if (!file || !file.hasFile) return null;
|
|
411
|
+
|
|
412
|
+
if (!file.hasFile()) {
|
|
413
|
+
return '配置文件不存在';
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
error_message = this._removeConfigFile(file, name);
|
|
417
|
+
} catch (err) {
|
|
418
|
+
this.log('error', `删除文件失败: `, err);
|
|
419
|
+
error_message = `删除失败: ${err.message}`;
|
|
420
|
+
}
|
|
421
|
+
return error_message;
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* 删除配置文件
|
|
426
|
+
* @param {object} file 文件对象
|
|
427
|
+
* @param {string} name 配置名称
|
|
428
|
+
* @returns {string | null} 错误消息
|
|
429
|
+
*/
|
|
430
|
+
Item.prototype._removeConfigFile = function (file, name) {
|
|
431
|
+
const text = file.loadText();
|
|
432
|
+
if (!text) {
|
|
433
|
+
this.delDir();
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const config = text.toJson();
|
|
438
|
+
if (Array.isArray(config)) {
|
|
439
|
+
return this._removeArrayItem(file, config, name);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
this.delDir();
|
|
443
|
+
return null;
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* 从数组配置中删除指定项
|
|
448
|
+
* @param {object} file 文件对象
|
|
449
|
+
* @param {Array} config 配置数组
|
|
450
|
+
* @param {string} name 配置名称
|
|
451
|
+
* @returns {string | null} 错误消息
|
|
452
|
+
*/
|
|
453
|
+
Item.prototype._removeArrayItem = function (file, config, name) {
|
|
454
|
+
const index = config.findIndex((item) => item.name === name);
|
|
455
|
+
if (index === -1) return null;
|
|
456
|
+
|
|
457
|
+
this.delDir();
|
|
458
|
+
config.splice(index, 1);
|
|
459
|
+
|
|
460
|
+
if (config.length > 0) {
|
|
461
|
+
file.saveText(JSON.stringify(config, null, 4));
|
|
462
|
+
} else if (file.delFile) {
|
|
463
|
+
file.delFile();
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return null;
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* 载入配置
|
|
471
|
+
* @param {object | string} config_data 配置对象或配置路径
|
|
472
|
+
* @param {string} name 配置名称
|
|
473
|
+
*/
|
|
474
|
+
Item.prototype.loadConfig = async function (config_data, name) {
|
|
475
|
+
let config;
|
|
476
|
+
try {
|
|
477
|
+
if (config_data) {
|
|
478
|
+
if (typeof config_data === 'string') {
|
|
479
|
+
config = this.loadFile(config_data, name);
|
|
480
|
+
} else {
|
|
481
|
+
config = config_data;
|
|
482
|
+
}
|
|
483
|
+
} else {
|
|
484
|
+
config = this.loadFile(this.filename, name);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
await this.setConfig(config);
|
|
488
|
+
this.setConfigAfter();
|
|
489
|
+
} catch (err) {
|
|
490
|
+
this.log('error', `载入配置失败: `, err);
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* 加载前处理
|
|
496
|
+
*/
|
|
497
|
+
Item.prototype.loadBefore = async function () {
|
|
498
|
+
try {
|
|
499
|
+
const module = this.loadScript();
|
|
500
|
+
if (module) {
|
|
501
|
+
this.complete = true;
|
|
502
|
+
}
|
|
503
|
+
} catch (err) {
|
|
504
|
+
this.log('error', `加载前处理失败: `, err);
|
|
505
|
+
this.complete = false;
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* 加载处理
|
|
511
|
+
*/
|
|
512
|
+
Item.prototype.load = async function () {
|
|
513
|
+
// 空实现,供子类重写
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* 重载配置和脚本
|
|
518
|
+
*/
|
|
519
|
+
Item.prototype.reload = async function () {
|
|
520
|
+
await this.run('unload');
|
|
521
|
+
await this.run('load');
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* 保存配置
|
|
526
|
+
*/
|
|
527
|
+
Item.prototype.save = function () {
|
|
528
|
+
try {
|
|
529
|
+
if (!this.filename) return;
|
|
530
|
+
|
|
531
|
+
const full_path = this.filename.fullname(this.dir);
|
|
532
|
+
const text = full_path.loadText();
|
|
533
|
+
|
|
534
|
+
if (text && text.trim().startsWith('[')) {
|
|
535
|
+
// 数组格式配置
|
|
536
|
+
const config_array = text.toJson();
|
|
537
|
+
if (Array.isArray(config_array)) {
|
|
538
|
+
// 查找并更新现有配置项
|
|
539
|
+
const existing_index = config_array.findIndex((item) => item.name === this.config.name);
|
|
540
|
+
if (existing_index !== -1) {
|
|
541
|
+
config_array[existing_index] = this.config;
|
|
542
|
+
} else {
|
|
543
|
+
// 如果不存在,添加新配置项
|
|
544
|
+
config_array.push(this.config);
|
|
545
|
+
}
|
|
546
|
+
full_path.saveText(JSON.stringify(config_array, null, 4));
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// 单对象格式配置,直接保存
|
|
552
|
+
full_path.saveText(JSON.stringify(this.config, null, 4));
|
|
553
|
+
} catch (err) {
|
|
554
|
+
this.log('error', `保存配置失败: `, err);
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* 主要执行函数
|
|
560
|
+
* @param {*} _params 参数集合
|
|
561
|
+
* @returns {Promise<any>} 执行结果
|
|
562
|
+
*/
|
|
563
|
+
Item.prototype.main = async function (..._params) {
|
|
564
|
+
// 空实现,供子类重写
|
|
565
|
+
return null;
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* 运行主函数
|
|
570
|
+
* @param {*} params 参数集合
|
|
571
|
+
* @returns {Promise<any>} 执行结果
|
|
572
|
+
*/
|
|
573
|
+
Item.prototype.run = async function (...params) {
|
|
574
|
+
return await this.exec('main', ...params);
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* 调用函数(核心执行方法)
|
|
579
|
+
* @param {string} method 函数名
|
|
580
|
+
* @param {*} params 参数集合
|
|
581
|
+
* @returns {Promise<any>} 执行结果
|
|
582
|
+
*/
|
|
583
|
+
Item.prototype.exec = async function (method, ...params) {
|
|
584
|
+
const method_func = this._getMethod(method);
|
|
585
|
+
if (!method_func) return null;
|
|
586
|
+
|
|
587
|
+
let result;
|
|
588
|
+
|
|
589
|
+
try {
|
|
590
|
+
result = await this._execBefore(method, params);
|
|
591
|
+
result = await this._execMain(method_func, params, result);
|
|
592
|
+
result = await this._execAfter(method, params, result);
|
|
593
|
+
} catch (err) {
|
|
594
|
+
this.log('error', `执行方法 ${method} 失败: `, err);
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
return result;
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* 获取方法函数
|
|
603
|
+
* @param {string} method 方法名
|
|
604
|
+
* @returns {Function|null} 方法函数
|
|
605
|
+
*/
|
|
606
|
+
Item.prototype._getMethod = function (method) {
|
|
607
|
+
let method_func = this._mod && this._mod[method];
|
|
608
|
+
if (!method_func) {
|
|
609
|
+
method_func = this[method];
|
|
610
|
+
}
|
|
611
|
+
return method_func || null;
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* 执行前置钩子
|
|
616
|
+
* @param {string} method 方法名
|
|
617
|
+
* @param {Array} params 参数
|
|
618
|
+
* @returns {Promise<any>} 前置钩子结果
|
|
619
|
+
*/
|
|
620
|
+
Item.prototype._execBefore = async function (method, params) {
|
|
621
|
+
const before_method = `${method}Before`;
|
|
622
|
+
const before_func = this._getMethod(before_method);
|
|
623
|
+
|
|
624
|
+
if (!before_func) return undefined;
|
|
625
|
+
|
|
626
|
+
try {
|
|
627
|
+
let result = before_func.call(this._mod || this, ...params);
|
|
628
|
+
if (util.types.isPromise(result)) {
|
|
629
|
+
result = await result;
|
|
630
|
+
}
|
|
631
|
+
return result;
|
|
632
|
+
} catch (err) {
|
|
633
|
+
this.log('error', `执行前置钩子 ${before_method} 失败: `, err);
|
|
634
|
+
return undefined;
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* 执行主方法
|
|
640
|
+
* @param {Function} method_func 方法函数
|
|
641
|
+
* @param {Array} params 参数
|
|
642
|
+
* @param {any} before_result 前置钩子结果
|
|
643
|
+
* @returns {Promise<any>} 主方法结果
|
|
644
|
+
*/
|
|
645
|
+
Item.prototype._execMain = async function (method_func, params, before_result) {
|
|
646
|
+
const method_result = method_func.call(this._mod || this, ...params);
|
|
647
|
+
const result = util.types.isPromise(method_result) ? await method_result : method_result;
|
|
648
|
+
return result;
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* 执行后置钩子
|
|
653
|
+
* @param {string} method 方法名
|
|
654
|
+
* @param {Array} params 参数
|
|
655
|
+
* @param {any} main_result 主方法结果
|
|
656
|
+
* @returns {Promise<any>} 后置钩子结果
|
|
657
|
+
*/
|
|
658
|
+
Item.prototype._execAfter = async function (method, params, main_result) {
|
|
659
|
+
const after_method = `${method}After`;
|
|
660
|
+
const after_func = this._getMethod(after_method);
|
|
661
|
+
|
|
662
|
+
if (!after_func) return main_result;
|
|
663
|
+
|
|
664
|
+
try {
|
|
665
|
+
const after_result = after_func.call(this._mod || this, main_result, ...params);
|
|
666
|
+
|
|
667
|
+
if (util.types.isPromise(after_result)) {
|
|
668
|
+
const resolved_result = await after_result;
|
|
669
|
+
return resolved_result !== undefined ? resolved_result : main_result;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
return after_result !== undefined ? after_result : main_result;
|
|
673
|
+
} catch (err) {
|
|
674
|
+
this.log('error', `执行后置钩子 ${after_method} 失败: `, err);
|
|
675
|
+
return main_result;
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* @module 导出Item类
|
|
681
|
+
*/
|
|
682
|
+
module.exports = {
|
|
683
|
+
Item
|
|
684
|
+
};
|