smart-review 1.0.1 → 1.0.2

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.
@@ -3,6 +3,7 @@ import path from 'path';
3
3
  import { createRequire } from 'module';
4
4
  import { defaultConfig, defaultRules } from './default-config.js';
5
5
  import { logger } from './utils/logger.js';
6
+ import { t } from './utils/i18n.js';
6
7
 
7
8
  export class ConfigLoader {
8
9
  constructor(projectRoot) {
@@ -51,7 +52,7 @@ export class ConfigLoader {
51
52
  externalConfig = JSON.parse(configContent);
52
53
 
53
54
  } catch (error) {
54
- logger.warn('外部配置文件解析失败,使用默认配置:', error.message);
55
+ logger.warn(t(undefined, 'external_config_parse_failed_warn', { error: error?.message || String(error) }));
55
56
  }
56
57
  }
57
58
 
@@ -72,7 +73,7 @@ export class ConfigLoader {
72
73
  // 根据配置决定规则加载策略
73
74
  if (config.useExternalRulesOnly) {
74
75
  // 仅使用外部规则模式:只返回外部规则,不加载内置规则
75
- logger.info('使用外部规则模式:仅加载 local-rules 目录中的规则');
76
+ logger.info(t(undefined, 'use_external_rules_only_info'));
76
77
  return externalRules;
77
78
  }
78
79
 
@@ -94,8 +95,9 @@ export class ConfigLoader {
94
95
  }
95
96
 
96
97
  const allRules = Array.from(ruleMap.values());
97
-
98
- return allRules;
98
+ // 根据语言本地化规则的展示字段
99
+ const localizedRules = this.localizeRules(allRules, config);
100
+ return localizedRules;
99
101
  }
100
102
 
101
103
  async loadExternalRules() {
@@ -118,7 +120,7 @@ export class ConfigLoader {
118
120
  }
119
121
  }
120
122
  } catch (error) {
121
- logger.warn('加载外部规则失败:', error.message);
123
+ logger.warn(t(undefined, 'load_external_rules_failed_warn', { error: error?.message || String(error) }));
122
124
  }
123
125
 
124
126
  return externalRules;
@@ -169,7 +171,7 @@ export class ConfigLoader {
169
171
  }
170
172
  } catch (tempError) {
171
173
  // 如果临时文件方法失败,回退到原来的 base64 方法
172
- logger.warn(`临时文件方法失败,回退到 base64 方法: ${tempError.message}`);
174
+ logger.warn(t(undefined, 'temp_file_method_failed_fallback_info', { error: tempError?.message || String(tempError) }));
173
175
 
174
176
  // 清理可能已创建的临时文件
175
177
  try {
@@ -201,12 +203,38 @@ export class ConfigLoader {
201
203
  return config.rules || [];
202
204
  }
203
205
  } catch (error) {
204
- logger.warn(`加载规则文件失败 ${filePath}:`, error.message);
206
+ logger.warn(t(undefined, 'load_rule_file_failed_warn', { file: filePath, error: error?.message || String(error) }));
205
207
  }
206
208
 
207
209
  return [];
208
210
  }
209
211
 
