vite-plugin-ai-code-review 1.0.3 → 1.0.5
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/dist/index.js +203 -168
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +138 -129
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,28 +1,54 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Object.defineProperty
|
|
4
|
-
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
13
29
|
|
|
14
|
-
|
|
15
|
-
var
|
|
16
|
-
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
CodeReviewer: () => CodeReviewer,
|
|
34
|
+
GitUtils: () => GitUtils,
|
|
35
|
+
Reporter: () => Reporter,
|
|
36
|
+
default: () => index_default,
|
|
37
|
+
vitePluginAICodeReview: () => vitePluginAICodeReview
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(index_exports);
|
|
17
40
|
|
|
18
41
|
// src/reviewer.ts
|
|
42
|
+
var import_openai = require("@langchain/openai");
|
|
43
|
+
var import_messages = require("@langchain/core/messages");
|
|
44
|
+
var import_crypto = __toESM(require("crypto"));
|
|
19
45
|
var CodeReviewer = class {
|
|
20
46
|
constructor(options) {
|
|
21
47
|
this.llm = null;
|
|
22
48
|
this.cache = /* @__PURE__ */ new Map();
|
|
23
49
|
this.options = options;
|
|
24
50
|
if (options.apiKey) {
|
|
25
|
-
this.llm = new
|
|
51
|
+
this.llm = new import_openai.ChatOpenAI({
|
|
26
52
|
openAIApiKey: options.apiKey,
|
|
27
53
|
configuration: { baseURL: options.apiUrl },
|
|
28
54
|
modelName: options.model,
|
|
@@ -52,7 +78,7 @@ var CodeReviewer = class {
|
|
|
52
78
|
}
|
|
53
79
|
return issues;
|
|
54
80
|
} catch (error) {
|
|
55
|
-
console.error(
|
|
81
|
+
console.error(`❌ 审查失败: ${error.message}`);
|
|
56
82
|
return [];
|
|
57
83
|
}
|
|
58
84
|
}
|
|
@@ -83,64 +109,64 @@ var CodeReviewer = class {
|
|
|
83
109
|
*/
|
|
84
110
|
buildSystemPrompt() {
|
|
85
111
|
const { level, rules } = this.options;
|
|
86
|
-
let prompt =
|
|
112
|
+
let prompt = `你是一个专业的代码审查专家。请审查代码并识别问题。
|
|
87
113
|
|
|
88
|
-
|
|
114
|
+
审查级别: ${level}
|
|
89
115
|
`;
|
|
90
116
|
if (rules.security !== "off") {
|
|
91
117
|
prompt += `
|
|
92
|
-
|
|
93
|
-
- XSS
|
|
94
|
-
- SQL
|
|
95
|
-
- eval()
|
|
96
|
-
-
|
|
97
|
-
-
|
|
118
|
+
🔒 安全问题 (${rules.security}):
|
|
119
|
+
- XSS 漏洞
|
|
120
|
+
- SQL 注入
|
|
121
|
+
- eval() 使用
|
|
122
|
+
- 敏感信息泄露
|
|
123
|
+
- 不安全的依赖`;
|
|
98
124
|
}
|
|
99
125
|
if (rules.performance !== "off") {
|
|
100
126
|
prompt += `
|
|
101
|
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
127
|
+
⚡ 性能问题 (${rules.performance}):
|
|
128
|
+
- 大循环
|
|
129
|
+
- 内存泄漏
|
|
130
|
+
- 重复计算
|
|
131
|
+
- 不必要的渲染
|
|
132
|
+
- 阻塞操作`;
|
|
107
133
|
}
|
|
108
134
|
if (rules.style !== "off") {
|
|
109
135
|
prompt += `
|
|
110
|
-
|
|
111
|
-
-
|
|
112
|
-
-
|
|
113
|
-
-
|
|
114
|
-
-
|
|
136
|
+
📝 代码规范 (${rules.style}):
|
|
137
|
+
- 命名规范
|
|
138
|
+
- 代码复杂度
|
|
139
|
+
- 重复代码
|
|
140
|
+
- 注释完整性`;
|
|
115
141
|
}
|
|
116
142
|
if (rules.bestPractice !== "off") {
|
|
117
143
|
prompt += `
|
|
118
|
-
|
|
119
|
-
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
144
|
+
🎨 最佳实践 (${rules.bestPractice}):
|
|
145
|
+
- 错误处理
|
|
146
|
+
- 类型安全
|
|
147
|
+
- 组件设计
|
|
148
|
+
- 状态管理`;
|
|
123
149
|
}
|
|
124
150
|
prompt += `
|
|
125
151
|
|
|
126
|
-
|
|
152
|
+
返回 JSON 格式:
|
|
127
153
|
{
|
|
128
154
|
"issues": [
|
|
129
155
|
{
|
|
130
|
-
"line": 10, //
|
|
156
|
+
"line": 10, // 必须是准确的行号!
|
|
131
157
|
"category": "security",
|
|
132
158
|
"severity": "error",
|
|
133
|
-
"message": "
|
|
134
|
-
"suggestion": "
|
|
159
|
+
"message": "使用了 eval(),存在安全风险",
|
|
160
|
+
"suggestion": "使用 JSON.parse() 或其他安全方法"
|
|
135
161
|
}
|
|
136
162
|
]
|
|
137
163
|
}
|
|
138
164
|
|
|
139
|
-
|
|
140
|
-
1. line
|
|
141
|
-
2.
|
|
142
|
-
3.
|
|
143
|
-
return new
|
|
165
|
+
**重要提示**:
|
|
166
|
+
1. line 字段必须是准确的行号,与代码中的行号一致
|
|
167
|
+
2. 如果代码带有行号前缀(如 "10: const x = 1"),请提取正确的行号
|
|
168
|
+
3. 只返回 JSON,不要其他解释`;
|
|
169
|
+
return new import_messages.SystemMessage(prompt);
|
|
144
170
|
}
|
|
145
171
|
/**
|
|
146
172
|
* 构建用户提示
|
|
@@ -150,20 +176,20 @@ var CodeReviewer = class {
|
|
|
150
176
|
const language = this.getLanguage(fileExt || "");
|
|
151
177
|
const lines = code.split("\n");
|
|
152
178
|
const codeWithLineNumbers = lines.map((line, index) => `${index + 1}: ${line}`).join("\n");
|
|
153
|
-
return new
|
|
154
|
-
|
|
179
|
+
return new import_messages.HumanMessage(`
|
|
180
|
+
请审查以下 ${language} 代码:
|
|
155
181
|
|
|
156
|
-
|
|
157
|
-
|
|
182
|
+
文件: ${filePath}
|
|
183
|
+
总行数: ${lines.length}
|
|
158
184
|
|
|
159
|
-
|
|
185
|
+
代码(带行号):
|
|
160
186
|
\`\`\`${language}
|
|
161
187
|
${codeWithLineNumbers}
|
|
162
188
|
\`\`\`
|
|
163
189
|
|
|
164
|
-
|
|
190
|
+
**重要**:请返回准确的行号!行号必须与上面代码中的行号一致。
|
|
165
191
|
|
|
166
|
-
|
|
192
|
+
请返回 JSON 格式的问题列表。
|
|
167
193
|
`);
|
|
168
194
|
}
|
|
169
195
|
/**
|
|
@@ -178,7 +204,7 @@ ${codeWithLineNumbers}
|
|
|
178
204
|
line: issue.line,
|
|
179
205
|
category: issue.category || "best-practice",
|
|
180
206
|
severity: issue.severity || "info",
|
|
181
|
-
message: issue.message || "
|
|
207
|
+
message: issue.message || "未知问题",
|
|
182
208
|
suggestion: issue.suggestion,
|
|
183
209
|
code: issue.code
|
|
184
210
|
})).filter((issue) => {
|
|
@@ -207,7 +233,7 @@ ${codeWithLineNumbers}
|
|
|
207
233
|
* 生成缓存键
|
|
208
234
|
*/
|
|
209
235
|
getCacheKey(code) {
|
|
210
|
-
return
|
|
236
|
+
return import_crypto.default.createHash("md5").update(code).digest("hex");
|
|
211
237
|
}
|
|
212
238
|
/**
|
|
213
239
|
* 清除缓存
|
|
@@ -226,6 +252,11 @@ ${codeWithLineNumbers}
|
|
|
226
252
|
};
|
|
227
253
|
}
|
|
228
254
|
};
|
|
255
|
+
|
|
256
|
+
// src/git-utils.ts
|
|
257
|
+
var import_child_process = require("child_process");
|
|
258
|
+
var import_fs = __toESM(require("fs"));
|
|
259
|
+
var import_path = __toESM(require("path"));
|
|
229
260
|
var GitUtils = class {
|
|
230
261
|
/**
|
|
231
262
|
* 获取 Git 变更的文件列表
|
|
@@ -234,29 +265,29 @@ var GitUtils = class {
|
|
|
234
265
|
async getChangedFiles() {
|
|
235
266
|
try {
|
|
236
267
|
if (!this.isGitRepository()) {
|
|
237
|
-
console.warn("
|
|
268
|
+
console.warn("⚠️ 不在 Git 仓库中,无法获取变更文件");
|
|
238
269
|
return [];
|
|
239
270
|
}
|
|
240
|
-
console.log(
|
|
271
|
+
console.log(`🔍 [Git] 对比策略: HEAD~1 vs HEAD`);
|
|
241
272
|
const changedFiles = this.getCommitDiffFiles();
|
|
242
|
-
console.log(
|
|
273
|
+
console.log(`🔍 [Git] 检测到 ${changedFiles.length} 个变更文件`);
|
|
243
274
|
changedFiles.forEach((f) => console.log(` - ${f}`));
|
|
244
275
|
const existingFiles = changedFiles.map((file) => {
|
|
245
276
|
const cleanFile = file.replace(/^[^/]+\//, "");
|
|
246
277
|
return cleanFile;
|
|
247
278
|
}).filter((file) => {
|
|
248
|
-
const fullPath =
|
|
249
|
-
const exists =
|
|
279
|
+
const fullPath = import_path.default.resolve(process.cwd(), file);
|
|
280
|
+
const exists = import_fs.default.existsSync(fullPath);
|
|
250
281
|
if (!exists) {
|
|
251
|
-
console.log(`
|
|
282
|
+
console.log(` ⚠️ 文件不存在: ${fullPath}`);
|
|
252
283
|
}
|
|
253
284
|
return exists;
|
|
254
285
|
});
|
|
255
|
-
console.log(
|
|
256
|
-
existingFiles.forEach((f) => console.log(`
|
|
286
|
+
console.log(`🔍 [Git] 过滤后文件: ${existingFiles.length} 个`);
|
|
287
|
+
existingFiles.forEach((f) => console.log(` ✓ ${f}`));
|
|
257
288
|
return existingFiles;
|
|
258
289
|
} catch (error) {
|
|
259
|
-
console.warn(
|
|
290
|
+
console.warn(`⚠️ 获取 Git 变更文件失败: ${error.message}`);
|
|
260
291
|
return [];
|
|
261
292
|
}
|
|
262
293
|
}
|
|
@@ -265,7 +296,7 @@ var GitUtils = class {
|
|
|
265
296
|
*/
|
|
266
297
|
isGitRepository() {
|
|
267
298
|
try {
|
|
268
|
-
|
|
299
|
+
(0, import_child_process.execSync)("git rev-parse --git-dir", {
|
|
269
300
|
stdio: "ignore",
|
|
270
301
|
cwd: process.cwd()
|
|
271
302
|
});
|
|
@@ -279,7 +310,7 @@ var GitUtils = class {
|
|
|
279
310
|
*/
|
|
280
311
|
getCommitDiffFiles() {
|
|
281
312
|
try {
|
|
282
|
-
const output =
|
|
313
|
+
const output = (0, import_child_process.execSync)("git diff --name-only HEAD~1 HEAD", {
|
|
283
314
|
encoding: "utf-8",
|
|
284
315
|
cwd: process.cwd()
|
|
285
316
|
});
|
|
@@ -287,10 +318,10 @@ var GitUtils = class {
|
|
|
287
318
|
if (files.length > 0) {
|
|
288
319
|
return files;
|
|
289
320
|
}
|
|
290
|
-
console.log(`
|
|
321
|
+
console.log(` ℹ️ 没有上一次提交,获取当前提交的所有文件`);
|
|
291
322
|
return this.getLastCommitFiles();
|
|
292
323
|
} catch (error) {
|
|
293
|
-
console.log(`
|
|
324
|
+
console.log(` ℹ️ 无法对比提交,尝试获取未提交的变更`);
|
|
294
325
|
return this.getUncommittedFiles();
|
|
295
326
|
}
|
|
296
327
|
}
|
|
@@ -299,7 +330,7 @@ var GitUtils = class {
|
|
|
299
330
|
*/
|
|
300
331
|
getLastCommitFiles() {
|
|
301
332
|
try {
|
|
302
|
-
const output =
|
|
333
|
+
const output = (0, import_child_process.execSync)(
|
|
303
334
|
"git diff-tree --no-commit-id --name-only -r HEAD",
|
|
304
335
|
{
|
|
305
336
|
encoding: "utf-8",
|
|
@@ -316,11 +347,11 @@ var GitUtils = class {
|
|
|
316
347
|
*/
|
|
317
348
|
getUncommittedFiles() {
|
|
318
349
|
try {
|
|
319
|
-
const unstagedOutput =
|
|
350
|
+
const unstagedOutput = (0, import_child_process.execSync)("git diff --name-only", {
|
|
320
351
|
encoding: "utf-8",
|
|
321
352
|
cwd: process.cwd()
|
|
322
353
|
});
|
|
323
|
-
const stagedOutput =
|
|
354
|
+
const stagedOutput = (0, import_child_process.execSync)("git diff --cached --name-only", {
|
|
324
355
|
encoding: "utf-8",
|
|
325
356
|
cwd: process.cwd()
|
|
326
357
|
});
|
|
@@ -336,7 +367,7 @@ var GitUtils = class {
|
|
|
336
367
|
*/
|
|
337
368
|
async getRecentChangedFiles(commits = 1) {
|
|
338
369
|
try {
|
|
339
|
-
const output =
|
|
370
|
+
const output = (0, import_child_process.execSync)(`git diff --name-only HEAD~${commits}`, {
|
|
340
371
|
encoding: "utf-8",
|
|
341
372
|
cwd: process.cwd()
|
|
342
373
|
});
|
|
@@ -350,7 +381,7 @@ var GitUtils = class {
|
|
|
350
381
|
*/
|
|
351
382
|
getCurrentBranch() {
|
|
352
383
|
try {
|
|
353
|
-
const output =
|
|
384
|
+
const output = (0, import_child_process.execSync)("git rev-parse --abbrev-ref HEAD", {
|
|
354
385
|
encoding: "utf-8",
|
|
355
386
|
cwd: process.cwd()
|
|
356
387
|
});
|
|
@@ -364,7 +395,7 @@ var GitUtils = class {
|
|
|
364
395
|
*/
|
|
365
396
|
getFileStatus(filePath) {
|
|
366
397
|
try {
|
|
367
|
-
const output =
|
|
398
|
+
const output = (0, import_child_process.execSync)(`git status --short "${filePath}"`, {
|
|
368
399
|
encoding: "utf-8",
|
|
369
400
|
cwd: process.cwd()
|
|
370
401
|
});
|
|
@@ -380,6 +411,10 @@ var GitUtils = class {
|
|
|
380
411
|
}
|
|
381
412
|
}
|
|
382
413
|
};
|
|
414
|
+
|
|
415
|
+
// src/reporter.ts
|
|
416
|
+
var import_fs2 = __toESM(require("fs"));
|
|
417
|
+
var import_path2 = __toESM(require("path"));
|
|
383
418
|
var Reporter = class {
|
|
384
419
|
constructor(options = {}) {
|
|
385
420
|
this.options = options;
|
|
@@ -405,23 +440,23 @@ var Reporter = class {
|
|
|
405
440
|
* 生成控制台报告
|
|
406
441
|
*/
|
|
407
442
|
generateConsoleReport(issues) {
|
|
408
|
-
console.log("\n
|
|
409
|
-
console.log("
|
|
410
|
-
console.log("
|
|
443
|
+
console.log("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
444
|
+
console.log("📊 代码审查报告");
|
|
445
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
|
|
411
446
|
const errors = issues.filter((i) => i.severity === "error");
|
|
412
447
|
const warnings = issues.filter((i) => i.severity === "warn");
|
|
413
448
|
const infos = issues.filter((i) => i.severity === "info");
|
|
414
|
-
console.log(
|
|
415
|
-
console.log(
|
|
416
|
-
console.log(
|
|
417
|
-
console.log(
|
|
449
|
+
console.log(`❌ 错误: ${errors.length}`);
|
|
450
|
+
console.log(`⚠️ 警告: ${warnings.length}`);
|
|
451
|
+
console.log(`ℹ️ 信息: ${infos.length}`);
|
|
452
|
+
console.log(`📝 总计: ${issues.length}
|
|
418
453
|
`);
|
|
419
454
|
const byCategory = this.groupByCategory(issues);
|
|
420
|
-
console.log("
|
|
455
|
+
console.log("📋 问题分类:");
|
|
421
456
|
Object.entries(byCategory).forEach(([category, count]) => {
|
|
422
457
|
console.log(` ${this.getCategoryIcon(category)} ${category}: ${count}`);
|
|
423
458
|
});
|
|
424
|
-
console.log("\n
|
|
459
|
+
console.log("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
|
|
425
460
|
}
|
|
426
461
|
/**
|
|
427
462
|
* 生成 HTML 报告
|
|
@@ -433,7 +468,7 @@ var Reporter = class {
|
|
|
433
468
|
<head>
|
|
434
469
|
<meta charset="UTF-8">
|
|
435
470
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
436
|
-
<title
|
|
471
|
+
<title>代码审查报告</title>
|
|
437
472
|
<style>
|
|
438
473
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
439
474
|
body {
|
|
@@ -586,7 +621,7 @@ var Reporter = class {
|
|
|
586
621
|
line-height: 1.6;
|
|
587
622
|
}
|
|
588
623
|
.issue-suggestion::before {
|
|
589
|
-
content: "
|
|
624
|
+
content: "💡 建议: ";
|
|
590
625
|
font-weight: bold;
|
|
591
626
|
color: #2e7d32;
|
|
592
627
|
font-size: 16px;
|
|
@@ -621,27 +656,27 @@ var Reporter = class {
|
|
|
621
656
|
<body>
|
|
622
657
|
<div class="container">
|
|
623
658
|
<div class="header">
|
|
624
|
-
<h1
|
|
625
|
-
<div class="time"
|
|
659
|
+
<h1>🔍 代码审查报告</h1>
|
|
660
|
+
<div class="time">生成时间: ${(/* @__PURE__ */ new Date()).toLocaleString("zh-CN")}</div>
|
|
626
661
|
</div>
|
|
627
662
|
|
|
628
663
|
<div class="content">
|
|
629
664
|
<div class="summary">
|
|
630
665
|
<div class="summary-card error">
|
|
631
666
|
<h2>${issues.filter((i) => i.severity === "error").length}</h2>
|
|
632
|
-
<p
|
|
667
|
+
<p>错误</p>
|
|
633
668
|
</div>
|
|
634
669
|
<div class="summary-card warn">
|
|
635
670
|
<h2>${issues.filter((i) => i.severity === "warn").length}</h2>
|
|
636
|
-
<p
|
|
671
|
+
<p>警告</p>
|
|
637
672
|
</div>
|
|
638
673
|
<div class="summary-card info">
|
|
639
674
|
<h2>${issues.filter((i) => i.severity === "info").length}</h2>
|
|
640
|
-
<p
|
|
675
|
+
<p>信息</p>
|
|
641
676
|
</div>
|
|
642
677
|
</div>
|
|
643
678
|
|
|
644
|
-
<div class="section-title"
|
|
679
|
+
<div class="section-title">📊 问题分类统计</div>
|
|
645
680
|
<div class="category-stats">
|
|
646
681
|
${Object.entries(this.groupByCategory(issues)).map(
|
|
647
682
|
([category, count]) => `<div class="category-tag">${this.getCategoryIcon(
|
|
@@ -650,7 +685,7 @@ var Reporter = class {
|
|
|
650
685
|
).join("")}
|
|
651
686
|
</div>
|
|
652
687
|
|
|
653
|
-
<div class="section-title"
|
|
688
|
+
<div class="section-title">📋 问题详情</div>
|
|
654
689
|
${issues.map(
|
|
655
690
|
(issue) => `
|
|
656
691
|
<div class="issue">
|
|
@@ -658,7 +693,7 @@ var Reporter = class {
|
|
|
658
693
|
<span class="issue-badge ${issue.severity}">${issue.severity.toUpperCase()}</span>
|
|
659
694
|
<span class="issue-category">${issue.category}</span>
|
|
660
695
|
<span class="issue-file">${issue.file}</span>
|
|
661
|
-
${issue.line ? `<span class="issue-line"
|
|
696
|
+
${issue.line ? `<span class="issue-line">行 ${issue.line}</span>` : ""}
|
|
662
697
|
</div>
|
|
663
698
|
<div class="issue-message">${issue.message}</div>
|
|
664
699
|
${issue.suggestion ? `<div class="issue-suggestion">${issue.suggestion}</div>` : ""}
|
|
@@ -675,13 +710,13 @@ var Reporter = class {
|
|
|
675
710
|
</body>
|
|
676
711
|
</html>
|
|
677
712
|
`;
|
|
678
|
-
const reportsDir =
|
|
679
|
-
if (!
|
|
680
|
-
|
|
713
|
+
const reportsDir = import_path2.default.join(process.cwd(), "ai-reports");
|
|
714
|
+
if (!import_fs2.default.existsSync(reportsDir)) {
|
|
715
|
+
import_fs2.default.mkdirSync(reportsDir, { recursive: true });
|
|
681
716
|
}
|
|
682
|
-
const reportPath =
|
|
683
|
-
|
|
684
|
-
console.log(
|
|
717
|
+
const reportPath = import_path2.default.join(reportsDir, "code-review-report.html");
|
|
718
|
+
import_fs2.default.writeFileSync(reportPath, html, "utf-8");
|
|
719
|
+
console.log(`📄 HTML 报告已生成: ${reportPath}
|
|
685
720
|
`);
|
|
686
721
|
}
|
|
687
722
|
/**
|
|
@@ -691,45 +726,45 @@ var Reporter = class {
|
|
|
691
726
|
const errors = issues.filter((i) => i.severity === "error");
|
|
692
727
|
const warnings = issues.filter((i) => i.severity === "warn");
|
|
693
728
|
const infos = issues.filter((i) => i.severity === "info");
|
|
694
|
-
let markdown = `#
|
|
729
|
+
let markdown = `# 🔍 代码审查报告
|
|
695
730
|
|
|
696
|
-
|
|
731
|
+
生成时间: ${(/* @__PURE__ */ new Date()).toLocaleString("zh-CN")}
|
|
697
732
|
|
|
698
|
-
##
|
|
733
|
+
## 📊 概览
|
|
699
734
|
|
|
700
|
-
|
|
|
735
|
+
| 类型 | 数量 |
|
|
701
736
|
|------|------|
|
|
702
|
-
|
|
|
703
|
-
|
|
|
704
|
-
|
|
|
705
|
-
|
|
|
737
|
+
| ❌ 错误 | ${errors.length} |
|
|
738
|
+
| ⚠️ 警告 | ${warnings.length} |
|
|
739
|
+
| ℹ️ 信息 | ${infos.length} |
|
|
740
|
+
| 📝 总计 | ${issues.length} |
|
|
706
741
|
|
|
707
|
-
##
|
|
742
|
+
## 📋 问题详情
|
|
708
743
|
|
|
709
744
|
`;
|
|
710
745
|
issues.forEach((issue, index) => {
|
|
711
746
|
const icon = this.getSeverityIcon(issue.severity);
|
|
712
747
|
markdown += `### ${index + 1}. ${icon} ${issue.category}
|
|
713
748
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
749
|
+
**文件**: \`${issue.file}${issue.line ? `:${issue.line}` : ""}\`
|
|
750
|
+
**严重程度**: ${issue.severity}
|
|
751
|
+
**问题**: ${issue.message}
|
|
717
752
|
|
|
718
753
|
`;
|
|
719
754
|
if (issue.suggestion) {
|
|
720
|
-
markdown +=
|
|
755
|
+
markdown += `💡 **建议**: ${issue.suggestion}
|
|
721
756
|
|
|
722
757
|
`;
|
|
723
758
|
}
|
|
724
759
|
markdown += "---\n\n";
|
|
725
760
|
});
|
|
726
|
-
const reportsDir =
|
|
727
|
-
if (!
|
|
728
|
-
|
|
761
|
+
const reportsDir = import_path2.default.join(process.cwd(), "ai-reports");
|
|
762
|
+
if (!import_fs2.default.existsSync(reportsDir)) {
|
|
763
|
+
import_fs2.default.mkdirSync(reportsDir, { recursive: true });
|
|
729
764
|
}
|
|
730
|
-
const reportPath =
|
|
731
|
-
|
|
732
|
-
console.log(
|
|
765
|
+
const reportPath = import_path2.default.join(reportsDir, "code-review-report.md");
|
|
766
|
+
import_fs2.default.writeFileSync(reportPath, markdown, "utf-8");
|
|
767
|
+
console.log(`📄 Markdown 报告已生成: ${reportPath}
|
|
733
768
|
`);
|
|
734
769
|
}
|
|
735
770
|
/**
|
|
@@ -746,13 +781,13 @@ var Reporter = class {
|
|
|
746
781
|
},
|
|
747
782
|
issues
|
|
748
783
|
};
|
|
749
|
-
const reportsDir =
|
|
750
|
-
if (!
|
|
751
|
-
|
|
784
|
+
const reportsDir = import_path2.default.join(process.cwd(), "ai-reports");
|
|
785
|
+
if (!import_fs2.default.existsSync(reportsDir)) {
|
|
786
|
+
import_fs2.default.mkdirSync(reportsDir, { recursive: true });
|
|
752
787
|
}
|
|
753
|
-
const reportPath =
|
|
754
|
-
|
|
755
|
-
console.log(
|
|
788
|
+
const reportPath = import_path2.default.join(reportsDir, "code-review-report.json");
|
|
789
|
+
import_fs2.default.writeFileSync(reportPath, JSON.stringify(report, null, 2), "utf-8");
|
|
790
|
+
console.log(`📄 JSON 报告已生成: ${reportPath}
|
|
756
791
|
`);
|
|
757
792
|
}
|
|
758
793
|
/**
|
|
@@ -770,12 +805,12 @@ var Reporter = class {
|
|
|
770
805
|
*/
|
|
771
806
|
getCategoryIcon(category) {
|
|
772
807
|
const icons = {
|
|
773
|
-
security: "
|
|
774
|
-
performance: "
|
|
775
|
-
style: "
|
|
776
|
-
"best-practice": "
|
|
808
|
+
security: "🔒",
|
|
809
|
+
performance: "⚡",
|
|
810
|
+
style: "📝",
|
|
811
|
+
"best-practice": "🎨"
|
|
777
812
|
};
|
|
778
|
-
return icons[category] || "
|
|
813
|
+
return icons[category] || "📋";
|
|
779
814
|
}
|
|
780
815
|
/**
|
|
781
816
|
* 获取严重程度图标
|
|
@@ -783,13 +818,13 @@ var Reporter = class {
|
|
|
783
818
|
getSeverityIcon(severity) {
|
|
784
819
|
switch (severity) {
|
|
785
820
|
case "error":
|
|
786
|
-
return "
|
|
821
|
+
return "❌";
|
|
787
822
|
case "warn":
|
|
788
|
-
return "
|
|
823
|
+
return "⚠️";
|
|
789
824
|
case "info":
|
|
790
|
-
return "
|
|
825
|
+
return "ℹ️";
|
|
791
826
|
default:
|
|
792
|
-
return "
|
|
827
|
+
return "📝";
|
|
793
828
|
}
|
|
794
829
|
}
|
|
795
830
|
};
|
|
@@ -844,20 +879,20 @@ function vitePluginAICodeReview(options = {}) {
|
|
|
844
879
|
name: "vite-plugin-ai-code-review",
|
|
845
880
|
enforce: "post",
|
|
846
881
|
configResolved(config) {
|
|
847
|
-
console.log("\n
|
|
848
|
-
console.log(
|
|
849
|
-
console.log(
|
|
850
|
-
console.log(
|
|
882
|
+
console.log("\n🔍 AI Code Review 已启动...");
|
|
883
|
+
console.log(`📂 审查模式: ${mode}`);
|
|
884
|
+
console.log(`📊 审查级别: ${level}`);
|
|
885
|
+
console.log(`🔑 API Key: ${apiKey ? "已配置" : "未配置"}
|
|
851
886
|
`);
|
|
852
887
|
},
|
|
853
888
|
async buildStart() {
|
|
854
889
|
if (!apiKey) {
|
|
855
|
-
console.warn("
|
|
890
|
+
console.warn("⚠️ 未配置 API Key,跳过代码审查");
|
|
856
891
|
return;
|
|
857
892
|
}
|
|
858
893
|
if (mode === "changed") {
|
|
859
894
|
filesToReview = await gitUtils.getChangedFiles();
|
|
860
|
-
console.log(
|
|
895
|
+
console.log(`🔍 [Git] 检测到 ${filesToReview.length} 个变更文件`);
|
|
861
896
|
filesToReview.forEach((f) => console.log(` - ${f}`));
|
|
862
897
|
} else if (mode === "manual") {
|
|
863
898
|
filesToReview = files;
|
|
@@ -868,16 +903,16 @@ function vitePluginAICodeReview(options = {}) {
|
|
|
868
903
|
(file) => shouldReview(file, include, exclude)
|
|
869
904
|
);
|
|
870
905
|
if (mode !== "all" && filesToReview.length > 0) {
|
|
871
|
-
console.log(
|
|
906
|
+
console.log(`📝 过滤后需要审查 ${filesToReview.length} 个文件
|
|
872
907
|
`);
|
|
873
908
|
for (const file of filesToReview) {
|
|
874
909
|
try {
|
|
875
|
-
const fs3 = await import(
|
|
876
|
-
const path3 = await import(
|
|
910
|
+
const fs3 = await import("fs");
|
|
911
|
+
const path3 = await import("path");
|
|
877
912
|
const fullPath = path3.resolve(process.cwd(), file);
|
|
878
913
|
if (fs3.existsSync(fullPath)) {
|
|
879
914
|
const code = fs3.readFileSync(fullPath, "utf-8");
|
|
880
|
-
console.log(
|
|
915
|
+
console.log(`🔍 [审查] ${file}`);
|
|
881
916
|
const issues = await reviewer.review(code, file);
|
|
882
917
|
if (issues.length > 0) {
|
|
883
918
|
allIssues.push(...issues);
|
|
@@ -889,22 +924,22 @@ function vitePluginAICodeReview(options = {}) {
|
|
|
889
924
|
);
|
|
890
925
|
console.log(` ${issue.message}`);
|
|
891
926
|
if (issue.suggestion) {
|
|
892
|
-
console.log(`
|
|
927
|
+
console.log(` 💡 ${issue.suggestion}`);
|
|
893
928
|
}
|
|
894
929
|
});
|
|
895
930
|
console.log("");
|
|
896
931
|
}
|
|
897
932
|
} else {
|
|
898
|
-
console.log(
|
|
933
|
+
console.log(`✅ 未发现问题
|
|
899
934
|
`);
|
|
900
935
|
}
|
|
901
936
|
}
|
|
902
937
|
} catch (error) {
|
|
903
|
-
console.warn(
|
|
938
|
+
console.warn(`⚠️ 审查失败 ${file}: ${error.message}`);
|
|
904
939
|
}
|
|
905
940
|
}
|
|
906
941
|
} else if (mode !== "all") {
|
|
907
|
-
console.log(
|
|
942
|
+
console.log(`📝 没有需要审查的文件
|
|
908
943
|
`);
|
|
909
944
|
}
|
|
910
945
|
},
|
|
@@ -919,8 +954,8 @@ function vitePluginAICodeReview(options = {}) {
|
|
|
919
954
|
return null;
|
|
920
955
|
}
|
|
921
956
|
try {
|
|
922
|
-
console.log(
|
|
923
|
-
const fs3 = await import(
|
|
957
|
+
console.log(`🔍 [审查] ${id}`);
|
|
958
|
+
const fs3 = await import("fs");
|
|
924
959
|
let sourceCode = code;
|
|
925
960
|
if (fs3.existsSync(id)) {
|
|
926
961
|
sourceCode = fs3.readFileSync(id, "utf-8");
|
|
@@ -936,27 +971,27 @@ function vitePluginAICodeReview(options = {}) {
|
|
|
936
971
|
);
|
|
937
972
|
console.log(` ${issue.message}`);
|
|
938
973
|
if (issue.suggestion) {
|
|
939
|
-
console.log(`
|
|
974
|
+
console.log(` 💡 ${issue.suggestion}`);
|
|
940
975
|
}
|
|
941
976
|
});
|
|
942
977
|
console.log("");
|
|
943
978
|
}
|
|
944
979
|
}
|
|
945
980
|
} catch (error) {
|
|
946
|
-
console.warn(
|
|
981
|
+
console.warn(`⚠️ 审查失败 ${id}: ${error.message}`);
|
|
947
982
|
}
|
|
948
983
|
return null;
|
|
949
984
|
},
|
|
950
985
|
async buildEnd() {
|
|
951
986
|
if (allIssues.length === 0) {
|
|
952
|
-
console.log("
|
|
987
|
+
console.log("✨ 代码审查完成,未发现问题\n");
|
|
953
988
|
return;
|
|
954
989
|
}
|
|
955
990
|
await reporter.generate(allIssues);
|
|
956
991
|
if (output.failOnError) {
|
|
957
992
|
const errors = allIssues.filter((i) => i.severity === "error");
|
|
958
993
|
if (errors.length > 0) {
|
|
959
|
-
throw new Error(
|
|
994
|
+
throw new Error(`代码审查发现 ${errors.length} 个错误`);
|
|
960
995
|
}
|
|
961
996
|
}
|
|
962
997
|
}
|
|
@@ -987,21 +1022,21 @@ function matchPattern(filePath, pattern) {
|
|
|
987
1022
|
function getSeverityIcon(severity) {
|
|
988
1023
|
switch (severity) {
|
|
989
1024
|
case "error":
|
|
990
|
-
return "
|
|
1025
|
+
return "❌";
|
|
991
1026
|
case "warn":
|
|
992
|
-
return "
|
|
1027
|
+
return "⚠️";
|
|
993
1028
|
case "info":
|
|
994
|
-
return "
|
|
1029
|
+
return "ℹ️";
|
|
995
1030
|
default:
|
|
996
|
-
return "
|
|
1031
|
+
return "📝";
|
|
997
1032
|
}
|
|
998
1033
|
}
|
|
999
1034
|
var index_default = vitePluginAICodeReview;
|
|
1000
|
-
|
|
1001
|
-
exports
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1035
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1036
|
+
0 && (module.exports = {
|
|
1037
|
+
CodeReviewer,
|
|
1038
|
+
GitUtils,
|
|
1039
|
+
Reporter,
|
|
1040
|
+
vitePluginAICodeReview
|
|
1041
|
+
});
|
|
1007
1042
|
//# sourceMappingURL=index.js.map
|