auto-cr-cmd 2.0.63 → 2.0.66

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
@@ -43,6 +43,9 @@ Common flags:
43
43
  - `--language <zh|en>`: Switch CLI output language (defaults to auto-detection).
44
44
  - `--rule-dir <directory>`: Load additional custom rules from a directory or package.
45
45
  - `--output <text|json>`: Choose between human-friendly text logs or structured JSON results (defaults to `text`).
46
+ - `--config <path>`: Point to a `.autocrrc.json` or `.autocrrc.js` file to enable/disable rules.
47
+ - `--ignore-path <path>`: Point to a `.autocrignore.json` or `.autocrignore.js` file to exclude files/directories from scanning.
48
+ - `--tsconfig <path>`: Use a custom `tsconfig.json` (defaults to `<cwd>/tsconfig.json`).
46
49
  - `--help`: Display the full command reference.
47
50
 
48
51
  Sample output:
@@ -108,6 +111,45 @@ npx auto-cr-cmd --output json -- ./src | jq
108
111
  }
109
112
  ```
110
113
 
114
+ ## Configuration (.autocrrc)
115
+
116
+ - Place `.autocrrc.json` or `.autocrrc.js` in your repo root (search order as listed). Use `--config <path>` to point elsewhere.
117
+ - `rules` accepts `off | warning | error | optimizing | true/false | 0/1/2`; unspecified rules keep their default severity.
118
+
119
+ ```jsonc
120
+ // .autocrrc.json
121
+ {
122
+ "rules": {
123
+ "no-deep-relative-imports": "error",
124
+ "no-swallowed-errors": "off"
125
+ }
126
+ }
127
+ ```
128
+
129
+ ### Ignore paths (.autocrignore)
130
+
131
+ - Place `.autocrignore.json` or `.autocrignore.js` in repo root (search order as listed), or pass `--ignore-path <file>`.
132
+ - Supports glob patterns (picomatch) via JSON/JS arrays (`{ ignore: [...] }`).
133
+
134
+ ```js
135
+ // .autocrignore.js
136
+ module.exports = {
137
+ ignore: ['node_modules', 'dist/**', '**/*.test.ts', 'public/**']
138
+ }
139
+ ```
140
+
141
+ ```json
142
+ // .autocrignore.json
143
+ {
144
+ "ignore": [
145
+ "node_modules",
146
+ "dist/**",
147
+ "**/*.test.ts",
148
+ "public/**"
149
+ ]
150
+ }
151
+ ```
152
+
111
153
  ## Writing Custom Rules
112
154
 
113
155
  The CLI consumes rules from the `auto-cr-rules` package by default, and you can extend it with your own logic.
package/README.zh-CN.md CHANGED
@@ -43,6 +43,9 @@ npx auto-cr-cmd --language zh [需要扫描的代码目录]
43
43
  - `--language <zh|en>`:切换 CLI 输出语言(默认为自动检测)。
44
44
  - `--rule-dir <directory>`:加载额外的自定义规则目录或包。
45
45
  - `--output <text|json>`:选择输出格式,`text` 为友好的终端日志,`json` 用于集成脚本(默认为 `text`)。
46
+ - `--config <path>`:指定 `.autocrrc.json` 或 `.autocrrc.js` 配置文件路径,用于开启/关闭规则。
47
+ - `--ignore-path <path>`:指定 `.autocrignore.json` 或 `.autocrignore.js` 忽略文件路径,用于排除扫描。
48
+ - `--tsconfig <path>`:指定自定义 `tsconfig.json` 路径(默认读取 `<cwd>/tsconfig.json`)。
46
49
  - `--help`:查看完整命令说明。
47
50
 
48
51
  示例输出:
@@ -108,6 +111,55 @@ npx auto-cr-cmd --output json -- ./src | jq
108
111
  }
109
112
  ```
110
113
 
