gitlab-ai-review 3.7.0 → 3.8.0

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/index.js CHANGED
@@ -209,10 +209,6 @@ export class GitLabAIReview {
209
209
  for (const review of fileReview.reviews) {
210
210
  if (review.hasIssue) {
211
211
  try {
212
- // 找到对应的变更,判断是删除还是新增
213
- const relatedChange = meaningfulChanges.find(c => c.lineNumber === review.lineNumber);
214
- const isDeletion = relatedChange && relatedChange.type === 'deletion';
215
-
216
212
  const commentResult = await this.gitlabClient.createLineComment(
217
213
  this.config.project.projectId,
218
214
  this.config.project.mergeRequestIid,
@@ -220,8 +216,7 @@ export class GitLabAIReview {
220
216
  {
221
217
  filePath: fileName,
222
218
  oldPath: change.old_path,
223
- // 删除的行使用 oldLine,新增的行使用 newLine
224
- ...(isDeletion ? { oldLine: review.lineNumber } : { newLine: review.lineNumber }),
219
+ newLine: review.lineNumber,
225
220
  }
226
221
  );
227
222
 
@@ -266,6 +261,66 @@ export class GitLabAIReview {
266
261
  return results;
267
262
  }
268
263
 
264
+ /**
265
+ * 智能合并修改块的评论
266
+ * 如果相邻的删除和新增是同一个修改,合并为一个评论
267
+ * @param {Array} reviews - AI 返回的审查结果
268
+ * @param {Array} meaningfulChanges - 有意义的变更列表
269
+ * @returns {Array} 合并后的审查结果
270
+ */
271
+ mergeModificationReviews(reviews, meaningfulChanges) {
272
+ if (!reviews || reviews.length === 0) return reviews;
273
+
274
+ const merged = [];
275
+ const processed = new Set();
276
+
277
+ reviews.forEach((review, index) => {
278
+ if (processed.has(index)) return;
279
+
280
+ const currentChange = meaningfulChanges.find(c => c.lineNumber === review.lineNumber);
281
+ if (!currentChange) {
282
+ merged.push(review);
283
+ return;
284
+ }
285
+
286
+ // 如果是删除,查找是否有对应的新增(可能是修改)
287
+ if (currentChange.type === 'deletion') {
288
+ // 查找相近行号的新增
289
+ const nextReviewIndex = reviews.findIndex((r, i) => {
290
+ if (i <= index || processed.has(i)) return false;
291
+ const nextChange = meaningfulChanges.find(c => c.lineNumber === r.lineNumber);
292
+ // 相差不超过 5 行,且是新增类型
293
+ return nextChange &&
294
+ nextChange.type === 'addition' &&
295
+ Math.abs(nextChange.lineNumber - currentChange.lineNumber) <= 5;
296
+ });
297
+
298
+ if (nextReviewIndex !== -1) {
299
+ const nextReview = reviews[nextReviewIndex];
300
+ const nextChange = meaningfulChanges.find(c => c.lineNumber === nextReview.lineNumber);
301
+
302
+ // 合并为一个修改块的评论
303
+ merged.push({
304
+ hasIssue: review.hasIssue || nextReview.hasIssue,
305
+ oldLine: currentChange.lineNumber, // 删除行
306
+ newLine: nextChange.lineNumber, // 新增行
307
+ comment: review.hasIssue ? review.comment : nextReview.comment, // 使用有问题的那个评论
308
+ });
309
+
310
+ processed.add(index);
311
+ processed.add(nextReviewIndex);
312
+ return;
313
+ }
314
+ }
315
+
316
+ // 如果不是修改块,保持原样
317
+ merged.push(review);
318
+ processed.add(index);
319
+ });
320
+
321
+ return merged;
322
+ }
323
+
269
324
  /**
270
325
  * 审查单个文件的所有变更(一次 API 调用)
271
326
  * @param {Object} change - 代码变更对象
@@ -406,10 +461,6 @@ export class GitLabAIReview {
406
461
  for (const review of fileReview.reviews) {
407
462
  if (review.hasIssue) {
408
463
  try {
409
- // 找到对应的变更,判断是删除还是新增
410
- const relatedChange = meaningfulChanges.find(c => c.lineNumber === review.lineNumber);
411
- const isDeletion = relatedChange && relatedChange.type === 'deletion';
412
-
413
464
  const commentResult = await this.gitlabClient.createLineComment(
414
465
  this.config.project.projectId,
415
466
  this.config.project.mergeRequestIid,
@@ -417,8 +468,7 @@ export class GitLabAIReview {
417
468
  {
418
469
  filePath: fileName,
419
470
  oldPath: change.old_path,
420
- // 删除的行使用 oldLine,新增的行使用 newLine
421
- ...(isDeletion ? { oldLine: review.lineNumber } : { newLine: review.lineNumber }),
471
+ newLine: review.lineNumber,
422
472
  }
423
473
  );
424
474
 
@@ -312,17 +312,12 @@ export function buildFileReviewWithImpactPrompt(fileName, meaningfulChanges, imp
312
312
 
313
313
  1. 仔细审查每一行变更,判断是否存在问题
314
314
  2. 注意区分**修改**和**重复定义**:如果同一位置有删除(-)和新增(+),这是修改,不是重复
315
- 3. **🚨 作用域检查的最高优先级:**
316
- - SDK 会标记"⚠️ **可能有局部定义/导入**"的行,这些行**大概率不是问题**
317
- - 对于标记的行,**默认假设不是问题**,除非有明确证据表明使用的是被删除的符号
318
- - 对于未标记的行,也要检查上下文(前后 3-5 行)是否有局部定义
319
- - **宁可漏报也不要误报**:不确定时不要报告为问题
320
- 4. **判断标准(按优先级):**
321
- - ✅ 有 "⚠️ 可能有局部定义" 标记 → **跳过,不报告**
322
- - ✅ 同一行或前几行有 \`const/let/var symbol\` → **跳过,不报告**
323
- - ✅ 同一行或前几行有 \`import { symbol }\` → **跳过,不报告**
324
- - ✅ 在函数参数中 \`function(symbol)\` → **跳过,不报告**
325
- - ❌ 确认是全局使用,且无局部定义 → **报告为问题**
315
+ 3. **🚨 检查删除的符号时,必须考虑作用域:**
316
+ - 检查使用处是否有**局部定义**(函数参数、局部变量、解构等)
317
+ - 检查使用处是否**重新导入**了同名符号
318
+ - 只有确认使用的是**被删除的这个符号**时,才报告为错误
319
+ - 示例:如果删除了全局函数 \`getData()\`,但使用处有 \`const getData = () => {...}\` 或 \`import { getData } from 'other'\`,则**不是问题**
320
+ 4. 优先检查"类型: 删除"的代码,确认是否有其他地方仍在使用
326
321
  5. **只对有问题的行提出审查意见**,没有问题的行不需要评论
327
322
  6. **必须使用中文**返回审查意见
328
323
  7. **必须返回标准 JSON 格式**,不要用其他格式,结构如下:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitlab-ai-review",
3
- "version": "3.7.0",
3
+ "version": "3.8.0",
4
4
  "description": "GitLab AI Review SDK with Impact Analysis - 支持影响分析、删除符号检测、注释代码识别、文件内部冲突检查、智能文件过滤的智能代码审查工具",
5
5
  "main": "index.js",
6
6
  "type": "module",