auto-cr-cmd 2.0.78 → 2.0.79
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/README.md +2 -1
- package/README.zh-CN.md +2 -1
- package/dist/config/autocrrc.js +7 -0
- package/dist/config/ignore.js +9 -0
- package/dist/config.js +3 -0
- package/dist/i18n/index.js +5 -0
- package/dist/index.js +3 -0
- package/dist/report/index.js +5 -0
- package/dist/rules/loader.js +5 -0
- package/dist/types/utils/file.d.ts +2 -0
- package/dist/utils/file.js +3 -0
- package/dist/utils/stdin.js +6 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
## Feature Highlights (Automated Code Review & Static Analysis)
|
|
24
24
|
|
|
25
|
-
- **Built-in Rule Library**: Ships with SWC AST static analysis rules out of the box, such as `no-deep-relative-imports`.
|
|
25
|
+
- **Built-in Rule Library**: Ships with SWC AST static analysis rules out of the box, such as `no-deep-relative-imports`, `no-circular-dependencies`, and `no-swallowed-errors`.
|
|
26
26
|
- **Extensible SDK**: `auto-cr-rules` exposes helpers like `defineRule` and `helpers.imports`, reducing the friction of authoring custom TypeScript / JavaScript rules.
|
|
27
27
|
- **Workspace Friendly**: Manage both the CLI and rule package via pnpm workspaces and validate the full pipeline with a single build.
|
|
28
28
|
- **Publishing Toolkit**: Version bump scripts and npm publish commands keep both packages in sync.
|
|
@@ -121,6 +121,7 @@ npx auto-cr-cmd --output json -- ./src | jq
|
|
|
121
121
|
{
|
|
122
122
|
"rules": {
|
|
123
123
|
"no-deep-relative-imports": "error",
|
|
124
|
+
"no-circular-dependencies": "warning",
|
|
124
125
|
"no-swallowed-errors": "off"
|
|
125
126
|
}
|
|
126
127
|
}
|
package/README.zh-CN.md
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
## 特性亮点(自动化代码审查 & 静态代码分析)
|
|
24
24
|
|
|
25
|
-
- **内置规则库**:默认集成 SWC AST 静态分析规则,例如 `no-deep-relative-imports`。
|
|
25
|
+
- **内置规则库**:默认集成 SWC AST 静态分析规则,例如 `no-deep-relative-imports`、`no-circular-dependencies`、`no-swallowed-errors`。
|
|
26
26
|
- **可扩展 SDK**:`auto-cr-rules` 暴露 `defineRule`、`helpers.imports` 等工具,降低编写 TypeScript / JavaScript 自定义规则的复杂度。
|
|
27
27
|
- **工作区管理**:使用 pnpm workspace 同时管理 CLI 与规则包,一次构建即可验证完整流程。
|
|
28
28
|
- **发布友好**:内置版本递增脚本与 npm 发布命令,保持两个包的版本同步。
|
|
@@ -121,6 +121,7 @@ npx auto-cr-cmd --output json -- ./src | jq
|
|
|
121
121
|
{
|
|
122
122
|
"rules": {
|
|
123
123
|
"no-deep-relative-imports": "error",
|
|
124
|
+
"no-circular-dependencies": "warning",
|
|
124
125
|
"no-swallowed-errors": "off"
|
|
125
126
|
}
|
|
126
127
|
}
|
package/dist/config/autocrrc.js
CHANGED
|
@@ -20,7 +20,9 @@ var fs_1 = __importDefault(require("fs"));
|
|
|
20
20
|
var path_1 = __importDefault(require("path"));
|
|
21
21
|
var auto_cr_rules_1 = require("auto-cr-rules");
|
|
22
22
|
var i18n_1 = require("../i18n");
|
|
23
|
+
// 支持的配置文件候选名(从当前工作目录开始查找)。
|
|
23
24
|
var RC_CANDIDATES = ['.autocrrc.json', '.autocrrc.js'];
|
|
25
|
+
// 读取 .autocrrc 并校验结构;任何解析失败都转成 warning 不中断扫描。
|
|
24
26
|
function loadAutoCrRc(configPath) {
|
|
25
27
|
var warnings = [];
|
|
26
28
|
var t = (0, i18n_1.getTranslator)();
|
|
@@ -55,6 +57,7 @@ function loadAutoCrRc(configPath) {
|
|
|
55
57
|
return { warnings: warnings };
|
|
56
58
|
}
|
|
57
59
|
}
|
|
60
|
+
// 将 rules 配置应用到内置/自定义规则上,支持关闭与调整 severity。
|
|
58
61
|
function applyRuleConfig(rules, ruleSettings, onWarning) {
|
|
59
62
|
if (!ruleSettings || Object.keys(ruleSettings).length === 0) {
|
|
60
63
|
return rules;
|
|
@@ -86,6 +89,7 @@ function applyRuleConfig(rules, ruleSettings, onWarning) {
|
|
|
86
89
|
}
|
|
87
90
|
return configured;
|
|
88
91
|
}
|
|
92
|
+
// 优先使用显式路径,否则在工作目录内按候选名查找。
|
|
89
93
|
function resolveConfigPath(explicitPath) {
|
|
90
94
|
if (explicitPath) {
|
|
91
95
|
return path_1.default.isAbsolute(explicitPath) ? explicitPath : path_1.default.resolve(process.cwd(), explicitPath);
|
|
@@ -99,6 +103,7 @@ function resolveConfigPath(explicitPath) {
|
|
|
99
103
|
}
|
|
100
104
|
return null;
|
|
101
105
|
}
|
|
106
|
+
// 读取配置文件:支持 JSON 与 JS 导出。
|
|
102
107
|
function readConfigFile(filePath) {
|
|
103
108
|
if (filePath.endsWith('.json')) {
|
|
104
109
|
var raw = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
@@ -110,6 +115,7 @@ function readConfigFile(filePath) {
|
|
|
110
115
|
}
|
|
111
116
|
return {};
|
|
112
117
|
}
|
|
118
|
+
// 兼容 default 导出(CommonJS/ESM)。
|
|
113
119
|
function unwrapDefault(value) {
|
|
114
120
|
var _a;
|
|
115
121
|
if (isRecord(value) && 'default' in value) {
|
|
@@ -120,6 +126,7 @@ function unwrapDefault(value) {
|
|
|
120
126
|
function isRecord(value) {
|
|
121
127
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
122
128
|
}
|
|
129
|
+
// 统一配置格式:支持字符串/数字/布尔值等多种简写形式。
|
|
123
130
|
function normalizeRuleSetting(input) {
|
|
124
131
|
if (input === undefined) {
|
|
125
132
|
return undefined;
|
package/dist/config/ignore.js
CHANGED
|
@@ -9,7 +9,9 @@ var fs_1 = __importDefault(require("fs"));
|
|
|
9
9
|
var path_1 = __importDefault(require("path"));
|
|
10
10
|
var picomatch_1 = __importDefault(require("picomatch"));
|
|
11
11
|
var i18n_1 = require("../i18n");
|
|
12
|
+
// 忽略文件候选名(从当前工作目录开始查找)。
|
|
12
13
|
var IGNORE_CANDIDATES = ['.autocrignore.json', '.autocrignore.js'];
|
|
14
|
+
// 加载忽略配置:支持 JSON/JS/文本多种形式,失败仅输出 warning。
|
|
13
15
|
function loadIgnoreConfig(configPath) {
|
|
14
16
|
var warnings = [];
|
|
15
17
|
var t = (0, i18n_1.getTranslator)();
|
|
@@ -36,6 +38,7 @@ function loadIgnoreConfig(configPath) {
|
|
|
36
38
|
return { patterns: [], warnings: warnings, baseDir: baseDir };
|
|
37
39
|
}
|
|
38
40
|
}
|
|
41
|
+
// 构建忽略匹配器,匹配绝对路径与相对路径两种形式。
|
|
39
42
|
function createIgnoreMatcher(patterns, baseDir) {
|
|
40
43
|
if (baseDir === void 0) { baseDir = process.cwd(); }
|
|
41
44
|
if (!patterns.length) {
|
|
@@ -51,6 +54,7 @@ function createIgnoreMatcher(patterns, baseDir) {
|
|
|
51
54
|
return matchers.some(function (matcher) { return matcher(normalized) || matcher(relative); });
|
|
52
55
|
};
|
|
53
56
|
}
|
|
57
|
+
// 解析忽略配置路径:显式传入优先,其次按候选名查找。
|
|
54
58
|
function resolveConfigPath(explicitPath) {
|
|
55
59
|
if (explicitPath) {
|
|
56
60
|
return path_1.default.isAbsolute(explicitPath) ? explicitPath : path_1.default.resolve(process.cwd(), explicitPath);
|
|
@@ -64,6 +68,7 @@ function resolveConfigPath(explicitPath) {
|
|
|
64
68
|
}
|
|
65
69
|
return null;
|
|
66
70
|
}
|
|
71
|
+
// 读取忽略文件:JSON/JS 导出均可。
|
|
67
72
|
function readIgnoreFile(filePath) {
|
|
68
73
|
if (filePath.endsWith('.json')) {
|
|
69
74
|
var raw = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
@@ -75,6 +80,8 @@ function readIgnoreFile(filePath) {
|
|
|
75
80
|
}
|
|
76
81
|
return [];
|
|
77
82
|
}
|
|
83
|
+
// 规范化 ignore 内容:
|
|
84
|
+
// - 支持字符串数组 / 单个字符串(按行拆分)/ { ignore } / { default }。
|
|
78
85
|
function normalizeIgnorePayload(payload) {
|
|
79
86
|
var values = [];
|
|
80
87
|
if (Array.isArray(payload)) {
|
|
@@ -97,6 +104,7 @@ function normalizeIgnorePayload(payload) {
|
|
|
97
104
|
}
|
|
98
105
|
return values;
|
|
99
106
|
}
|
|
107
|
+
// 过滤空行与注释行。
|
|
100
108
|
function normalizeEntry(entry) {
|
|
101
109
|
if (typeof entry !== 'string') {
|
|
102
110
|
return null;
|
|
@@ -110,6 +118,7 @@ function normalizeEntry(entry) {
|
|
|
110
118
|
function isRecord(value) {
|
|
111
119
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
112
120
|
}
|
|
121
|
+
// 统一路径分隔符为 POSIX,保证跨平台匹配一致。
|
|
113
122
|
function toPosix(p) {
|
|
114
123
|
return p.split(path_1.default.sep).join('/');
|
|
115
124
|
}
|
package/dist/config.js
CHANGED
|
@@ -21,6 +21,7 @@ var path_1 = __importDefault(require("path"));
|
|
|
21
21
|
var jsonc_parser_1 = require("jsonc-parser");
|
|
22
22
|
var i18n_1 = require("./i18n");
|
|
23
23
|
var consola_1 = __importDefault(require("consola"));
|
|
24
|
+
// 缓存 tsconfig 解析结果,避免每个文件都重复读取与解析。
|
|
24
25
|
var cachedTsConfig;
|
|
25
26
|
var tsConfigPathOverride = null;
|
|
26
27
|
function setTsConfigPath(path) {
|
|
@@ -43,6 +44,7 @@ function formatParseErrors(errors, content) {
|
|
|
43
44
|
})
|
|
44
45
|
.join('; ');
|
|
45
46
|
}
|
|
47
|
+
// 读取并解析 tsconfig;失败时只记录警告,不中断扫描流程。
|
|
46
48
|
function readTsConfig() {
|
|
47
49
|
if (cachedTsConfig !== undefined) {
|
|
48
50
|
return cachedTsConfig;
|
|
@@ -128,6 +130,7 @@ function createEsParserConfig(extension, options, enableDecorators) {
|
|
|
128
130
|
importAttributes: true,
|
|
129
131
|
};
|
|
130
132
|
}
|
|
133
|
+
// 按文件扩展名推导 SWC 的 parser 选项,并结合 tsconfig 的 target/decorators。
|
|
131
134
|
function loadParseOptions(filePath) {
|
|
132
135
|
var extension = path_1.default.extname(filePath).toLowerCase();
|
|
133
136
|
var tsConfig = readTsConfig();
|
package/dist/i18n/index.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.normalizeLanguage = normalizeLanguage;
|
|
|
4
4
|
exports.setLanguage = setLanguage;
|
|
5
5
|
exports.getLanguage = getLanguage;
|
|
6
6
|
exports.getTranslator = getTranslator;
|
|
7
|
+
// 中英文文案表:CLI 与 reporter 统一从这里取文案,避免散落硬编码。
|
|
7
8
|
var translations = {
|
|
8
9
|
zh: {
|
|
9
10
|
noPathsProvided: function () { return '未提供文件或目录路径,跳过代码扫描'; },
|
|
@@ -232,8 +233,10 @@ var translations = {
|
|
|
232
233
|
},
|
|
233
234
|
},
|
|
234
235
|
};
|
|
236
|
+
// 当前语言与翻译器为全局单例,方便在各处同步使用。
|
|
235
237
|
var currentLanguage = 'zh';
|
|
236
238
|
var currentTranslator = translations.zh;
|
|
239
|
+
// 对输入语言进行归一化,未知语言回退到中文。
|
|
237
240
|
function normalizeLanguage(input) {
|
|
238
241
|
if (!input) {
|
|
239
242
|
return 'zh';
|
|
@@ -253,9 +256,11 @@ function setLanguage(language) {
|
|
|
253
256
|
currentTranslator = translations[normalized];
|
|
254
257
|
return currentTranslator;
|
|
255
258
|
}
|
|
259
|
+
// 获取当前语言标识(用于 reporter 输出与规则文案)。
|
|
256
260
|
function getLanguage() {
|
|
257
261
|
return currentLanguage;
|
|
258
262
|
}
|
|
263
|
+
// 获取当前翻译器(用于 CLI/报错/提示文案)。
|
|
259
264
|
function getTranslator() {
|
|
260
265
|
return currentTranslator;
|
|
261
266
|
}
|
package/dist/index.js
CHANGED
|
@@ -386,6 +386,7 @@ function analyzeFile(file, rules, format, log) {
|
|
|
386
386
|
}
|
|
387
387
|
function normalizeViolationInput(input, spanArg) {
|
|
388
388
|
var _a;
|
|
389
|
+
// 规则既可以直接输出字符串,也可以输出结构化对象;这里统一为标准格式。
|
|
389
390
|
if (typeof input === 'string') {
|
|
390
391
|
return {
|
|
391
392
|
message: input,
|
|
@@ -436,6 +437,7 @@ function normalizeViolationInput(input, spanArg) {
|
|
|
436
437
|
span: spanArg,
|
|
437
438
|
};
|
|
438
439
|
}
|
|
440
|
+
// CLI 输出格式解析:仅允许 text/json。
|
|
439
441
|
function parseOutputFormat(value) {
|
|
440
442
|
if (!value) {
|
|
441
443
|
return 'text';
|
|
@@ -477,6 +479,7 @@ function formatViolationForJson(violation) {
|
|
|
477
479
|
return payload;
|
|
478
480
|
}
|
|
479
481
|
function formatJsonOutput(result) {
|
|
482
|
+
// JSON 输出用于 CI/脚本解析,保持结构稳定。
|
|
480
483
|
return {
|
|
481
484
|
summary: {
|
|
482
485
|
scannedFiles: result.scannedFiles,
|
package/dist/report/index.js
CHANGED
|
@@ -30,6 +30,7 @@ var consola_1 = __importDefault(require("consola"));
|
|
|
30
30
|
var i18n_1 = require("../i18n");
|
|
31
31
|
var UNTAGGED_TAG = 'untagged';
|
|
32
32
|
var DEFAULT_FORMAT = 'text';
|
|
33
|
+
// 不同严重级别映射到不同日志级别。
|
|
33
34
|
var severityLoggers = (_a = {},
|
|
34
35
|
_a[auto_cr_rules_1.RuleSeverity.Error] = consola_1.default.error,
|
|
35
36
|
_a[auto_cr_rules_1.RuleSeverity.Warning] = consola_1.default.warn,
|
|
@@ -43,6 +44,7 @@ function createReporter(filePath, source, options) {
|
|
|
43
44
|
var language = (0, i18n_1.getLanguage)();
|
|
44
45
|
var records = [];
|
|
45
46
|
var format = (_a = options.format) !== null && _a !== void 0 ? _a : DEFAULT_FORMAT;
|
|
47
|
+
// 累计单文件的违规统计,便于输出文件级 summary。
|
|
46
48
|
var totalViolations = 0;
|
|
47
49
|
var errorViolations = 0;
|
|
48
50
|
var severityCounts = {
|
|
@@ -94,6 +96,7 @@ function createReporter(filePath, source, options) {
|
|
|
94
96
|
var _a, _b;
|
|
95
97
|
var tag = (_a = rule.tag) !== null && _a !== void 0 ? _a : UNTAGGED_TAG;
|
|
96
98
|
var severity = (_b = rule.severity) !== null && _b !== void 0 ? _b : auto_cr_rules_1.RuleSeverity.Error;
|
|
99
|
+
// 规则级 reporter 会把具体信息写入 records。
|
|
97
100
|
var store = function (payload) {
|
|
98
101
|
pushRecord({
|
|
99
102
|
tag: tag,
|
|
@@ -137,6 +140,7 @@ function createReporter(filePath, source, options) {
|
|
|
137
140
|
};
|
|
138
141
|
return reporterWithRecord;
|
|
139
142
|
};
|
|
143
|
+
// flush 会输出(text 模式)并返回结构化 summary,同时重置内部状态。
|
|
140
144
|
var flush = function () {
|
|
141
145
|
var violationSnapshot = records.map(function (record) { return (__assign(__assign({}, record), { suggestions: record.suggestions ? __spreadArray([], record.suggestions, true) : undefined })); });
|
|
142
146
|
var summary = {
|
|
@@ -186,6 +190,7 @@ function createReporter(filePath, source, options) {
|
|
|
186
190
|
resetCounters();
|
|
187
191
|
return summary;
|
|
188
192
|
};
|
|
193
|
+
// 每次 flush 后清零,避免跨文件混淆统计。
|
|
189
194
|
var resetCounters = function () {
|
|
190
195
|
totalViolations = 0;
|
|
191
196
|
errorViolations = 0;
|
package/dist/rules/loader.js
CHANGED
|
@@ -10,7 +10,9 @@ var consola_1 = require("consola");
|
|
|
10
10
|
var file_1 = require("../utils/file");
|
|
11
11
|
var i18n_1 = require("../i18n");
|
|
12
12
|
var auto_cr_rules_1 = require("auto-cr-rules");
|
|
13
|
+
// 自定义规则加载器:只解析 JS/CJS/MJS 文件,便于在运行时动态引入。
|
|
13
14
|
var SUPPORTED_EXTENSIONS = ['.js', '.cjs', '.mjs'];
|
|
15
|
+
// 从指定目录读取规则文件,并转换为 Rule 列表。
|
|
14
16
|
function loadCustomRules(ruleDir) {
|
|
15
17
|
var t = (0, i18n_1.getTranslator)();
|
|
16
18
|
if (!ruleDir) {
|
|
@@ -30,6 +32,7 @@ function loadCustomRules(ruleDir) {
|
|
|
30
32
|
try {
|
|
31
33
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
32
34
|
var moduleExports = require(file);
|
|
35
|
+
// 支持模块直接导出 rule / rules / default / 数组。
|
|
33
36
|
var rules = extractRules(moduleExports, file);
|
|
34
37
|
if (!rules.length) {
|
|
35
38
|
consola_1.consola.warn(t.customRuleNoExport({ file: file }));
|
|
@@ -43,6 +46,7 @@ function loadCustomRules(ruleDir) {
|
|
|
43
46
|
}
|
|
44
47
|
return loaded;
|
|
45
48
|
}
|
|
49
|
+
// 兼容多种导出形态:默认导出、命名导出或数组。
|
|
46
50
|
function extractRules(moduleExports, origin) {
|
|
47
51
|
var collected = [];
|
|
48
52
|
collected.push.apply(collected, normalizeCandidate(moduleExports, origin));
|
|
@@ -60,6 +64,7 @@ function extractRules(moduleExports, origin) {
|
|
|
60
64
|
}
|
|
61
65
|
return collected;
|
|
62
66
|
}
|
|
67
|
+
// 把候选导出统一转为 Rule;无法识别的会被忽略。
|
|
63
68
|
function normalizeCandidate(candidate, origin) {
|
|
64
69
|
if (!candidate) {
|
|
65
70
|
return [];
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export declare const readFile: (path: string) => string;
|
|
2
2
|
/**
|
|
3
3
|
* 递归获取目录下所有 TypeScript 和 JavaScript 文件
|
|
4
|
+
* - 默认跳过 node_modules
|
|
5
|
+
* - 可通过 shouldIgnore 进一步过滤路径
|
|
4
6
|
*/
|
|
5
7
|
export declare function getAllFiles(dirPath: string, arrayOfFiles?: string[], extensions?: string[], options?: {
|
|
6
8
|
skipNodeModules?: boolean;
|
package/dist/utils/file.js
CHANGED
|
@@ -10,12 +10,15 @@ var fs_1 = __importDefault(require("fs"));
|
|
|
10
10
|
var path_1 = __importDefault(require("path"));
|
|
11
11
|
var consola_1 = require("consola");
|
|
12
12
|
var i18n_1 = require("../i18n");
|
|
13
|
+
// 统一读取文本文件(UTF-8),供解析与规则执行使用。
|
|
13
14
|
var readFile = function (path) {
|
|
14
15
|
return fs_1.default.readFileSync(path, 'utf-8');
|
|
15
16
|
};
|
|
16
17
|
exports.readFile = readFile;
|
|
17
18
|
/**
|
|
18
19
|
* 递归获取目录下所有 TypeScript 和 JavaScript 文件
|
|
20
|
+
* - 默认跳过 node_modules
|
|
21
|
+
* - 可通过 shouldIgnore 进一步过滤路径
|
|
19
22
|
*/
|
|
20
23
|
function getAllFiles(dirPath, arrayOfFiles, extensions, options) {
|
|
21
24
|
if (arrayOfFiles === void 0) { arrayOfFiles = []; }
|
package/dist/utils/stdin.js
CHANGED
|
@@ -37,6 +37,10 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.readPathsFromStdin = readPathsFromStdin;
|
|
40
|
+
// 从 STDIN 读取路径列表:
|
|
41
|
+
// - 默认仅在非 TTY 时读取;
|
|
42
|
+
// - 支持 NUL 分隔与换行分隔两种格式;
|
|
43
|
+
// - 保留空格,仅移除空行与 CR。
|
|
40
44
|
function readPathsFromStdin(shouldForceRead) {
|
|
41
45
|
return __awaiter(this, void 0, void 0, function () {
|
|
42
46
|
var shouldRead;
|
|
@@ -75,11 +79,11 @@ function readPathsFromStdin(shouldForceRead) {
|
|
|
75
79
|
if (buf.length === 0) {
|
|
76
80
|
return finish([]);
|
|
77
81
|
}
|
|
78
|
-
//
|
|
82
|
+
// 优先使用 NUL 分隔(适配 xargs -0 等工具),否则按换行切分。
|
|
79
83
|
var hasNul = buf.includes(0); // 0x00
|
|
80
84
|
var payload = buf.toString('utf8');
|
|
81
85
|
var parts = hasNul ? payload.split('\0') : payload.split(/\r?\n/);
|
|
82
|
-
//
|
|
86
|
+
// 保留文件名中的空格,只去掉末尾 CR 并过滤空行。
|
|
83
87
|
var lines = parts
|
|
84
88
|
.map(function (s) { return (s.endsWith('\r') ? s.slice(0, -1) : s); })
|
|
85
89
|
.filter(function (s) { return s.length > 0; });
|