114
+ ## 配置(.autocrrc)
115
+
116
+ - 在仓库根目录放置 `.autocrrc.json` 或 `.autocrrc.js`(按此顺序查找);如需放在其他位置,可通过 `--config <path>` 指定。
117
+ - `rules` 支持的值:`off | warning | error | optimizing | true/false | 0/1/2`,未写明的规则沿用默认严重级别。
118
+
119
+ ```jsonc
120
+ // .autocrrc.json
121
+ {
122
+ "rules": {
123
+ "no-deep-relative-imports": "error",
124
+ "no-swallowed-errors": "off"
125
+ }
126
+ }
127
+ ```
128
+
129
+ ### 忽略文件(.autocrignore)
130
+
131
+ - 在仓库根目录放置 `.autocrignore.json` 或 `.autocrignore.js`(按此顺序查找),或通过 `--ignore-path <file>` 指定自定义路径。
132
+ - 仅支持 JSON/JS 写法,基于 picomatch 的 glob 模式,数组键为 `ignore`。
133
+
134
+ ```js
135
+ // .autocrignore.js
136
+ module.exports = {
137
+ ignore: ['node_modules', 'dist/**', '**/*.test.ts', 'public/**']
138
+ }
139
+ ```
140
+
141
+ ```json
142
+ // .autocrignore.json
143
+ {
144
+ "ignore": [
145
+ "node_modules",
146
+ "dist/**",
147
+ "**/*.test.ts",
148
+ "public/**"
149
+ ]
150
+ }
151
+ ```
152
+
153
+ ```js
154
+ // .autocrrc.js
155
+ module.exports = {
156
+ rules: {
157
+ 'no-swallowed-errors': 'warning', // 覆盖严重级别
158
+ 'no-deep-relative-imports': true // 保持规则默认严重级别
159
+ }
160
+ }
161
+ ```
162
+
111
163
  ## 编写自定义规则
112
164
 
