monocart-coverage-reports 2.5.9 → 2.6.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/lib/utils/util.js CHANGED
@@ -1,526 +1,526 @@
1
- const fs = require('fs');
2
- const { writeFile, readFile } = require('fs/promises');
3
- const path = require('path');
4
- const { pathToFileURL } = require('url');
5
- const os = require('os');
6
- const crypto = require('crypto');
7
- const EC = require('eight-colors');
8
- const CG = require('console-grid');
9
- const Share = require('../platform/share.js');
10
- const request = require('./request.js');
11
- const { deflateSync } = require('lz-utils');
12
-
13
- const { acornWalk, supportsColor } = require('../packages/monocart-coverage-vendor.js');
14
-
15
- // https://github.com/chalk/supports-color
16
- // disabled color if Terminal stdout does not support color
17
- if (!supportsColor.stdout) {
18
- EC.disabled = true;
19
- }
20
-
21
- const Util = {
22
- ... Share,
23
-
24
- EC,
25
- CG,
26
-
27
- root: process.cwd(),
28
-
29
- request,
30
-
31
- relativePath: function(p, root) {
32
- p = `${p}`;
33
- root = `${root || Util.root}`;
34
- let rp = path.relative(root, p);
35
- rp = Util.formatPath(rp);
36
- return rp;
37
- },
38
-
39
- replace: function(str, obj, defaultValue) {
40
- str = `${str}`;
41
- if (!obj) {
42
- return str;
43
- }
44
- str = str.replace(/\{([^}{]+)\}/g, function(match, key) {
45
- if (!Util.hasOwn(obj, key)) {
46
- if (typeof (defaultValue) !== 'undefined') {
47
- return defaultValue;
48
- }
49
- return match;
50
- }
51
- let val = obj[key];
52
- if (typeof (val) === 'function') {
53
- val = val(obj, key);
54
- }
55
- if (typeof (val) === 'undefined') {
56
- val = '';
57
- }
58
- return val;
59
- });
60
- return str;
61
- },
62
-
63
- calculateSha1: (buffer) => {
64
- const hash = crypto.createHash('sha1');
65
- hash.update(buffer);
66
- return hash.digest('hex');
67
- },
68
-
69
- checkCoverageData: (data) => {
70
- if (!data) {
71
- return false;
72
- }
73
- if (Array.isArray(data) && data.length) {
74
- return true;
75
- }
76
- if (Object.keys(data).length) {
77
- return true;
78
- }
79
- return false;
80
- },
81
-
82
- resolveUrl: (input, base) => {
83
- let url;
84
- try {
85
- url = new URL(input, base);
86
- } catch (e) {
87
- // console.error('error url', input);
88
- return;
89
- }
90
- return url;
91
- },
92
-
93
- resolveCacheSourcePath: (cacheDir, id) => {
94
- const filename = `source-${id}.json`;
95
- const sourcePath = path.resolve(cacheDir, filename);
96
- return sourcePath;
97
- },
98
-
99
- resolveWatermarks: (defaultWatermarks, watermarks) => {
100
- if (watermarks) {
101
- if (Array.isArray(watermarks)) {
102
- Object.keys(defaultWatermarks).forEach((k) => {
103
- defaultWatermarks[k] = watermarks;
104
- });
105
- } else {
106
- Object.assign(defaultWatermarks, watermarks);
107
- }
108
- }
109
- return defaultWatermarks;
110
- },
111
-
112
- resolveReportPath: (options, htmlPathHandler) => {
113
-
114
- let reportPath = options.reportPath;
115
- if (typeof reportPath === 'function') {
116
- reportPath = reportPath();
117
- }
118
-
119
- if (typeof reportPath === 'string') {
120
- if (reportPath) {
121
- const p = path.resolve(options.outputDir, reportPath);
122
- return Util.relativePath(p);
123
- }
124
- // empty
125
- return reportPath;
126
- }
127
- // using default html path as report path
128
- return htmlPathHandler();
129
- },
130
-
131
- resolveNodeModule: (p) => {
132
-
133
- // root
134
- const cwd = path.resolve('node_modules', p);
135
- if (fs.existsSync(cwd)) {
136
- return cwd;
137
- }
138
-
139
- // sub node modules
140
- const sub = path.resolve(__dirname, '../../node_modules', p);
141
- if (fs.existsSync(sub)) {
142
- return sub;
143
- }
144
-
145
- // same level dep
146
- const dep = path.resolve(__dirname, '../../../', p);
147
- if (fs.existsSync(dep)) {
148
- return dep;
149
- }
150
-
151
- Util.logError(`Not found module: ${p}`);
152
-
153
- return cwd;
154
- },
155
-
156
- resolvePackage: (p) => {
157
- return path.resolve(__dirname, '../packages', p);
158
- },
159
-
160
- saveHtmlReport: async (options) => {
161
-
162
- const {
163
- inline,
164
- reportData,
165
- jsFiles,
166
- assetsPath,
167
- outputDir,
168
- htmlFile,
169
-
170
- reportDataFile
171
- } = options;
172
-
173
- // report data
174
- const reportDataCompressed = deflateSync(JSON.stringify(reportData));
175
- const reportDataStr = `window.reportData = '${reportDataCompressed}';`;
176
-
177
- // js libs
178
- const jsList = [];
179
- for (const jsFile of jsFiles) {
180
- const jsStr = await Util.readFile(jsFile);
181
- jsList.push({
182
- filename: path.basename(jsFile),
183
- str: jsStr
184
- });
185
- }
186
-
187
- // html content
188
- let htmlStr = '';
189
- const EOL = Util.getEOL();
190
- if (inline) {
191
- htmlStr = [
192
- '<script>',
193
- reportDataStr,
194
- ... jsList.map((it) => it.str),
195
- '</script>'
196
- ].join(EOL);
197
- } else {
198
-
199
- await Util.writeFile(path.resolve(outputDir, reportDataFile), reportDataStr);
200
-
201
- const assetsDir = path.resolve(outputDir, assetsPath);
202
- const relAssetsDir = Util.relativePath(assetsDir, outputDir);
203
-
204
- for (const item of jsList) {
205
- const filePath = path.resolve(assetsDir, item.filename);
206
- if (!fs.existsSync(filePath)) {
207
- await Util.writeFile(filePath, item.str);
208
- }
209
- }
210
-
211
- htmlStr = [
212
- `<script src="${reportDataFile}"></script>`,
213
- ... jsList.map((it) => `<script src="${relAssetsDir}/${it.filename}"></script>`)
214
- ].join(EOL);
215
- }
216
-
217
- // html
218
- const htmlPath = path.resolve(outputDir, htmlFile);
219
- const template = Util.getTemplate(path.resolve(__dirname, '../default/template.html'));
220
- const html = Util.replace(template, {
221
- title: reportData.title,
222
- content: htmlStr
223
- });
224
-
225
- await Util.writeFile(htmlPath, html);
226
-
227
- return Util.relativePath(htmlPath);
228
- },
229
-
230
- runCustomReporter: async (reportName, reportData, reportOptions, globalOptions) => {
231
- let CustomReporter;
232
- let err;
233
- try {
234
- CustomReporter = await import(reportName);
235
- } catch (e) {
236
- err = e;
237
- try {
238
- CustomReporter = await import(pathToFileURL(reportName));
239
- } catch (ee) {
240
- err = ee;
241
- }
242
- }
243
-
244
- if (!CustomReporter) {
245
- Util.logError(err.message);
246
- return;
247
- }
248
-
249
- CustomReporter = CustomReporter.default || CustomReporter;
250
-
251
- const reporter = new CustomReporter(reportOptions, globalOptions);
252
-
253
- const results = await reporter.generate(reportData);
254
-
255
- return results;
256
- },
257
-
258
- getEOL: function(content) {
259
- if (!content) {
260
- return os.EOL;
261
- }
262
- const nIndex = content.lastIndexOf('\n');
263
- if (nIndex === -1) {
264
- return os.EOL;
265
- }
266
- if (content.substr(nIndex - 1, 1) === '\r') {
267
- return '\r\n';
268
- }
269
- return '\n';
270
- },
271
-
272
- visitAst: (rootNode, visitors) => {
273
- const baseVisitor = acornWalk.base;
274
- const parents = [rootNode];
275
- const visitor = (node, st, override) => {
276
- const type = override || node.type;
277
- // console.log('visit', node.type, override, parents.length);
278
- const handler = visitors[type];
279
- if (handler) {
280
- const res = handler(node, parents);
281
- if (res === 'break') {
282
- return;
283
- }
284
- }
285
- const isNew = node !== parents[parents.length - 1];
286
- if (isNew) {
287
- parents.push(node);
288
- }
289
- baseVisitor[type](node, st, visitor);
290
- if (isNew) {
291
- parents.pop();
292
- }
293
- };
294
- visitor(rootNode);
295
- },
296
-
297
- updateOffsetToLocation: (locator, loc) => {
298
- const sLoc = locator.offsetToLocation(loc.start);
299
- loc.start = {
300
- line: sLoc.line,
301
- column: sLoc.column
302
- };
303
- const eLoc = locator.offsetToLocation(loc.end);
304
- loc.end = {
305
- line: eLoc.line,
306
- column: eLoc.column
307
- };
308
- },
309
-
310
- forEachFile: function(dir, extList, callback) {
311
- if (!fs.existsSync(dir)) {
312
- return;
313
- }
314
- // all exts, full name, ext
315
- const isMatched = (name) => !Util.isList(extList) || extList.includes(name) || extList.includes(path.extname(name));
316
- const subDirs = [];
317
- const subDirHandler = () => {
318
- if (!subDirs.length) {
319
- return;
320
- }
321
-
322
- for (const subDir of subDirs) {
323
- const res = Util.forEachFile(subDir, extList, callback);
324
- if (res === 'break') {
325
- return;
326
- }
327
- }
328
- };
329
-
330
- const list = fs.readdirSync(dir);
331
- for (const name of list) {
332
- const abs = path.resolve(dir, name);
333
- const info = fs.statSync(abs);
334
- if (info.isDirectory()) {
335
- subDirs.push(abs);
336
- continue;
337
- }
338
-
339
- if (info.isFile() && isMatched(name)) {
340
- const res = callback(name, dir);
341
- if (res === 'break') {
342
- return;
343
- }
344
- }
345
-
346
- }
347
-
348
- subDirHandler();
349
-
350
- },
351
-
352
- readFileSync: function(filePath) {
353
- if (fs.existsSync(filePath)) {
354
- // Returns: <string> | <Buffer>
355
- const buf = fs.readFileSync(filePath);
356
- if (Buffer.isBuffer(buf)) {
357
- return buf.toString('utf8');
358
- }
359
- return buf;
360
- }
361
- },
362
-
363
- readFile: async (filePath) => {
364
- if (fs.existsSync(filePath)) {
365
- const buf = await readFile(filePath).catch((e) => {
366
- Util.logError(`read file: ${filePath} ${e.message || e}`);
367
- });
368
- if (Buffer.isBuffer(buf)) {
369
- return buf.toString('utf8');
370
- }
371
- return buf;
372
- }
373
- },
374
-
375
- writeFileSync: function(filePath, content) {
376
- if (!fs.existsSync(filePath)) {
377
- const p = path.dirname(filePath);
378
- if (!fs.existsSync(p)) {
379
- fs.mkdirSync(p, {
380
- recursive: true
381
- });
382
- }
383
- }
384
- fs.writeFileSync(filePath, content);
385
- },
386
-
387
- writeFile: async (filePath, content) => {
388
- if (!fs.existsSync(filePath)) {
389
- const p = path.dirname(filePath);
390
- if (!fs.existsSync(p)) {
391
- fs.mkdirSync(p, {
392
- recursive: true
393
- });
394
- }
395
- }
396
- await writeFile(filePath, content).catch((e) => {
397
- Util.logError(`write file: ${filePath} ${e.message || e}`);
398
- });
399
- },
400
-
401
- rmSync: (p) => {
402
- if (!fs.existsSync(p)) {
403
- return;
404
- }
405
- try {
406
- fs.rmSync(p, {
407
- recursive: true,
408
- force: true,
409
- maxRetries: 10
410
- });
411
- } catch (err) {
412
- console.log(err.message);
413
- }
414
- },
415
-
416
- getTemplate: function(templatePath) {
417
- if (!Util.templateCache) {
418
- Util.templateCache = {};
419
- }
420
- let template = Util.templateCache[templatePath];
421
- if (!template) {
422
- template = Util.readFileSync(templatePath);
423
- if (template) {
424
- Util.templateCache[templatePath] = template;
425
- } else {
426
- Util.logError(`not found template: ${templatePath}`);
427
- }
428
- }
429
- return template;
430
- },
431
-
432
- getColorStrByStatus: (str, status) => {
433
- if (status === 'low') {
434
- return EC.red(str);
435
- }
436
- if (status === 'medium') {
437
- return EC.yellow(str);
438
- }
439
- if (status === 'high') {
440
- return EC.green(str);
441
- }
442
- return str;
443
- },
444
-
445
- // ==========================================================================================
446
-
447
- loggingLevels: {
448
- off: 0,
449
- error: 10,
450
- info: 20,
451
- debug: 30
452
- },
453
-
454
- isDebug: () => {
455
- return Util.loggingType === 'debug';
456
- },
457
-
458
- initLoggingLevel: (level) => {
459
-
460
- const types = {
461
- off: 'off',
462
- error: 'error',
463
- info: 'info',
464
- debug: 'debug'
465
- };
466
- const type = types[level] || types.info;
467
- Util.loggingType = type;
468
- Util.loggingLevel = Util.loggingLevels[type];
469
-
470
- // console.log('=========================================');
471
- // console.log(from, Util.loggingType, Util.loggingLevel);
472
-
473
- return type;
474
- },
475
-
476
- logError: (message) => {
477
- if (Util.loggingLevel < Util.loggingLevels.error) {
478
- return;
479
- }
480
- EC.logRed(`[MCR] ${message}`);
481
- },
482
-
483
- logInfo: (message) => {
484
- if (Util.loggingLevel < Util.loggingLevels.info) {
485
- return;
486
- }
487
- console.log(`[MCR] ${message}`);
488
- },
489
-
490
- // grid is info level
491
- logGrid: (gridData) => {
492
- if (Util.loggingLevel < Util.loggingLevels.info) {
493
- return;
494
- }
495
- CG(gridData);
496
- },
497
-
498
- logDebug: (message) => {
499
- if (Util.loggingLevel < Util.loggingLevels.debug) {
500
- return;
501
- }
502
- console.log(`[MCR] ${message}`);
503
- },
504
-
505
- // time is debug level, fix the log info, for checking snapshot
506
- logTime: (message, time_start) => {
507
- if (Util.loggingLevel < Util.loggingLevels.debug) {
508
- return;
509
- }
510
- const duration = Date.now() - time_start;
511
- const durationH = Util.TSF(duration);
512
- const ls = [`[MCR] ${message}`, ' ('];
513
- if (duration <= 100) {
514
- ls.push(EC.green(durationH));
515
- } else if (duration < 500) {
516
- ls.push(EC.yellow(durationH));
517
- } else {
518
- ls.push(EC.red(durationH));
519
- }
520
- ls.push(')');
521
- console.log(ls.join(''));
522
- }
523
-
524
- };
525
-
526
- module.exports = Util;
1
+ const fs = require('fs');
2
+ const { writeFile, readFile } = require('fs/promises');
3
+ const path = require('path');
4
+ const { pathToFileURL } = require('url');
5
+ const os = require('os');
6
+ const crypto = require('crypto');
7
+ const EC = require('eight-colors');
8
+ const CG = require('console-grid');
9
+ const Share = require('../platform/share.js');
10
+ const request = require('./request.js');
11
+ const { deflateSync } = require('lz-utils');
12
+
13
+ const { acornWalk, supportsColor } = require('../packages/monocart-coverage-vendor.js');
14
+
15
+ // https://github.com/chalk/supports-color
16
+ // disabled color if Terminal stdout does not support color
17
+ if (!supportsColor.stdout) {
18
+ EC.disabled = true;
19
+ }
20
+
21
+ const Util = {
22
+ ... Share,
23
+
24
+ EC,
25
+ CG,
26
+
27
+ root: process.cwd(),
28
+
29
+ request,
30
+
31
+ relativePath: function(p, root) {
32
+ p = `${p}`;
33
+ root = `${root || Util.root}`;
34
+ let rp = path.relative(root, p);
35
+ rp = Util.formatPath(rp);
36
+ return rp;
37
+ },
38
+
39
+ replace: function(str, obj, defaultValue) {
40
+ str = `${str}`;
41
+ if (!obj) {
42
+ return str;
43
+ }
44
+ str = str.replace(/\{([^}{]+)\}/g, function(match, key) {
45
+ if (!Util.hasOwn(obj, key)) {
46
+ if (typeof (defaultValue) !== 'undefined') {
47
+ return defaultValue;
48
+ }
49
+ return match;
50
+ }
51
+ let val = obj[key];
52
+ if (typeof (val) === 'function') {
53
+ val = val(obj, key);
54
+ }
55
+ if (typeof (val) === 'undefined') {
56
+ val = '';
57
+ }
58
+ return val;
59
+ });
60
+ return str;
61
+ },
62
+
63
+ calculateSha1: (buffer) => {
64
+ const hash = crypto.createHash('sha1');
65
+ hash.update(buffer);
66
+ return hash.digest('hex');
67
+ },
68
+
69
+ checkCoverageData: (data) => {
70
+ if (!data) {
71
+ return false;
72
+ }
73
+ if (Array.isArray(data) && data.length) {
74
+ return true;
75
+ }
76
+ if (Object.keys(data).length) {
77
+ return true;
78
+ }
79
+ return false;
80
+ },
81
+
82
+ resolveUrl: (input, base) => {
83
+ let url;
84
+ try {
85
+ url = new URL(input, base);
86
+ } catch (e) {
87
+ // console.error('error url', input);
88
+ return;
89
+ }
90
+ return url;
91
+ },
92
+
93
+ resolveCacheSourcePath: (cacheDir, id) => {
94
+ const filename = `source-${id}.json`;
95
+ const sourcePath = path.resolve(cacheDir, filename);
96
+ return sourcePath;
97
+ },
98
+
99
+ resolveWatermarks: (defaultWatermarks, watermarks) => {
100
+ if (watermarks) {
101
+ if (Array.isArray(watermarks)) {
102
+ Object.keys(defaultWatermarks).forEach((k) => {
103
+ defaultWatermarks[k] = watermarks;
104
+ });
105
+ } else {
106
+ Object.assign(defaultWatermarks, watermarks);
107
+ }
108
+ }
109
+ return defaultWatermarks;
110
+ },
111
+
112
+ resolveReportPath: (options, htmlPathHandler) => {
113
+
114
+ let reportPath = options.reportPath;
115
+ if (typeof reportPath === 'function') {
116
+ reportPath = reportPath();
117
+ }
118
+
119
+ if (typeof reportPath === 'string') {
120
+ if (reportPath) {
121
+ const p = path.resolve(options.outputDir, reportPath);
122
+ return Util.relativePath(p);
123
+ }
124
+ // empty
125
+ return reportPath;
126
+ }
127
+ // using default html path as report path
128
+ return htmlPathHandler();
129
+ },
130
+
131
+ resolveNodeModule: (p) => {
132
+
133
+ // root
134
+ const cwd = path.resolve('node_modules', p);
135
+ if (fs.existsSync(cwd)) {
136
+ return cwd;
137
+ }
138
+
139
+ // sub node modules
140
+ const sub = path.resolve(__dirname, '../../node_modules', p);
141
+ if (fs.existsSync(sub)) {
142
+ return sub;
143
+ }
144
+
145
+ // same level dep
146
+ const dep = path.resolve(__dirname, '../../../', p);
147
+ if (fs.existsSync(dep)) {
148
+ return dep;
149
+ }
150
+
151
+ Util.logError(`Not found module: ${p}`);
152
+
153
+ return cwd;
154
+ },
155
+
156
+ resolvePackage: (p) => {
157
+ return path.resolve(__dirname, '../packages', p);
158
+ },
159
+
160
+ saveHtmlReport: async (options) => {
161
+
162
+ const {
163
+ inline,
164
+ reportData,
165
+ jsFiles,
166
+ assetsPath,
167
+ outputDir,
168
+ htmlFile,
169
+
170
+ reportDataFile
171
+ } = options;
172
+
173
+ // report data
174
+ const reportDataCompressed = deflateSync(JSON.stringify(reportData));
175
+ const reportDataStr = `window.reportData = '${reportDataCompressed}';`;
176
+
177
+ // js libs
178
+ const jsList = [];
179
+ for (const jsFile of jsFiles) {
180
+ const jsStr = await Util.readFile(jsFile);
181
+ jsList.push({
182
+ filename: path.basename(jsFile),
183
+ str: jsStr
184
+ });
185
+ }
186
+
187
+ // html content
188
+ let htmlStr = '';
189
+ const EOL = Util.getEOL();
190
+ if (inline) {
191
+ htmlStr = [
192
+ '<script>',
193
+ reportDataStr,
194
+ ... jsList.map((it) => it.str),
195
+ '</script>'
196
+ ].join(EOL);
197
+ } else {
198
+
199
+ await Util.writeFile(path.resolve(outputDir, reportDataFile), reportDataStr);
200
+
201
+ const assetsDir = path.resolve(outputDir, assetsPath);
202
+ const relAssetsDir = Util.relativePath(assetsDir, outputDir);
203
+
204
+ for (const item of jsList) {
205
+ const filePath = path.resolve(assetsDir, item.filename);
206
+ if (!fs.existsSync(filePath)) {
207
+ await Util.writeFile(filePath, item.str);
208
+ }
209
+ }
210
+
211
+ htmlStr = [
212
+ `<script src="${reportDataFile}"></script>`,
213
+ ... jsList.map((it) => `<script src="${relAssetsDir}/${it.filename}"></script>`)
214
+ ].join(EOL);
215
+ }
216
+
217
+ // html
218
+ const htmlPath = path.resolve(outputDir, htmlFile);
219
+ const template = Util.getTemplate(path.resolve(__dirname, '../default/template.html'));
220
+ const html = Util.replace(template, {
221
+ title: reportData.title,
222
+ content: htmlStr
223
+ });
224
+
225
+ await Util.writeFile(htmlPath, html);
226
+
227
+ return Util.relativePath(htmlPath);
228
+ },
229
+
230
+ runCustomReporter: async (reportName, reportData, reportOptions, globalOptions) => {
231
+ let CustomReporter;
232
+ let err;
233
+ try {
234
+ CustomReporter = await import(reportName);
235
+ } catch (e) {
236
+ err = e;
237
+ try {
238
+ CustomReporter = await import(pathToFileURL(reportName));
239
+ } catch (ee) {
240
+ err = ee;
241
+ }
242
+ }
243
+
244
+ if (!CustomReporter) {
245
+ Util.logError(err.message);
246
+ return;
247
+ }
248
+
249
+ CustomReporter = CustomReporter.default || CustomReporter;
250
+
251
+ const reporter = new CustomReporter(reportOptions, globalOptions);
252
+
253
+ const results = await reporter.generate(reportData);
254
+
255
+ return results;
256
+ },
257
+
258
+ getEOL: function(content) {
259
+ if (!content) {
260
+ return os.EOL;
261
+ }
262
+ const nIndex = content.lastIndexOf('\n');
263
+ if (nIndex === -1) {
264
+ return os.EOL;
265
+ }
266
+ if (content.substr(nIndex - 1, 1) === '\r') {
267
+ return '\r\n';
268
+ }
269
+ return '\n';
270
+ },
271
+
272
+ visitAst: (rootNode, visitors) => {
273
+ const baseVisitor = acornWalk.base;
274
+ const parents = [rootNode];
275
+ const visitor = (node, st, override) => {
276
+ const type = override || node.type;
277
+ // console.log('visit', node.type, override, parents.length);
278
+ const handler = visitors[type];
279
+ if (handler) {
280
+ const res = handler(node, parents);
281
+ if (res === 'break') {
282
+ return;
283
+ }
284
+ }
285
+ const isNew = node !== parents[parents.length - 1];
286
+ if (isNew) {
287
+ parents.push(node);
288
+ }
289
+ baseVisitor[type](node, st, visitor);
290
+ if (isNew) {
291
+ parents.pop();
292
+ }
293
+ };
294
+ visitor(rootNode);
295
+ },
296
+
297
+ updateOffsetToLocation: (locator, loc) => {
298
+ const sLoc = locator.offsetToLocation(loc.start);
299
+ loc.start = {
300
+ line: sLoc.line,
301
+ column: sLoc.column
302
+ };
303
+ const eLoc = locator.offsetToLocation(loc.end);
304
+ loc.end = {
305
+ line: eLoc.line,
306
+ column: eLoc.column
307
+ };
308
+ },
309
+
310
+ forEachFile: function(dir, extList, callback) {
311
+ if (!fs.existsSync(dir)) {
312
+ return;
313
+ }
314
+ // all exts, full name, ext
315
+ const isMatched = (name) => !Util.isList(extList) || extList.includes(name) || extList.includes(path.extname(name));
316
+ const subDirs = [];
317
+ const subDirHandler = () => {
318
+ if (!subDirs.length) {
319
+ return;
320
+ }
321
+
322
+ for (const subDir of subDirs) {
323
+ const res = Util.forEachFile(subDir, extList, callback);
324
+ if (res === 'break') {
325
+ return;
326
+ }
327
+ }
328
+ };
329
+
330
+ const list = fs.readdirSync(dir);
331
+ for (const name of list) {
332
+ const abs = path.resolve(dir, name);
333
+ const info = fs.statSync(abs);
334
+ if (info.isDirectory()) {
335
+ subDirs.push(abs);
336
+ continue;
337
+ }
338
+
339
+ if (info.isFile() && isMatched(name)) {
340
+ const res = callback(name, dir);
341
+ if (res === 'break') {
342
+ return;
343
+ }
344
+ }
345
+
346
+ }
347
+
348
+ subDirHandler();
349
+
350
+ },
351
+
352
+ readFileSync: function(filePath) {
353
+ if (fs.existsSync(filePath)) {
354
+ // Returns: <string> | <Buffer>
355
+ const buf = fs.readFileSync(filePath);
356
+ if (Buffer.isBuffer(buf)) {
357
+ return buf.toString('utf8');
358
+ }
359
+ return buf;
360
+ }
361
+ },
362
+
363
+ readFile: async (filePath) => {
364
+ if (fs.existsSync(filePath)) {
365
+ const buf = await readFile(filePath).catch((e) => {
366
+ Util.logError(`read file: ${filePath} ${e.message || e}`);
367
+ });
368
+ if (Buffer.isBuffer(buf)) {
369
+ return buf.toString('utf8');
370
+ }
371
+ return buf;
372
+ }
373
+ },
374
+
375
+ writeFileSync: function(filePath, content) {
376
+ if (!fs.existsSync(filePath)) {
377
+ const p = path.dirname(filePath);
378
+ if (!fs.existsSync(p)) {
379
+ fs.mkdirSync(p, {
380
+ recursive: true
381
+ });
382
+ }
383
+ }
384
+ fs.writeFileSync(filePath, content);
385
+ },
386
+
387
+ writeFile: async (filePath, content) => {
388
+ if (!fs.existsSync(filePath)) {
389
+ const p = path.dirname(filePath);
390
+ if (!fs.existsSync(p)) {
391
+ fs.mkdirSync(p, {
392
+ recursive: true
393
+ });
394
+ }
395
+ }
396
+ await writeFile(filePath, content).catch((e) => {
397
+ Util.logError(`write file: ${filePath} ${e.message || e}`);
398
+ });
399
+ },
400
+
401
+ rmSync: (p) => {
402
+ if (!fs.existsSync(p)) {
403
+ return;
404
+ }
405
+ try {
406
+ fs.rmSync(p, {
407
+ recursive: true,
408
+ force: true,
409
+ maxRetries: 10
410
+ });
411
+ } catch (err) {
412
+ console.log(err.message);
413
+ }
414
+ },
415
+
416
+ getTemplate: function(templatePath) {
417
+ if (!Util.templateCache) {
418
+ Util.templateCache = {};
419
+ }
420
+ let template = Util.templateCache[templatePath];
421
+ if (!template) {
422
+ template = Util.readFileSync(templatePath);
423
+ if (template) {
424
+ Util.templateCache[templatePath] = template;
425
+ } else {
426
+ Util.logError(`not found template: ${templatePath}`);
427
+ }
428
+ }
429
+ return template;
430
+ },
431
+
432
+ getColorStrByStatus: (str, status) => {
433
+ if (status === 'low') {
434
+ return EC.red(str);
435
+ }
436
+ if (status === 'medium') {
437
+ return EC.yellow(str);
438
+ }
439
+ if (status === 'high') {
440
+ return EC.green(str);
441
+ }
442
+ return str;
443
+ },
444
+
445
+ // ==========================================================================================
446
+
447
+ loggingLevels: {
448
+ off: 0,
449
+ error: 10,
450
+ info: 20,
451
+ debug: 30
452
+ },
453
+
454
+ isDebug: () => {
455
+ return Util.loggingType === 'debug';
456
+ },
457
+
458
+ initLoggingLevel: (level) => {
459
+
460
+ const types = {
461
+ off: 'off',
462
+ error: 'error',
463
+ info: 'info',
464
+ debug: 'debug'
465
+ };
466
+ const type = types[level] || types.info;
467
+ Util.loggingType = type;
468
+ Util.loggingLevel = Util.loggingLevels[type];
469
+
470
+ // console.log('=========================================');
471
+ // console.log(from, Util.loggingType, Util.loggingLevel);
472
+
473
+ return type;
474
+ },
475
+
476
+ logError: (message) => {
477
+ if (Util.loggingLevel < Util.loggingLevels.error) {
478
+ return;
479
+ }
480
+ EC.logRed(`[MCR] ${message}`);
481
+ },
482
+
483
+ logInfo: (message) => {
484
+ if (Util.loggingLevel < Util.loggingLevels.info) {
485
+ return;
486
+ }
487
+ console.log(`[MCR] ${message}`);
488
+ },
489
+
490
+ // grid is info level
491
+ logGrid: (gridData) => {
492
+ if (Util.loggingLevel < Util.loggingLevels.info) {
493
+ return;
494
+ }
495
+ CG(gridData);
496
+ },
497
+
498
+ logDebug: (message) => {
499
+ if (Util.loggingLevel < Util.loggingLevels.debug) {
500
+ return;
501
+ }
502
+ console.log(`[MCR] ${message}`);
503
+ },
504
+
505
+ // time is debug level, fix the log info, for checking snapshot
506
+ logTime: (message, time_start) => {
507
+ if (Util.loggingLevel < Util.loggingLevels.debug) {
508
+ return;
509
+ }
510
+ const duration = Date.now() - time_start;
511
+ const durationH = Util.TSF(duration);
512
+ const ls = [`[MCR] ${message}`, ' ('];
513
+ if (duration <= 100) {
514
+ ls.push(EC.green(durationH));
515
+ } else if (duration < 500) {
516
+ ls.push(EC.yellow(durationH));
517
+ } else {
518
+ ls.push(EC.red(durationH));
519
+ }
520
+ ls.push(')');
521
+ console.log(ls.join(''));
522
+ }
523
+
524
+ };
525
+
526
+ module.exports = Util;