212
+ /**
213
+ * 按当前语言对规则 name/message/suggestion 进行本地化。
214
+ * 若翻译键不存在则保留原始内容。
215
+ */
216
+ localizeRules(rules, configOrLocale) {
217
+ if (!Array.isArray(rules) || rules.length === 0) return rules;
218
+ return rules.map((rule) => {
219
+ const id = rule?.id;
220
+ if (!id) return rule;
221
+
222
+ const nameKey = `rule_${id}_name`;
223
+ const msgKey = `rule_${id}_message`;
224
+ const sugKey = `rule_${id}_suggestion`;
225
+
226
+ const maybeName = t(configOrLocale, nameKey);
227
+ const maybeMsg = t(configOrLocale, msgKey);
228
+ const maybeSug = t(configOrLocale, sugKey);
229
+
230
+ const localized = { ...rule };
231
+ if (typeof maybeName === 'string' && maybeName !== nameKey) localized.name = maybeName;
232
+ if (typeof maybeMsg === 'string' && maybeMsg !== msgKey) localized.message = maybeMsg;
233
+ if (typeof maybeSug === 'string' && maybeSug !== sugKey) localized.suggestion = maybeSug;
234
+ return localized;
235
+ });
236
+ }
237
+
210
238
  deepMerge(target, source) {
211
239
  const result = { ...target };
212
240
 
@@ -1,3 +1,5 @@
1
+ import { t } from './utils/i18n.js';
2
+
1
3
  export const defaultConfig = {
2
4
  // AI配置
3
5
  ai: {
@@ -26,6 +28,13 @@ export const defaultConfig = {
26
28
  contextMergeLines: 10 // 上下文合并行长度(大概值),用于在diff审查时提供足够的上下文
27
29
  },
28
30
 
31
+ // Git 行为配置
32
+ git: {
33
+ // 在 merge/rebase 过程中,默认仅审查“冲突并由开发者手动处理过”的文件;
34
+ // 对于无冲突的自动合并文件,默认跳过审查。
35
+ skipNonConflictOnMergeRebase: true
36
+ },
37
+
29
38
  // 风险等级配置
30
39
  riskLevels: {
31
40
  critical: { block: true },
@@ -123,29 +132,29 @@ export const defaultRules = {
123
132
  security: [
124
133
  {
125
134
  id: 'SEC001',
126
- name: '硬编码密码',
135
+ name: t(undefined, 'rule_SEC001_name'),
127
136
  pattern: '(password|pwd|pass)\\s*=\\s*[\'"][^\'"]+[\'"]',
128
137
  risk: 'high',
129
- message: '发现硬编码的密码,建议使用环境变量或安全的配置管理',
130
- suggestion: '使用环境变量或加密的配置存储',
138
+ message: t(undefined, 'rule_SEC001_message'),
139
+ suggestion: t(undefined, 'rule_SEC001_suggestion'),
131
140
  flags: 'gi'
132
141
  },
133
142
  {
134
143
  id: 'SEC002',
135
- name: 'SQL注入风险',
144
+ name: t(undefined, 'rule_SEC002_name'),
136
145
  pattern: '(execute|query)\\s*\\(\\s*[fF]?[\'"][^\']*\\+.*[\'"]',
137
146
  risk: 'critical',
138
- message: '发现可能的SQL注入风险,字符串拼接SQL查询',
139
- suggestion: '使用参数化查询或ORM的安全方法',
147
+ message: t(undefined, 'rule_SEC002_message'),
148
+ suggestion: t(undefined, 'rule_SEC002_suggestion'),
140
149
  flags: 'gi'
141
150
  },
142
151
  {
143
152
  id: 'SEC003',
144
- name: 'XSS风险',
153
+ name: t(undefined, 'rule_SEC003_name'),
145
154
  pattern: 'innerHTML\\s*=|document\\.write\\s*\\(',
146
155
  risk: 'high',
147
- message: '发现直接操作HTML内容,可能存在XSS风险',
148
- suggestion: '使用textContent或安全的DOM操作方法',
156
+ message: t(undefined, 'rule_SEC003_message'),
157
+ suggestion: t(undefined, 'rule_SEC003_suggestion'),
149
158
  flags: 'gi'
150
159
  }
151
160
  ],
@@ -153,20 +162,20 @@ export const defaultRules = {
153
162
  performance: [
154
163
  {
155
164
  id: 'PERF001',
156
- name: '循环内数据库查询',
165
+ name: t(undefined, 'rule_PERF001_name'),
157
166
  pattern: 'for\\s*\\([^)]*\\)\\s*\\{[^}]*\\.(find|query|select)[^}]*\\}',
158
167
  risk: 'medium',
159
- message: '在循环内执行数据库查询,可能导致N+1查询问题',
160
- suggestion: '使用批量查询或预加载数据',
168
+ message: t(undefined, 'rule_PERF001_message'),
169
+ suggestion: t(undefined, 'rule_PERF001_suggestion'),
161
170
  flags: 'gi'
162
171
  },
163
172
  {
164
173
  id: 'PERF002',
165
- name: '内存泄漏风险',
174
+ name: t(undefined, 'rule_PERF002_name'),
166
175
  pattern: 'setInterval\\s*\\([^)]*\\)|setTimeout\\s*\\([^)]*\\)',
167
176
  risk: 'medium',
168
- message: '发现定时器使用,可能存在内存泄漏风险',
169
- suggestion: '确保在组件卸载时清理定时器',
177
+ message: t(undefined, 'rule_PERF002_message'),
178
+ suggestion: t(undefined, 'rule_PERF002_suggestion'),
170
179
  flags: 'gi'
171
180
  }
172
181
  ],
@@ -174,29 +183,29 @@ export const defaultRules = {
174
183
  'best-practices': [
175
184
  {
176
185
  id: 'BP001',
177
- name: '调试代码',
186
+ name: t(undefined, 'rule_BP001_name'),
178
187
  pattern: 'console\\.log|print\\(|alert\\(',
179
188
  risk: 'low',
180
- message: '发现调试代码,建议在提交前移除',
181
- suggestion: '使用日志系统替代console.log',
189
+ message: t(undefined, 'rule_BP001_message'),
190
+ suggestion: t(undefined, 'rule_BP001_suggestion'),
182
191
  flags: 'gi'
183
192
  },
184
193
  {
185
194
  id: 'BP002',
186
- name: '魔法数字',
195
+ name: t(undefined, 'rule_BP002_name'),
187
196
  pattern: '\\b(?<!\\.)(?!(?:0|1|10|12|24|30|60|100|200|201|300|400|401|403|404|500|503|1000|3000|5000|8080|9000)\\b)\\d{3,}(?!\\.\\d)\\b',
188
197
  risk: 'low',
189
- message: '检测到魔法数字,建议使用常量定义',
190
- suggestion: '将数字定义为有意义的常量',
198
+ message: t(undefined, 'rule_BP002_message'),
199
+ suggestion: t(undefined, 'rule_BP002_suggestion'),
191
200
  flags: 'g'
192
201
  },
193
202
  {
194
203
  id: 'BP013',
195
- name: '使用var声明',
204
+ name: t(undefined, 'rule_BP013_name'),
196
205
  pattern: '\\bvar\\s+\\w+',
197
206
  risk: 'medium',
198
- message: '检测到使用var声明变量,可能导致作用域问题',
199
- suggestion: '使用let或const替代var,提高代码安全性',
207
+ message: t(undefined, 'rule_BP013_message'),
208
+ suggestion: t(undefined, 'rule_BP013_suggestion'),
200
209
  flags: 'gi'
201
210
  }
202
211
  ]