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 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
  }
@@ -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;
@@ -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();
@@ -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,
@@ -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;
@@ -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;
@@ -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 = []; }
@@ -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
- // Prefer NUL-delimited when present; else fall back to newline.
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
- // Preserve spaces in filenames; only strip stray CR and drop empties.
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; });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auto-cr-cmd",
3
- "version": "2.0.78",
3
+ "version": "2.0.79",
4
4
  "description": "Fast automated code review CLI powered by SWC-based static analysis",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/types/index.d.ts",