auto-cr-cmd 2.0.92 → 2.0.96
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/dist/index.js +191 -251
- package/dist/report/index.js +50 -35
- package/dist/rules/loader.js +9 -4
- package/dist/scan/analyzeFile.js +219 -0
- package/dist/scan/runtime.js +37 -0
- package/dist/scan/types.js +2 -0
- package/dist/scan/worker.js +137 -0
- package/dist/scan/workerPool.js +173 -0
- package/dist/scan/workerTypes.js +2 -0
- package/dist/types/config/autocrrc.d.ts +1 -2
- package/dist/types/report/index.d.ts +6 -0
- package/dist/types/rules/loader.d.ts +4 -1
- package/dist/types/scan/analyzeFile.d.ts +16 -0
- package/dist/types/scan/runtime.d.ts +7 -0
- package/dist/types/scan/types.d.ts +19 -0
- package/dist/types/scan/worker.d.ts +1 -0
- package/dist/types/scan/workerPool.d.ts +15 -0
- package/dist/types/scan/workerTypes.d.ts +31 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -63,14 +63,17 @@ var _a;
|
|
|
63
63
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
64
64
|
var consola_1 = require("consola");
|
|
65
65
|
var fs_1 = __importDefault(require("fs"));
|
|
66
|
+
var os_1 = __importDefault(require("os"));
|
|
66
67
|
var path_1 = __importDefault(require("path"));
|
|
67
68
|
var commander_1 = require("commander");
|
|
68
|
-
var wasm_1 = require("@swc/wasm");
|
|
69
69
|
var config_1 = require("./config");
|
|
70
70
|
var report_1 = require("./report");
|
|
71
71
|
var i18n_1 = require("./i18n");
|
|
72
72
|
var file_1 = require("./utils/file");
|
|
73
73
|
var stdin_1 = require("./utils/stdin");
|
|
74
|
+
var analyzeFile_1 = require("./scan/analyzeFile");
|
|
75
|
+
var runtime_1 = require("./scan/runtime");
|
|
76
|
+
var workerPool_1 = require("./scan/workerPool");
|
|
74
77
|
var loader_1 = require("./rules/loader");
|
|
75
78
|
var autocrrc_1 = require("./config/autocrrc");
|
|
76
79
|
var ignore_1 = require("./config/ignore");
|
|
@@ -83,7 +86,7 @@ var consolaLoggers = {
|
|
|
83
86
|
// 仅扫描 JS/TS 源码扩展名,避免把配置文件/JSON/图片等送进 SWC 解析导致报错。
|
|
84
87
|
var SCANNABLE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx'];
|
|
85
88
|
// 运行 TS 源码时优先加载本地 rules,避免开发时拿到旧的 workspace 依赖。
|
|
86
|
-
var rulesRuntime = loadRulesRuntime();
|
|
89
|
+
var rulesRuntime = (0, runtime_1.loadRulesRuntime)();
|
|
87
90
|
var builtinRules = rulesRuntime.builtinRules;
|
|
88
91
|
var createRuleContext = rulesRuntime.createRuleContext;
|
|
89
92
|
var RuleSeverity = rulesRuntime.RuleSeverity;
|
|
@@ -91,33 +94,28 @@ var RuleSeverity = rulesRuntime.RuleSeverity;
|
|
|
91
94
|
var isScannableFile = function (filePath) {
|
|
92
95
|
return SCANNABLE_EXTENSIONS.some(function (extension) { return filePath.endsWith(extension); });
|
|
93
96
|
};
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
var localEntry = path_1.default.resolve(__dirname, '../../auto-cr-rules/src/index.ts');
|
|
107
|
-
if (!fs_1.default.existsSync(localEntry)) {
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
try {
|
|
111
|
-
var localRuntime = require(localEntry);
|
|
112
|
-
if (Array.isArray(localRuntime.builtinRules)) {
|
|
113
|
-
return localRuntime;
|
|
97
|
+
// 小文件集无需并行,避免 worker 初始化开销大于收益。
|
|
98
|
+
var MIN_FILES_FOR_WORKERS = 20;
|
|
99
|
+
var resolveWorkerCount = function (totalFiles) {
|
|
100
|
+
// 支持环境变量覆盖并发数:
|
|
101
|
+
// - AUTO_CR_WORKERS=0 表示强制单线程;
|
|
102
|
+
// - AUTO_CR_WORKERS=1 表示不启用并行;
|
|
103
|
+
// - >1 则按指定数量启用 worker。
|
|
104
|
+
var override = process.env.AUTO_CR_WORKERS;
|
|
105
|
+
if (override) {
|
|
106
|
+
var parsed = Number(override);
|
|
107
|
+
if (!Number.isNaN(parsed) && parsed >= 0) {
|
|
108
|
+
return Math.min(totalFiles, Math.floor(parsed));
|
|
114
109
|
}
|
|
115
110
|
}
|
|
116
|
-
|
|
117
|
-
return
|
|
111
|
+
if (totalFiles < MIN_FILES_FOR_WORKERS) {
|
|
112
|
+
return 1;
|
|
118
113
|
}
|
|
119
|
-
|
|
120
|
-
|
|
114
|
+
// 默认按 CPU 数量 - 1 取值,给主线程留出空间。
|
|
115
|
+
var cpuCount = os_1.default.cpus().length || 1;
|
|
116
|
+
var maxWorkers = Math.max(1, cpuCount - 1);
|
|
117
|
+
return Math.min(maxWorkers, totalFiles);
|
|
118
|
+
};
|
|
121
119
|
/**
|
|
122
120
|
* CLI 主流程:
|
|
123
121
|
* 1. 校验输入路径并应用 ignore;
|
|
@@ -127,7 +125,7 @@ function resolveLocalRulesRuntime() {
|
|
|
127
125
|
*/
|
|
128
126
|
function run() {
|
|
129
127
|
return __awaiter(this, arguments, void 0, function (filePaths, ruleDir, format, configPath, ignorePath, progressOption) {
|
|
130
|
-
var t, notifications, progressMode, progressStream, progressStreamHasTty, progressEnabled, progressPinned, progressStyle, progressTotal, progressCurrent, progressLastPercent, clearProgressLine, renderProgress, startProgress, advanceProgress, finishProgress, reporterHooks, log, validPaths, ignoreConfig, isIgnored_1, allFiles, _i, validPaths_1, targetPath, stat, directoryFiles,
|
|
128
|
+
var t, notifications, progressMode, progressStream, progressStreamHasTty, progressEnabled, progressPinned, progressStyle, progressTotal, progressCurrent, progressLastPercent, clearProgressLine, renderProgress, startProgress, advanceProgress, finishProgress, reporterHooks, createNotification, logRecord, log, validPaths, ignoreConfig, isIgnored_1, allFiles, _i, validPaths_1, targetPath, stat, directoryFiles, scannableFiles_2, customRules, rcConfig, rules, filesWithErrors_1, filesWithWarnings_1, filesWithOptimizing_1, totalViolations_1, totalErrorViolations_1, totalWarningViolations_1, totalOptimizingViolations_1, fileSummaries_1, analysisFormat, workerCount, applyFileSummary_1, fileOccurrences_1, uniqueFiles, pendingResults_1, nextOutputIndex_1, flushReadyResults_1, initData, fileSummaryCache, _loop_1, _a, scannableFiles_1, file, error_1;
|
|
131
129
|
var _b;
|
|
132
130
|
if (filePaths === void 0) { filePaths = []; }
|
|
133
131
|
return __generator(this, function (_c) {
|
|
@@ -230,7 +228,7 @@ function run() {
|
|
|
230
228
|
reporterHooks = {
|
|
231
229
|
onAfterReport: function () { return renderProgress(true); },
|
|
232
230
|
};
|
|
233
|
-
|
|
231
|
+
createNotification = function (level, message, detail) {
|
|
234
232
|
var detailText;
|
|
235
233
|
if (detail !== undefined) {
|
|
236
234
|
if (detail instanceof Error) {
|
|
@@ -248,21 +246,27 @@ function run() {
|
|
|
248
246
|
}
|
|
249
247
|
}
|
|
250
248
|
}
|
|
251
|
-
|
|
249
|
+
return { level: level, message: message, detail: detailText };
|
|
250
|
+
};
|
|
251
|
+
logRecord = function (record) {
|
|
252
|
+
notifications.push(record);
|
|
252
253
|
if (format === 'text') {
|
|
253
|
-
var logger = consolaLoggers[level];
|
|
254
|
-
if (detail === undefined) {
|
|
255
|
-
logger(message);
|
|
254
|
+
var logger = consolaLoggers[record.level];
|
|
255
|
+
if (record.detail === undefined) {
|
|
256
|
+
logger(record.message);
|
|
256
257
|
}
|
|
257
258
|
else {
|
|
258
|
-
logger(message, detail);
|
|
259
|
+
logger(record.message, record.detail);
|
|
259
260
|
}
|
|
260
261
|
renderProgress(true);
|
|
261
262
|
}
|
|
262
263
|
};
|
|
264
|
+
log = function (level, message, detail) {
|
|
265
|
+
logRecord(createNotification(level, message, detail));
|
|
266
|
+
};
|
|
263
267
|
_c.label = 1;
|
|
264
268
|
case 1:
|
|
265
|
-
_c.trys.push([1,
|
|
269
|
+
_c.trys.push([1, 8, , 9]);
|
|
266
270
|
if (filePaths.length === 0) {
|
|
267
271
|
log('info', t.noPathsProvided());
|
|
268
272
|
return [2 /*return*/, {
|
|
@@ -322,8 +326,10 @@ function run() {
|
|
|
322
326
|
notifications: notifications,
|
|
323
327
|
}];
|
|
324
328
|
}
|
|
325
|
-
|
|
326
|
-
customRules = (0, loader_1.loadCustomRules)(ruleDir
|
|
329
|
+
scannableFiles_2 = allFiles.filter(function (candidate) { return !candidate.endsWith('.d.ts') && !isIgnored_1(candidate); });
|
|
330
|
+
customRules = (0, loader_1.loadCustomRules)(ruleDir, {
|
|
331
|
+
onWarning: function (message, detail) { return log('warn', message, detail); },
|
|
332
|
+
});
|
|
327
333
|
rcConfig = (0, autocrrc_1.loadAutoCrRc)(configPath);
|
|
328
334
|
rcConfig.warnings.forEach(function (warning) { return log('warn', warning); });
|
|
329
335
|
rules = (0, autocrrc_1.applyRuleConfig)(__spreadArray(__spreadArray([], builtinRules, true), customRules, true), rcConfig.rules, function (warning) {
|
|
@@ -341,234 +347,167 @@ function run() {
|
|
|
341
347
|
notifications: notifications,
|
|
342
348
|
}];
|
|
343
349
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
350
|
+
filesWithErrors_1 = 0;
|
|
351
|
+
filesWithWarnings_1 = 0;
|
|
352
|
+
filesWithOptimizing_1 = 0;
|
|
353
|
+
totalViolations_1 = 0;
|
|
354
|
+
totalErrorViolations_1 = 0;
|
|
355
|
+
totalWarningViolations_1 = 0;
|
|
356
|
+
totalOptimizingViolations_1 = 0;
|
|
357
|
+
fileSummaries_1 = [];
|
|
358
|
+
analysisFormat = 'json';
|
|
359
|
+
workerCount = resolveWorkerCount(scannableFiles_2.length);
|
|
360
|
+
applyFileSummary_1 = function (filePath, summary) {
|
|
361
|
+
if (summary.severityCounts.error > 0) {
|
|
362
|
+
filesWithErrors_1 += 1;
|
|
363
|
+
}
|
|
364
|
+
if (summary.severityCounts.warning > 0) {
|
|
365
|
+
filesWithWarnings_1 += 1;
|
|
366
|
+
}
|
|
367
|
+
if (summary.severityCounts.optimizing > 0) {
|
|
368
|
+
filesWithOptimizing_1 += 1;
|
|
369
|
+
}
|
|
370
|
+
totalViolations_1 += summary.totalViolations;
|
|
371
|
+
totalErrorViolations_1 += summary.errorViolations;
|
|
372
|
+
totalWarningViolations_1 += summary.severityCounts.warning;
|
|
373
|
+
totalOptimizingViolations_1 += summary.severityCounts.optimizing;
|
|
374
|
+
fileSummaries_1.push({
|
|
375
|
+
filePath: filePath,
|
|
376
|
+
severityCounts: summary.severityCounts,
|
|
377
|
+
totalViolations: summary.totalViolations,
|
|
378
|
+
errorViolations: summary.errorViolations,
|
|
379
|
+
violations: summary.violations,
|
|
380
|
+
});
|
|
381
|
+
};
|
|
382
|
+
startProgress(scannableFiles_2.length);
|
|
383
|
+
if (!(workerCount > 1)) return [3 /*break*/, 3];
|
|
384
|
+
fileOccurrences_1 = new Map();
|
|
385
|
+
scannableFiles_2.forEach(function (filePath, index) {
|
|
386
|
+
var _a;
|
|
387
|
+
var bucket = (_a = fileOccurrences_1.get(filePath)) !== null && _a !== void 0 ? _a : [];
|
|
388
|
+
bucket.push(index);
|
|
389
|
+
fileOccurrences_1.set(filePath, bucket);
|
|
390
|
+
});
|
|
391
|
+
uniqueFiles = Array.from(fileOccurrences_1.keys());
|
|
392
|
+
pendingResults_1 = new Map();
|
|
393
|
+
nextOutputIndex_1 = 0;
|
|
394
|
+
flushReadyResults_1 = function () {
|
|
395
|
+
while (pendingResults_1.has(nextOutputIndex_1)) {
|
|
396
|
+
var entry = pendingResults_1.get(nextOutputIndex_1);
|
|
397
|
+
if (!entry) {
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
pendingResults_1.delete(nextOutputIndex_1);
|
|
401
|
+
var filePath = scannableFiles_2[nextOutputIndex_1];
|
|
402
|
+
// 先回放日志,再回放违规输出,确保日志顺序与单线程一致。
|
|
403
|
+
entry.logs.forEach(function (record) { return logRecord(record); });
|
|
404
|
+
if (format === 'text') {
|
|
405
|
+
(0, report_1.renderViolations)(filePath, entry.summary.violations, __assign({ format: format }, reporterHooks));
|
|
406
|
+
}
|
|
407
|
+
applyFileSummary_1(filePath, entry.summary);
|
|
408
|
+
nextOutputIndex_1 += 1;
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
initData = {
|
|
412
|
+
ruleDir: ruleDir,
|
|
413
|
+
ruleSettings: rcConfig.rules,
|
|
414
|
+
language: (0, i18n_1.getLanguage)(),
|
|
415
|
+
tsconfigPath: resolvedTsconfigPath,
|
|
416
|
+
};
|
|
417
|
+
return [4 /*yield*/, (0, workerPool_1.runWorkerPool)({
|
|
418
|
+
files: uniqueFiles,
|
|
419
|
+
workerCount: workerCount,
|
|
420
|
+
initData: initData,
|
|
421
|
+
onResult: function (_a) {
|
|
422
|
+
var _b;
|
|
423
|
+
var filePath = _a.filePath, summary = _a.summary, logs = _a.logs;
|
|
424
|
+
var occurrences = (_b = fileOccurrences_1.get(filePath)) !== null && _b !== void 0 ? _b : [];
|
|
425
|
+
for (var _i = 0, occurrences_1 = occurrences; _i < occurrences_1.length; _i++) {
|
|
426
|
+
var index = occurrences_1[_i];
|
|
427
|
+
pendingResults_1.set(index, { summary: summary, logs: logs });
|
|
428
|
+
// 进度按“原始文件列表”推进,保持百分比与实际扫描一致。
|
|
429
|
+
advanceProgress();
|
|
430
|
+
}
|
|
431
|
+
flushReadyResults_1();
|
|
432
|
+
},
|
|
433
|
+
})];
|
|
355
434
|
case 2:
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
return [
|
|
435
|
+
_c.sent();
|
|
436
|
+
flushReadyResults_1();
|
|
437
|
+
return [3 /*break*/, 7];
|
|
359
438
|
case 3:
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
439
|
+
fileSummaryCache = new Map();
|
|
440
|
+
_loop_1 = function (file) {
|
|
441
|
+
var cached, summary, logs, capturedLogs_1, logForFile;
|
|
442
|
+
return __generator(this, function (_d) {
|
|
443
|
+
switch (_d.label) {
|
|
444
|
+
case 0:
|
|
445
|
+
cached = fileSummaryCache.get(file);
|
|
446
|
+
summary = void 0;
|
|
447
|
+
logs = [];
|
|
448
|
+
if (!cached) return [3 /*break*/, 1];
|
|
449
|
+
summary = cached.summary;
|
|
450
|
+
logs = cached.logs;
|
|
451
|
+
logs.forEach(function (record) { return logRecord(record); });
|
|
452
|
+
return [3 /*break*/, 3];
|
|
453
|
+
case 1:
|
|
454
|
+
capturedLogs_1 = [];
|
|
455
|
+
logForFile = function (level, message, detail) {
|
|
456
|
+
var record = createNotification(level, message, detail);
|
|
457
|
+
capturedLogs_1.push(record);
|
|
458
|
+
logRecord(record);
|
|
459
|
+
};
|
|
460
|
+
return [4 /*yield*/, (0, analyzeFile_1.analyzeFile)(file, rules, analysisFormat, logForFile, createRuleContext)];
|
|
461
|
+
case 2:
|
|
462
|
+
summary = _d.sent();
|
|
463
|
+
fileSummaryCache.set(file, { summary: summary, logs: capturedLogs_1 });
|
|
464
|
+
_d.label = 3;
|
|
465
|
+
case 3:
|
|
466
|
+
if (format === 'text') {
|
|
467
|
+
(0, report_1.renderViolations)(file, summary.violations, __assign({ format: format }, reporterHooks));
|
|
468
|
+
}
|
|
469
|
+
applyFileSummary_1(file, summary);
|
|
470
|
+
advanceProgress();
|
|
471
|
+
return [2 /*return*/];
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
};
|
|
475
|
+
_a = 0, scannableFiles_1 = scannableFiles_2;
|
|
382
476
|
_c.label = 4;
|
|
383
477
|
case 4:
|
|
384
|
-
_a
|
|
385
|
-
|
|
478
|
+
if (!(_a < scannableFiles_1.length)) return [3 /*break*/, 7];
|
|
479
|
+
file = scannableFiles_1[_a];
|
|
480
|
+
return [5 /*yield**/, _loop_1(file)];
|
|
386
481
|
case 5:
|
|
482
|
+
_c.sent();
|
|
483
|
+
_c.label = 6;
|
|
484
|
+
case 6:
|
|
485
|
+
_a++;
|
|
486
|
+
return [3 /*break*/, 4];
|
|
487
|
+
case 7:
|
|
387
488
|
finishProgress();
|
|
388
489
|
return [2 /*return*/, {
|
|
389
|
-
scannedFiles:
|
|
390
|
-
filesWithErrors:
|
|
391
|
-
filesWithWarnings:
|
|
392
|
-
filesWithOptimizing:
|
|
490
|
+
scannedFiles: scannableFiles_2.length,
|
|
491
|
+
filesWithErrors: filesWithErrors_1,
|
|
492
|
+
filesWithWarnings: filesWithWarnings_1,
|
|
493
|
+
filesWithOptimizing: filesWithOptimizing_1,
|
|
393
494
|
violationTotals: {
|
|
394
|
-
total:
|
|
395
|
-
error:
|
|
396
|
-
warning:
|
|
397
|
-
optimizing:
|
|
495
|
+
total: totalViolations_1,
|
|
496
|
+
error: totalErrorViolations_1,
|
|
497
|
+
warning: totalWarningViolations_1,
|
|
498
|
+
optimizing: totalOptimizingViolations_1,
|
|
398
499
|
},
|
|
399
|
-
files:
|
|
500
|
+
files: fileSummaries_1,
|
|
400
501
|
notifications: notifications,
|
|
401
502
|
}];
|
|
402
|
-
case
|
|
503
|
+
case 8:
|
|
403
504
|
error_1 = _c.sent();
|
|
404
505
|
throw error_1 instanceof Error ? error_1 : new Error(String(error_1));
|
|
405
|
-
case
|
|
506
|
+
case 9: return [2 /*return*/];
|
|
406
507
|
}
|
|
407
508
|
});
|
|
408
509
|
});
|
|
409
510
|
}
|
|
410
|
-
/**
|
|
411
|
-
* 单文件扫描流程:
|
|
412
|
-
* - 读取源码并解析 AST;
|
|
413
|
-
* - 基于语言/源码构建规则上下文;
|
|
414
|
-
* - 逐条执行规则,收集 reporter 输出;
|
|
415
|
-
* - 汇总为文件级统计。
|
|
416
|
-
*/
|
|
417
|
-
function analyzeFile(file, rules, format, log, reporterHooks) {
|
|
418
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
419
|
-
var source, reporter, t, ast, parseOptions, language, baseContext, sharedHelpers, _loop_1, _i, rules_1, rule, summary;
|
|
420
|
-
return __generator(this, function (_a) {
|
|
421
|
-
switch (_a.label) {
|
|
422
|
-
case 0:
|
|
423
|
-
source = (0, file_1.readFile)(file);
|
|
424
|
-
reporter = (0, report_1.createReporter)(file, source, __assign({ format: format }, reporterHooks));
|
|
425
|
-
t = (0, i18n_1.getTranslator)();
|
|
426
|
-
try {
|
|
427
|
-
parseOptions = (0, config_1.loadParseOptions)(file);
|
|
428
|
-
ast = (0, wasm_1.parseSync)(source, parseOptions);
|
|
429
|
-
}
|
|
430
|
-
catch (error) {
|
|
431
|
-
log('error', t.parseFileFailed({ file: file }), error);
|
|
432
|
-
return [2 /*return*/, {
|
|
433
|
-
severityCounts: {
|
|
434
|
-
error: 1,
|
|
435
|
-
warning: 0,
|
|
436
|
-
optimizing: 0,
|
|
437
|
-
},
|
|
438
|
-
totalViolations: 1,
|
|
439
|
-
errorViolations: 1,
|
|
440
|
-
violations: [],
|
|
441
|
-
}];
|
|
442
|
-
}
|
|
443
|
-
language = (0, i18n_1.getLanguage)();
|
|
444
|
-
baseContext = createRuleContext({
|
|
445
|
-
ast: ast,
|
|
446
|
-
filePath: file,
|
|
447
|
-
source: source,
|
|
448
|
-
reporter: reporter,
|
|
449
|
-
language: language,
|
|
450
|
-
});
|
|
451
|
-
sharedHelpers = baseContext.helpers;
|
|
452
|
-
_loop_1 = function (rule) {
|
|
453
|
-
var scopedReporter_1, reporterWithRecord_1, helpers, context, error_2;
|
|
454
|
-
return __generator(this, function (_b) {
|
|
455
|
-
switch (_b.label) {
|
|
456
|
-
case 0:
|
|
457
|
-
_b.trys.push([0, 2, , 3]);
|
|
458
|
-
scopedReporter_1 = reporter.forRule(rule);
|
|
459
|
-
reporterWithRecord_1 = scopedReporter_1;
|
|
460
|
-
helpers = __assign(__assign({}, sharedHelpers), { reportViolation: (function (input, span) {
|
|
461
|
-
var normalized = normalizeViolationInput(input, span);
|
|
462
|
-
if (typeof reporterWithRecord_1.record === 'function') {
|
|
463
|
-
reporterWithRecord_1.record({
|
|
464
|
-
description: normalized.message,
|
|
465
|
-
code: normalized.code,
|
|
466
|
-
suggestions: normalized.suggestions,
|
|
467
|
-
span: normalized.span,
|
|
468
|
-
line: normalized.line,
|
|
469
|
-
});
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
if (normalized.span) {
|
|
473
|
-
scopedReporter_1.errorAtSpan(normalized.span, normalized.message);
|
|
474
|
-
return;
|
|
475
|
-
}
|
|
476
|
-
if (typeof normalized.line === 'number') {
|
|
477
|
-
scopedReporter_1.errorAtLine(normalized.line, normalized.message);
|
|
478
|
-
return;
|
|
479
|
-
}
|
|
480
|
-
scopedReporter_1.error(normalized.message);
|
|
481
|
-
}) });
|
|
482
|
-
context = __assign(__assign({}, baseContext), { reporter: scopedReporter_1, helpers: helpers });
|
|
483
|
-
return [4 /*yield*/, rule.run(context)];
|
|
484
|
-
case 1:
|
|
485
|
-
_b.sent();
|
|
486
|
-
return [3 /*break*/, 3];
|
|
487
|
-
case 2:
|
|
488
|
-
error_2 = _b.sent();
|
|
489
|
-
log('error', t.ruleExecutionFailed({ ruleName: rule.name, file: file }), error_2);
|
|
490
|
-
return [3 /*break*/, 3];
|
|
491
|
-
case 3: return [2 /*return*/];
|
|
492
|
-
}
|
|
493
|
-
});
|
|
494
|
-
};
|
|
495
|
-
_i = 0, rules_1 = rules;
|
|
496
|
-
_a.label = 1;
|
|
497
|
-
case 1:
|
|
498
|
-
if (!(_i < rules_1.length)) return [3 /*break*/, 4];
|
|
499
|
-
rule = rules_1[_i];
|
|
500
|
-
return [5 /*yield**/, _loop_1(rule)];
|
|
501
|
-
case 2:
|
|
502
|
-
_a.sent();
|
|
503
|
-
_a.label = 3;
|
|
504
|
-
case 3:
|
|
505
|
-
_i++;
|
|
506
|
-
return [3 /*break*/, 1];
|
|
507
|
-
case 4:
|
|
508
|
-
summary = reporter.flush();
|
|
509
|
-
return [2 /*return*/, {
|
|
510
|
-
severityCounts: summary.severityCounts,
|
|
511
|
-
totalViolations: summary.totalViolations,
|
|
512
|
-
errorViolations: summary.errorViolations,
|
|
513
|
-
violations: summary.violations,
|
|
514
|
-
}];
|
|
515
|
-
}
|
|
516
|
-
});
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
function normalizeViolationInput(input, spanArg) {
|
|
520
|
-
var _a;
|
|
521
|
-
// 规则既可以直接输出字符串,也可以输出结构化对象;这里统一为标准格式。
|
|
522
|
-
if (typeof input === 'string') {
|
|
523
|
-
return {
|
|
524
|
-
message: input,
|
|
525
|
-
span: spanArg,
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
if (input && typeof input === 'object') {
|
|
529
|
-
var candidate = input;
|
|
530
|
-
var description = typeof candidate.description === 'string'
|
|
531
|
-
? candidate.description
|
|
532
|
-
: typeof candidate.message === 'string'
|
|
533
|
-
? candidate.message
|
|
534
|
-
: undefined;
|
|
535
|
-
var code = typeof candidate.code === 'string' ? candidate.code : undefined;
|
|
536
|
-
var suggestions = void 0;
|
|
537
|
-
if (Array.isArray(candidate.suggestions)) {
|
|
538
|
-
var normalizedSuggestions = [];
|
|
539
|
-
for (var _i = 0, _b = candidate.suggestions; _i < _b.length; _i++) {
|
|
540
|
-
var entry = _b[_i];
|
|
541
|
-
if (typeof entry === 'string') {
|
|
542
|
-
normalizedSuggestions.push({ text: entry });
|
|
543
|
-
continue;
|
|
544
|
-
}
|
|
545
|
-
if (entry && typeof entry === 'object') {
|
|
546
|
-
var suggestion = entry;
|
|
547
|
-
if (typeof suggestion.text === 'string') {
|
|
548
|
-
normalizedSuggestions.push({
|
|
549
|
-
text: suggestion.text,
|
|
550
|
-
link: typeof suggestion.link === 'string' ? suggestion.link : undefined,
|
|
551
|
-
});
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
if (normalizedSuggestions.length > 0) {
|
|
556
|
-
suggestions = normalizedSuggestions;
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
return {
|
|
560
|
-
message: description !== null && description !== void 0 ? description : 'Rule violation detected.',
|
|
561
|
-
span: (_a = candidate.span) !== null && _a !== void 0 ? _a : spanArg,
|
|
562
|
-
line: typeof candidate.line === 'number' ? candidate.line : undefined,
|
|
563
|
-
code: code,
|
|
564
|
-
suggestions: suggestions,
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
|
-
return {
|
|
568
|
-
message: 'Rule violation detected.',
|
|
569
|
-
span: spanArg,
|
|
570
|
-
};
|
|
571
|
-
}
|
|
572
511
|
// CLI 输出格式解析:仅允许 text/json。
|
|
573
512
|
function parseOutputFormat(value) {
|
|
574
513
|
if (!value) {
|
|
@@ -660,7 +599,8 @@ commander_1.program
|
|
|
660
599
|
var options = commander_1.program.opts();
|
|
661
600
|
var cliArguments = commander_1.program.args;
|
|
662
601
|
(0, i18n_1.setLanguage)((_a = options.language) !== null && _a !== void 0 ? _a : process.env.LANG);
|
|
663
|
-
|
|
602
|
+
var resolvedTsconfigPath = options.tsconfig ? path_1.default.resolve(process.cwd(), options.tsconfig) : undefined;
|
|
603
|
+
(0, config_1.setTsConfigPath)(resolvedTsconfigPath);
|
|
664
604
|
var outputFormat;
|
|
665
605
|
var progressOption;
|
|
666
606
|
try {
|
|
@@ -681,7 +621,7 @@ catch (error) {
|
|
|
681
621
|
}
|
|
682
622
|
;
|
|
683
623
|
(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
684
|
-
var stdinTargets, combinedTargets, filePaths, result, t, payload, exitCode, language, resultMessage, exitCode,
|
|
624
|
+
var stdinTargets, combinedTargets, filePaths, result, t, payload, exitCode, language, resultMessage, exitCode, error_2, t, detail, payload;
|
|
685
625
|
return __generator(this, function (_a) {
|
|
686
626
|
switch (_a.label) {
|
|
687
627
|
case 0:
|
|
@@ -716,9 +656,9 @@ catch (error) {
|
|
|
716
656
|
}
|
|
717
657
|
return [3 /*break*/, 4];
|
|
718
658
|
case 3:
|
|
719
|
-
|
|
659
|
+
error_2 = _a.sent();
|
|
720
660
|
t = (0, i18n_1.getTranslator)();
|
|
721
|
-
detail =
|
|
661
|
+
detail = error_2 instanceof Error ? error_2.message : String(error_2);
|
|
722
662
|
if (outputFormat === 'json') {
|
|
723
663
|
payload = {
|
|
724
664
|
error: {
|