113
165
  CLI 默认使用 `auto-cr-rules` 包提供的规则,你也可以扩展自己的逻辑。
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.loadAutoCrRc = loadAutoCrRc;
18
+ exports.applyRuleConfig = applyRuleConfig;
19
+ var fs_1 = __importDefault(require("fs"));
20
+ var path_1 = __importDefault(require("path"));
21
+ var auto_cr_rules_1 = require("auto-cr-rules");
22
+ var i18n_1 = require("../i18n");
23
+ var RC_CANDIDATES = ['.autocrrc.json', '.autocrrc.js'];
24
+ function loadAutoCrRc(configPath) {
25
+ var warnings = [];
26
+ var t = (0, i18n_1.getTranslator)();
27
+ var resolvedPath = resolveConfigPath(configPath);
28
+ if (!resolvedPath) {
29
+ return { warnings: warnings };
30
+ }
31
+ if (!fs_1.default.existsSync(resolvedPath)) {
32
+ warnings.push(t.autocrrcPathMissing({ path: resolvedPath }));
33
+ return { warnings: warnings };
34
+ }
35
+ try {
36
+ var raw = readConfigFile(resolvedPath);
37
+ var config = unwrapDefault(raw);
38
+ if (!isRecord(config)) {
39
+ warnings.push(t.autocrrcInvalidFormat({ path: resolvedPath }));
40
+ return { warnings: warnings };
41
+ }
42
+ if (config.rules !== undefined && !isRecord(config.rules)) {
43
+ warnings.push(t.autocrrcInvalidRulesField({ path: resolvedPath }));
44
+ return { warnings: warnings };
45
+ }
46
+ return {
47
+ path: resolvedPath,
48
+ rules: config.rules,
49
+ warnings: warnings,
50
+ };
51
+ }
52
+ catch (error) {
53
+ var detail = error instanceof Error ? error.message : String(error);
54
+ warnings.push(t.autocrrcLoadFailed({ path: resolvedPath, error: detail }));
55
+ return { warnings: warnings };
56
+ }
57
+ }
58
+ function applyRuleConfig(rules, ruleSettings, onWarning) {
59
+ if (!ruleSettings || Object.keys(ruleSettings).length === 0) {
60
+ return rules;
61
+ }
62
+ var t = (0, i18n_1.getTranslator)();
63
+ var configured = [];
64
+ for (var _i = 0, rules_1 = rules; _i < rules_1.length; _i++) {
65
+ var rule = rules_1[_i];
66
+ var hasSetting = Object.prototype.hasOwnProperty.call(ruleSettings, rule.name);
67
+ if (!hasSetting) {
68
+ configured.push(rule);
69
+ continue;
70
+ }
71
+ var rawSetting = ruleSettings[rule.name];
72
+ var normalized = normalizeRuleSetting(rawSetting);
73
+ if (normalized === 'off') {
74
+ continue;
75
+ }
76
+ if (normalized === null) {
77
+ onWarning(t.autocrrcInvalidRuleSetting({ ruleName: rule.name, value: stringifyValue(rawSetting) }));
78
+ configured.push(rule);
79
+ continue;
80
+ }
81
+ if (normalized === undefined) {
82
+ configured.push(rule);
83
+ continue;
84
+ }
85
+ configured.push(__assign(__assign({}, rule), { severity: normalized }));
86
+ }
87
+ return configured;
88
+ }
89
+ function resolveConfigPath(explicitPath) {
90
+ if (explicitPath) {
91
+ return path_1.default.isAbsolute(explicitPath) ? explicitPath : path_1.default.resolve(process.cwd(), explicitPath);
92
+ }
93
+ for (var _i = 0, RC_CANDIDATES_1 = RC_CANDIDATES; _i < RC_CANDIDATES_1.length; _i++) {
94
+ var candidate = RC_CANDIDATES_1[_i];
95
+ var resolved = path_1.default.resolve(process.cwd(), candidate);
96
+ if (fs_1.default.existsSync(resolved)) {
97
+ return resolved;
98
+ }
99
+ }
100
+ return null;
101
+ }
102
+ function readConfigFile(filePath) {
103
+ if (filePath.endsWith('.json')) {
104
+ var raw = fs_1.default.readFileSync(filePath, 'utf-8');
105
+ return JSON.parse(raw);
106
+ }
107
+ if (filePath.endsWith('.js')) {
108
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
109
+ return require(filePath);
110
+ }
111
+ return {};
112
+ }
113
+ function unwrapDefault(value) {
114
+ var _a;
115
+ if (isRecord(value) && 'default' in value) {
116
+ return (_a = value.default) !== null && _a !== void 0 ? _a : value;
117
+ }
118
+ return value;
119
+ }
120
+ function isRecord(value) {
121
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
122
+ }
123
+ function normalizeRuleSetting(input) {
124
+ if (input === undefined) {
125
+ return undefined;
126
+ }
127
+ if (input === null) {
128
+ return null;
129
+ }
130
+ if (typeof input === 'boolean') {
131
+ return input ? undefined : 'off';
132
+ }
133
+ if (typeof input === 'number') {
134
+ if (input === 0)
135
+ return 'off';
136
+ if (input === 1)
137
+ return auto_cr_rules_1.RuleSeverity.Warning;
138
+ if (input === 2)
139
+ return auto_cr_rules_1.RuleSeverity.Error;
140
+ return null;
141
+ }
142
+ if (typeof input === 'string') {
143
+ var normalized = input.toLowerCase();
144
+ if (normalized === 'off' || normalized === 'disable' || normalized === 'disabled') {
145
+ return 'off';
146
+ }
147
+ if (normalized === 'warn' || normalized === 'warning') {
148
+ return auto_cr_rules_1.RuleSeverity.Warning;
149
+ }
150
+ if (normalized === 'error') {
151
+ return auto_cr_rules_1.RuleSeverity.Error;
152
+ }
153
+ if (normalized === 'optimizing' || normalized === 'optimize' || normalized === 'optimise') {
154
+ return auto_cr_rules_1.RuleSeverity.Optimizing;
155
+ }
156
+ return null;
157
+ }
158
+ if (input === auto_cr_rules_1.RuleSeverity.Error || input === auto_cr_rules_1.RuleSeverity.Warning || input === auto_cr_rules_1.RuleSeverity.Optimizing) {
159
+ return input;
160
+ }
161
+ return null;
162
+ }
163
+ function stringifyValue(value) {
164
+ if (typeof value === 'string') {
165
+ return "\"".concat(value, "\"");
166
+ }
167
+ try {
168
+ return JSON.stringify(value);
169
+ }
170
+ catch (_a) {
171
+ return String(value);
172
+ }
173
+ }
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadIgnoreConfig = loadIgnoreConfig;
7
+ exports.createIgnoreMatcher = createIgnoreMatcher;
8
+ var fs_1 = __importDefault(require("fs"));
9
+ var path_1 = __importDefault(require("path"));
10
+ var picomatch_1 = __importDefault(require("picomatch"));
11
+ var i18n_1 = require("../i18n");
12
+ var IGNORE_CANDIDATES = ['.autocrignore.json', '.autocrignore.js'];
13
+ function loadIgnoreConfig(configPath) {
14
+ var warnings = [];
15
+ var t = (0, i18n_1.getTranslator)();
16
+ var resolvedPath = resolveConfigPath(configPath);
17
+ if (!resolvedPath) {
18
+ return { patterns: [], warnings: warnings, baseDir: process.cwd() };
19
+ }
20
+ if (!fs_1.default.existsSync(resolvedPath)) {
21
+ warnings.push(t.autocrignorePathMissing({ path: resolvedPath }));
22
+ return { patterns: [], warnings: warnings, baseDir: process.cwd() };
23
+ }
24
+ var baseDir = path_1.default.dirname(resolvedPath);
25
+ try {
26
+ var raw = readIgnoreFile(resolvedPath);
27
+ var patterns = normalizeIgnorePayload(raw);
28
+ if (!patterns.length) {
29
+ warnings.push(t.autocrignoreInvalidFormat({ path: resolvedPath }));
30
+ }
31
+ return { path: resolvedPath, patterns: patterns, warnings: warnings, baseDir: baseDir };
32
+ }
33
+ catch (error) {
34
+ var detail = error instanceof Error ? error.message : String(error);
35
+ warnings.push(t.autocrignoreLoadFailed({ path: resolvedPath, error: detail }));
36
+ return { patterns: [], warnings: warnings, baseDir: baseDir };
37
+ }
38
+ }
39
+ function createIgnoreMatcher(patterns, baseDir) {
40
+ if (baseDir === void 0) { baseDir = process.cwd(); }
41
+ if (!patterns.length) {
42
+ return function () { return false; };
43
+ }
44
+ var cwd = baseDir;
45
+ var matchers = patterns
46
+ .map(function (pattern) { return (0, picomatch_1.default)(pattern, { dot: true, nocase: false, posix: true }); })
47
+ .filter(function (matcher) { return matcher !== null; });
48
+ return function (candidate) {
49
+ var normalized = toPosix(candidate);
50
+ var relative = toPosix(path_1.default.relative(cwd, candidate));
51
+ return matchers.some(function (matcher) { return matcher(normalized) || matcher(relative); });
52
+ };
53
+ }
54
+ function resolveConfigPath(explicitPath) {
55
+ if (explicitPath) {
56
+ return path_1.default.isAbsolute(explicitPath) ? explicitPath : path_1.default.resolve(process.cwd(), explicitPath);
57
+ }
58
+ for (var _i = 0, IGNORE_CANDIDATES_1 = IGNORE_CANDIDATES; _i < IGNORE_CANDIDATES_1.length; _i++) {
59
+ var candidate = IGNORE_CANDIDATES_1[_i];
60
+ var resolved = path_1.default.resolve(process.cwd(), candidate);
61
+ if (fs_1.default.existsSync(resolved)) {
62
+ return resolved;
63
+ }
64
+ }
65
+ return null;
66
+ }
67
+ function readIgnoreFile(filePath) {
68
+ if (filePath.endsWith('.json')) {
69
+ var raw = fs_1.default.readFileSync(filePath, 'utf-8');
70
+ return JSON.parse(raw);
71
+ }
72
+ if (filePath.endsWith('.js')) {
73
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
74
+ return require(filePath);
75
+ }
76
+ return [];
77
+ }
78
+ function normalizeIgnorePayload(payload) {
79
+ var values = [];
80
+ if (Array.isArray(payload)) {
81
+ for (var _i = 0, payload_1 = payload; _i < payload_1.length; _i++) {
82
+ var entry = payload_1[_i];
83
+ var normalized = normalizeEntry(entry);
84
+ if (normalized)
85
+ values.push(normalized);
86
+ }
87
+ return values;
88
+ }
89
+ if (isRecord(payload) && payload.ignore) {
90
+ return normalizeIgnorePayload(payload.ignore);
91
+ }
92
+ if (isRecord(payload) && payload.default) {
93
+ return normalizeIgnorePayload(payload.default);
94
+ }
95
+ if (typeof payload === 'string') {
96
+ return normalizeIgnorePayload(payload.split(/\r?\n/));
97
+ }
98
+ return values;
99
+ }
100
+ function normalizeEntry(entry) {
101
+ if (typeof entry !== 'string') {
102
+ return null;
103
+ }
104
+ var trimmed = entry.trim();
105
+ if (!trimmed || trimmed.startsWith('#')) {
106
+ return null;
107
+ }
108
+ return trimmed;
109
+ }
110
+ function isRecord(value) {
111
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
112
+ }
113
+ function toPosix(p) {
114
+ return p.split(path_1.default.sep).join('/');
115
+ }
package/dist/config.js CHANGED
@@ -14,17 +14,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.setTsConfigPath = setTsConfigPath;
17
18
  exports.loadParseOptions = loadParseOptions;
