smart-review 1.0.1 → 1.0.3

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: {
@@ -123,81 +125,89 @@ export const defaultRules = {
123
125
  security: [
124
126
  {
125
127
  id: 'SEC001',
126
- name: '硬编码密码',
128
+ name: t(undefined, 'rule_SEC001_name'),
127
129
  pattern: '(password|pwd|pass)\\s*=\\s*[\'"][^\'"]+[\'"]',
128
130
  risk: 'high',
129
- message: '发现硬编码的密码,建议使用环境变量或安全的配置管理',
130
- suggestion: '使用环境变量或加密的配置存储',
131
- flags: 'gi'
131
+ message: t(undefined, 'rule_SEC001_message'),
132
+ suggestion: t(undefined, 'rule_SEC001_suggestion'),
133
+ flags: 'gi',
134
+ extensions: ['.js', '.ts', '.py', '.java', '.rb', '.php', '.cs', '.go']
132
135
  },
133
136
  {
134
137
  id: 'SEC002',
135
- name: 'SQL注入风险',
138
+ name: t(undefined, 'rule_SEC002_name'),
136
139
  pattern: '(execute|query)\\s*\\(\\s*[fF]?[\'"][^\']*\\+.*[\'"]',
137
140
  risk: 'critical',
138
- message: '发现可能的SQL注入风险,字符串拼接SQL查询',
139
- suggestion: '使用参数化查询或ORM的安全方法',
140
- flags: 'gi'
141
+ message: t(undefined, 'rule_SEC002_message'),
142
+ suggestion: t(undefined, 'rule_SEC002_suggestion'),
143
+ flags: 'gi',
144
+ extensions: ['.js', '.ts', '.java', '.cs', '.php', '.py', '.rb', '.go']
141
145
  },
142
146
  {
143
147
  id: 'SEC003',
144
- name: 'XSS风险',
148
+ name: t(undefined, 'rule_SEC003_name'),
145
149
  pattern: 'innerHTML\\s*=|document\\.write\\s*\\(',
146
150
  risk: 'high',
147
- message: '发现直接操作HTML内容,可能存在XSS风险',
148
- suggestion: '使用textContent或安全的DOM操作方法',
149
- flags: 'gi'
151
+ message: t(undefined, 'rule_SEC003_message'),
152
+ suggestion: t(undefined, 'rule_SEC003_suggestion'),
153
+ flags: 'gi',
154
+ extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue', '.svelte']
150
155
  }
151
156
  ],
152
157
 
153
158
  performance: [
154
159
  {
155
160
  id: 'PERF001',
156
- name: '循环内数据库查询',
161
+ name: t(undefined, 'rule_PERF001_name'),
157
162
  pattern: 'for\\s*\\([^)]*\\)\\s*\\{[^}]*\\.(find|query|select)[^}]*\\}',
158
163
  risk: 'medium',
159
- message: '在循环内执行数据库查询,可能导致N+1查询问题',
160
- suggestion: '使用批量查询或预加载数据',
161
- flags: 'gi'
164
+ message: t(undefined, 'rule_PERF001_message'),
165
+ suggestion: t(undefined, 'rule_PERF001_suggestion'),
166
+ flags: 'gi',
167
+ extensions: ['.js', '.ts', '.java', '.py', '.rb', '.php', '.cs', '.go']
162
168
  },
163
169
  {
164
170
  id: 'PERF002',
165
- name: '内存泄漏风险',
171
+ name: t(undefined, 'rule_PERF002_name'),
166
172
  pattern: 'setInterval\\s*\\([^)]*\\)|setTimeout\\s*\\([^)]*\\)',
167
173
  risk: 'medium',
168
- message: '发现定时器使用,可能存在内存泄漏风险',
169
- suggestion: '确保在组件卸载时清理定时器',
170
- flags: 'gi'
174
+ message: t(undefined, 'rule_PERF002_message'),
175
+ suggestion: t(undefined, 'rule_PERF002_suggestion'),
176
+ flags: 'gi',
177
+ extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue', '.svelte']
171
178
  }
172
179
  ],
173
180
 
174
181
  'best-practices': [
175
182
  {
176
183
  id: 'BP001',
177
- name: '调试代码',
184
+ name: t(undefined, 'rule_BP001_name'),
178
185
  pattern: 'console\\.log|print\\(|alert\\(',
179
186
  risk: 'low',
180
- message: '发现调试代码,建议在提交前移除',
181
- suggestion: '使用日志系统替代console.log',
182
- flags: 'gi'
187
+ message: t(undefined, 'rule_BP001_message'),
188
+ suggestion: t(undefined, 'rule_BP001_suggestion'),
189
+ flags: 'gi',
190
+ extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue', '.svelte', '.py', '.php', '.rb']
183
191
  },
184
192
  {
185
193
  id: 'BP002',
186
- name: '魔法数字',
194
+ name: t(undefined, 'rule_BP002_name'),
187
195
  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
196
  risk: 'low',
189
- message: '检测到魔法数字,建议使用常量定义',
190
- suggestion: '将数字定义为有意义的常量',
191
- flags: 'g'
197
+ message: t(undefined, 'rule_BP002_message'),
198
+ suggestion: t(undefined, 'rule_BP002_suggestion'),
199
+ flags: 'g',
200
+ extensions: ['.js', '.ts', '.java', '.cs', '.php', '.py', '.rb', '.go']
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,提高代码安全性',
200
- flags: 'gi'
207
+ message: t(undefined, 'rule_BP013_message'),
208
+ suggestion: t(undefined, 'rule_BP013_suggestion'),
209
+ flags: 'gi',
210
+ extensions: ['.js', '.jsx', '.ts', '.tsx']
201
211
  }
202
212
  ]
203
213
  };