18
19
  var fs_1 = __importDefault(require("fs"));
19
20
  var path_1 = __importDefault(require("path"));
20
21
  var i18n_1 = require("./i18n");
21
22
  var consola_1 = __importDefault(require("consola"));
22
23
  var cachedTsConfig;
24
+ var tsConfigPathOverride = null;
25
+ function setTsConfigPath(path) {
26
+ tsConfigPathOverride = path ? path : null;
27
+ cachedTsConfig = undefined;
28
+ }
23
29
  function readTsConfig() {
24
30
  if (cachedTsConfig !== undefined) {
25
31
  return cachedTsConfig;
26
32
  }
27
- var tsConfigPath = path_1.default.resolve(process.cwd(), 'tsconfig.json');
33
+ var tsConfigPath = tsConfigPathOverride !== null && tsConfigPathOverride !== void 0 ? tsConfigPathOverride : path_1.default.resolve(process.cwd(), 'tsconfig.json');
28
34
  if (!fs_1.default.existsSync(tsConfigPath)) {
29
35
  cachedTsConfig = null;
30
36
  return cachedTsConfig;
@@ -45,6 +45,39 @@ var translations = {
45
45
  var file = _a.file;
46
46
  return "\u52A0\u8F7D\u81EA\u5B9A\u4E49\u89C4\u5219\u5931\u8D25: ".concat(file);
47
47
  },
48
+ autocrrcPathMissing: function (_a) {
49
+ var path = _a.path;
50
+ return "\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728: ".concat(path);
51
+ },
52
+ autocrrcLoadFailed: function (_a) {
53
+ var path = _a.path, error = _a.error;
54
+ return "\u8BFB\u53D6 .autocrrc \u914D\u7F6E\u5931\u8D25 (".concat(path, "): ").concat(error);
55
+ },
56
+ autocrrcInvalidFormat: function (_a) {
57
+ var path = _a.path;
58
+ return "\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u65E0\u6548\uFF08\u9700\u5BFC\u51FA\u5BF9\u8C61\uFF09: ".concat(path);
59
+ },
60
+ autocrrcInvalidRulesField: function (_a) {
61
+ var path = _a.path;
62
+ return "\u914D\u7F6E\u6587\u4EF6 rules \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61: ".concat(path);
63
+ },
64
+ autocrrcInvalidRuleSetting: function (_a) {
65
+ var ruleName = _a.ruleName, value = _a.value;
66
+ return "\u89C4\u5219 ".concat(ruleName, " \u7684\u914D\u7F6E\u503C\u65E0\u6548: ").concat(value, "\u3002\u53EF\u9009: off | warning | error | optimizing | true/false | 0/1/2");
67
+ },
68
+ autocrrcAllRulesDisabled: function () { return '配置已关闭所有规则,跳过扫描'; },
69
+ autocrignorePathMissing: function (_a) {
70
+ var path = _a.path;
71
+ return "\u5FFD\u7565\u6587\u4EF6\u4E0D\u5B58\u5728: ".concat(path);
72
+ },
73
+ autocrignoreLoadFailed: function (_a) {
74
+ var path = _a.path, error = _a.error;
75
+ return "\u8BFB\u53D6 .autocrignore \u5931\u8D25 (".concat(path, "): ").concat(error);
76
+ },
77
+ autocrignoreInvalidFormat: function (_a) {
78
+ var path = _a.path;
79
+ return "\u5FFD\u7565\u6587\u4EF6\u683C\u5F0F\u65E0\u6548\uFF08\u9700\u63D0\u4F9B\u5B57\u7B26\u4E32\u6570\u7EC4\u6216\u9010\u884C\u6A21\u5F0F\uFF09: ".concat(path);
80
+ },
48
81
  tsconfigReadFailed: function () { return '警告: 无法读取 tsconfig.json'; },
49
82
  reporterSeverityLabel: function (_a) {
50
83
  var severity = _a.severity;
@@ -125,6 +158,39 @@ var translations = {
125
158
  var file = _a.file;
126
159
  return "Failed to load custom rule: ".concat(file);
127
160
  },
161
+ autocrrcPathMissing: function (_a) {
162
+ var path = _a.path;
163
+ return "Config file not found: ".concat(path);
164
+ },
165
+ autocrrcLoadFailed: function (_a) {
166
+ var path = _a.path, error = _a.error;
167
+ return "Failed to read .autocrrc config (".concat(path, "): ").concat(error);
168
+ },
169
+ autocrrcInvalidFormat: function (_a) {
170
+ var path = _a.path;
171
+ return "Invalid config format (should export an object): ".concat(path);
172
+ },
173
+ autocrrcInvalidRulesField: function (_a) {
174
+ var path = _a.path;
175
+ return "Config \"rules\" field must be an object: ".concat(path);
176
+ },
177
+ autocrrcInvalidRuleSetting: function (_a) {
178
+ var ruleName = _a.ruleName, value = _a.value;
179
+ return "Invalid setting for rule ".concat(ruleName, ": ").concat(value, ". Use off | warning | error | optimizing | true/false | 0/1/2");
180
+ },
181
+ autocrrcAllRulesDisabled: function () { return 'All rules are disabled by config; skipping scan'; },
182
+ autocrignorePathMissing: function (_a) {
183
+ var path = _a.path;
184
+ return "Ignore file not found: ".concat(path);
185
+ },
186
+ autocrignoreLoadFailed: function (_a) {
187
+ var path = _a.path, error = _a.error;
188
+ return "Failed to read .autocrignore (".concat(path, "): ").concat(error);
189
+ },
190
+ autocrignoreInvalidFormat: function (_a) {
191
+ var path = _a.path;
192
+ return "Invalid ignore file format (expect string array or line-based list): ".concat(path);
193
+ },
128
194
  tsconfigReadFailed: function () { return 'Warning: Failed to read tsconfig.json'; },
129
195
  reporterSeverityLabel: function (_a) {
130
196
  var severity = _a.severity;
package/dist/index.js CHANGED
@@ -73,6 +73,8 @@ var file_1 = require("./utils/file");
73
73
  var stdin_1 = require("./utils/stdin");
74
74
  var auto_cr_rules_1 = require("auto-cr-rules");
75
75
  var loader_1 = require("./rules/loader");
76
+ var autocrrc_1 = require("./config/autocrrc");
77
+ var ignore_1 = require("./config/ignore");
76
78
  consola_1.consola.options.formatOptions = __assign(__assign({}, consola_1.consola.options.formatOptions), { date: false });
77
79
  var consolaLoggers = {
78
80
  info: consola_1.consola.info.bind(consola_1.consola),
@@ -80,8 +82,8 @@ var consolaLoggers = {
80
82
  error: consola_1.consola.error.bind(consola_1.consola),
81
83
  };
82
84
  function run() {
83
- return __awaiter(this, arguments, void 0, function (filePaths, ruleDir, format) {
84
- var t, notifications, log, validPaths, allFiles, _i, validPaths_1, targetPath, stat, directoryFiles, scannableFiles, customRules, rules, filesWithErrors, filesWithWarnings, filesWithOptimizing, totalViolations, totalErrorViolations, totalWarningViolations, totalOptimizingViolations, fileSummaries, _a, scannableFiles_1, file, summary, error_1;
85
+ return __awaiter(this, arguments, void 0, function (filePaths, ruleDir, format, configPath, ignorePath) {
86
+ var t, notifications, log, validPaths, ignoreConfig, isIgnored_1, allFiles, _i, validPaths_1, targetPath, stat, directoryFiles, scannableFiles, customRules, rcConfig, rules, filesWithErrors, filesWithWarnings, filesWithOptimizing, totalViolations, totalErrorViolations, totalWarningViolations, totalOptimizingViolations, fileSummaries, _a, scannableFiles_1, file, summary, error_1;
85
87
  if (filePaths === void 0) { filePaths = []; }
86
88
  return __generator(this, function (_b) {
87
89
  switch (_b.label) {
@@ -145,15 +147,25 @@ function run() {
145
147
  notifications: notifications,
146
148
  }];
147
149
  }
150
+ ignoreConfig = (0, ignore_1.loadIgnoreConfig)(ignorePath);
151
+ ignoreConfig.warnings.forEach(function (warning) { return log('warn', warning); });
152
+ isIgnored_1 = (0, ignore_1.createIgnoreMatcher)(ignoreConfig.patterns, ignoreConfig.baseDir);
148
153
  allFiles = [];
149
154
  for (_i = 0, validPaths_1 = validPaths; _i < validPaths_1.length; _i++) {
150
155
  targetPath = validPaths_1[_i];
156
+ if (isIgnored_1(targetPath)) {
157
+ continue;
158
+ }
151
159
  stat = fs_1.default.statSync(targetPath);
152
160
  if (stat.isFile()) {
153
- allFiles.push(targetPath);
161
+ if (!isIgnored_1(targetPath)) {
162
+ allFiles.push(targetPath);
163
+ }
154
164
  }
155
165
  else if (stat.isDirectory()) {
156
- directoryFiles = (0, file_1.getAllFiles)(targetPath);
166
+ directoryFiles = (0, file_1.getAllFiles)(targetPath, [], ['.ts', '.tsx', '.js', '.jsx'], {
167
+ shouldIgnore: function (fullPath) { return isIgnored_1(fullPath); },
168
+ });
157
169
  allFiles = __spreadArray(__spreadArray([], allFiles, true), directoryFiles, true);
158
170
  }
159
171
  }
@@ -169,11 +181,15 @@ function run() {
169
181
  notifications: notifications,
170
182
  }];
171
183
  }
172
- scannableFiles = allFiles.filter(function (candidate) { return !candidate.endsWith('.d.ts'); });
184
+ scannableFiles = allFiles.filter(function (candidate) { return !candidate.endsWith('.d.ts') && !isIgnored_1(candidate); });
173
185
  customRules = (0, loader_1.loadCustomRules)(ruleDir);
174
- rules = __spreadArray(__spreadArray([], auto_cr_rules_1.builtinRules, true), customRules, true);
186
+ rcConfig = (0, autocrrc_1.loadAutoCrRc)(configPath);
187
+ rcConfig.warnings.forEach(function (warning) { return log('warn', warning); });
188
+ rules = (0, autocrrc_1.applyRuleConfig)(__spreadArray(__spreadArray([], auto_cr_rules_1.builtinRules, true), customRules, true), rcConfig.rules, function (warning) {
189
+ return log('warn', warning);
190
+ });
175
191
  if (rules.length === 0) {
176
- log('warn', t.noRulesLoaded());
192
+ log('warn', rcConfig.rules ? t.autocrrcAllRulesDisabled() : t.noRulesLoaded());
177
193
  return [2 /*return*/, {
178
194
  scannedFiles: 0,
179
195
  filesWithErrors: 0,
@@ -464,11 +480,15 @@ commander_1.program
464
480
  .option('-r, --rule-dir <directory>', '自定义规则目录路径 / Custom rule directory')
465
481
  .option('-l, --language <language>', '设置 CLI 语言 (zh/en) / Set CLI language (zh/en)')
466
482
  .option('-o, --output <format>', '设置输出格式 (text/json) / Output format (text/json)', 'text')
483
+ .option('-c, --config <path>', '配置文件路径 (.autocrrc.json|.autocrrc.js) / Config file path (.autocrrc.json|.autocrrc.js)')
484
+ .option('--ignore-path <path>', '忽略文件列表路径 (.autocrignore.json|.autocrignore.js) / Ignore file path (.autocrignore.json|.autocrignore.js)')
485
+ .option('--tsconfig <path>', '自定义 tsconfig 路径 / Custom tsconfig path')
467
486
  .option('--stdin', '从标准输入读取扫描路径 / Read file paths from STDIN')
468
487
  .parse(process.argv);
469
488
  var options = commander_1.program.opts();
470
489
  var cliArguments = commander_1.program.args;
471
490
  (0, i18n_1.setLanguage)((_a = options.language) !== null && _a !== void 0 ? _a : process.env.LANG);
491
+ (0, config_1.setTsConfigPath)(options.tsconfig ? path_1.default.resolve(process.cwd(), options.tsconfig) : undefined);
472
492
  var outputFormat;
473
493
  try {
474
494
  outputFormat = parseOutputFormat(options.output);
@@ -490,7 +510,7 @@ catch (error) {
490
510
  stdinTargets = _a.sent();
491
511
  combinedTargets = __spreadArray(__spreadArray([], cliArguments, true), stdinTargets, true);
492
512
  filePaths = combinedTargets.map(function (target) { return path_1.default.resolve(process.cwd(), target); });
493
- return [4 /*yield*/, run(filePaths, options.ruleDir, outputFormat)];
513
+ return [4 /*yield*/, run(filePaths, options.ruleDir, outputFormat, options.config, options.ignorePath)];
494
514
  case 2:
495
515
  result = _a.sent();
496
516
  t = (0, i18n_1.getTranslator)();
@@ -0,0 +1,13 @@
1
+ import { RuleSeverity, type Rule } from 'auto-cr-rules';
2
+ type RuleSettingInput = RuleSeverity | 'off' | 'warn' | 'warning' | 'error' | 'optimizing' | 0 | 1 | 2 | boolean;
3
+ export interface AutoCrRcConfig {
4
+ rules?: Record<string, RuleSettingInput>;
5
+ }
6
+ export interface LoadedAutoCrRc {
7
+ path?: string;
8
+ rules?: Record<string, RuleSettingInput>;
9
+ warnings: string[];
10
+ }
11
+ export declare function loadAutoCrRc(configPath?: string): LoadedAutoCrRc;
12
+ export declare function applyRuleConfig(rules: Rule[], ruleSettings: Record<string, RuleSettingInput> | undefined, onWarning: (message: string) => void): Rule[];
13
+ export {};
@@ -0,0 +1,8 @@
1
+ export interface LoadedIgnoreConfig {
2
+ path?: string;
3
+ patterns: string[];
4
+ baseDir: string;
5
+ warnings: string[];
6
+ }
7
+ export declare function loadIgnoreConfig(configPath?: string): LoadedIgnoreConfig;
8
+ export declare function createIgnoreMatcher(patterns: string[], baseDir?: string): (candidate: string) => boolean;
@@ -1,2 +1,3 @@
1
1
  import type { ParseOptions } from '@swc/types';
2
+ export declare function setTsConfigPath(path?: string): void;
2
3
  export declare function loadParseOptions(filePath: string): ParseOptions;
@@ -32,6 +32,34 @@ interface Translator {
32
32
  customRuleLoadFailed(params: {
33
33
  file: string;
34
34
  }): string;
35
+ autocrrcPathMissing(params: {
36
+ path: string;
37
+ }): string;
38
+ autocrrcLoadFailed(params: {
39
+ path: string;
40
+ error: string;
41
+ }): string;
42
+ autocrrcInvalidFormat(params: {
43
+ path: string;
44
+ }): string;
45
+ autocrrcInvalidRulesField(params: {
46
+ path: string;
47
+ }): string;
48
+ autocrrcInvalidRuleSetting(params: {
49
+ ruleName: string;
50
+ value: string;
51
+ }): string;
52
+ autocrrcAllRulesDisabled(): string;
53
+ autocrignorePathMissing(params: {
54
+ path: string;
55
+ }): string;
56
+ autocrignoreLoadFailed(params: {
57
+ path: string;
58
+ error: string;
59
+ }): string;
60
+ autocrignoreInvalidFormat(params: {
61
+ path: string;
62
+ }): string;
35
63
  tsconfigReadFailed(): string;
36
64
  reporterSeverityLabel(params: {
37
65
  severity: RuleSeverity;
@@ -2,7 +2,10 @@ export declare const readFile: (path: string) => string;
2
2
  /**
3
3
  * 递归获取目录下所有 TypeScript 和 JavaScript 文件
4
4
  */
5
- export declare function getAllFiles(dirPath: string, arrayOfFiles?: string[], extensions?: string[]): string[];
5
+ export declare function getAllFiles(dirPath: string, arrayOfFiles?: string[], extensions?: string[], options?: {
6
+ skipNodeModules?: boolean;
7
+ shouldIgnore?: (fullPath: string, isDirectory: boolean) => boolean;
8
+ }): string[];
6
9
  /**
7
10
  * 检查文件或目录是否存在
8
11
  */
@@ -17,16 +17,25 @@ exports.readFile = readFile;
17
17
  /**
18
18
  * 递归获取目录下所有 TypeScript 和 JavaScript 文件
19
19
  */
20
- function getAllFiles(dirPath, arrayOfFiles, extensions) {
20
+ function getAllFiles(dirPath, arrayOfFiles, extensions, options) {
21
21
  if (arrayOfFiles === void 0) { arrayOfFiles = []; }
22
22
  if (extensions === void 0) { extensions = ['.ts', '.tsx', '.js', '.jsx']; }
23
+ if (options === void 0) { options = {}; }
23
24
  if (!fs_1.default.existsSync(dirPath))
24
25
  return arrayOfFiles;
26
+ var _a = options.skipNodeModules, skipNodeModules = _a === void 0 ? true : _a;
25
27
  var files = fs_1.default.readdirSync(dirPath);
26
28
  files.forEach(function (file) {
27
29
  var fullPath = path_1.default.join(dirPath, file);
28
- if (fs_1.default.statSync(fullPath).isDirectory()) {
29
- arrayOfFiles = getAllFiles(fullPath, arrayOfFiles, extensions);
30
+ var stats = fs_1.default.statSync(fullPath);
31
+ if (options.shouldIgnore && options.shouldIgnore(fullPath, stats.isDirectory())) {
32
+ return;
33
+ }
34
+ if (stats.isDirectory()) {
35
+ if (skipNodeModules && file === 'node_modules') {
36
+ return;
37
+ }
38
+ arrayOfFiles = getAllFiles(fullPath, arrayOfFiles, extensions, options);
30
39
  }
31
40
  else {
32
41
  if (extensions === null || extensions === void 0 ? void 0 : extensions.some(function (ext) { return fullPath.endsWith(ext); })) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auto-cr-cmd",
3
- "version": "2.0.63",
3
+ "version": "2.0.66",
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",
@@ -46,16 +46,18 @@
46
46
  "sideEffects": false,
47
47
  "dependencies": {
48
48
  "@swc/core": "^1.13.20",
49
- "@swc/wasm": "^1.13.20",
50
- "auto-cr-rules": "^2.0.63",
49
+ "@swc/wasm": "^1.14.0",
50
+ "auto-cr-rules": "^2.0.66",
51
51
  "commander": "^14.0.0",
52
- "consola": "^3.4.2"
52
+ "consola": "^3.4.2",
53
+ "picomatch": "^4.0.3"
53
54
  },
54
55
  "devDependencies": {
55
- "@eslint/js": "^9.37.0",
56
+ "@eslint/js": "^9.38.0",
56
57
  "@swc/types": "^0.1.25",
57
- "@types/node": "^24.7.0",
58
- "eslint": "^9.37.0",
58
+ "@types/node": "^24.9.2",
59
+ "@types/picomatch": "^4.0.2",
60
+ "eslint": "^9.38.0",
59
61
  "eslint-plugin-prettier": "^5.5.4",
60
62
  "globals": "^16.3.0",
61
63
  "jiti": "^2.5.1",
@@ -63,6 +65,6 @@
63
65
  "ts-node": "^10.9.2",
64
66
  "tslib": "^2.8.1",
65
67
  "typescript": "^5.9.2",
66
- "typescript-eslint": "^8.46.0"
68
+ "typescript-eslint": "^8.46.2"
67
69
  }
68
70
  }