@wuyanbin/ai-code-review 1.1.5 → 1.1.6
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/reviewer/index.d.ts.map +1 -1
- package/dist/reviewer/index.js +15 -21
- package/dist/reviewer/index.js.map +1 -1
- package/dist/reviewer/utils.d.ts +40 -21
- package/dist/reviewer/utils.d.ts.map +1 -1
- package/dist/reviewer/utils.js +132 -103
- package/dist/reviewer/utils.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reviewer/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reviewer/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AA6ExD;;GAEG;AACH,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EACZ,QAAQ,gBAAgB,KACvB,OAAO,CAAC,UAAU,GAAG,IAAI,CAoF3B,CAAC"}
|
package/dist/reviewer/index.js
CHANGED
|
@@ -41,18 +41,12 @@ const buildUserPrompt = (diff, rules) => {
|
|
|
41
41
|
" }",
|
|
42
42
|
" ]",
|
|
43
43
|
"}",
|
|
44
|
-
"
|
|
44
|
+
"注意:",
|
|
45
45
|
"1. 一定要保证输出是合法的 JSON,不能包含注释或多余文本;",
|
|
46
46
|
'2. 如果没有任何问题,也请返回 {"comments": []};',
|
|
47
|
-
"3.
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"",
|
|
51
|
-
"Git diff 格式说明:",
|
|
52
|
-
"- diff 中的 @@ -a,b +c,d @@ 表示:新文件从第 c 行开始",
|
|
53
|
-
"- 以 + 开头的行是新增或修改的代码",
|
|
54
|
-
"- 以空格开头的行是上下文(未修改)",
|
|
55
|
-
"- 以 - 开头的行是删除的代码",
|
|
47
|
+
"3. line 字段必须使用 diff hunk 头中右侧的“新文件行号”(`@@ -old +new @@` 里 `+new` 一侧对应的行号)。",
|
|
48
|
+
" - 禁止使用左侧的 old 行号(`-old` 一侧),否则会导致评论定位偏移。",
|
|
49
|
+
" - 如果你无法确定精确的新行号,请不要输出该条 comment(宁可不报,也不要报错位置)。",
|
|
56
50
|
"",
|
|
57
51
|
"项目规范(摘要):",
|
|
58
52
|
rulesBrief,
|
|
@@ -90,9 +84,6 @@ const reviewCode = async (diff, config) => {
|
|
|
90
84
|
console.error("[reviewer] diff 为空,跳过审查");
|
|
91
85
|
return { comments: [] };
|
|
92
86
|
}
|
|
93
|
-
// 解析 diff,提取文件和行号映射
|
|
94
|
-
const diffFiles = (0, utils_1.parseDiffFiles)(effectiveDiff);
|
|
95
|
-
console.error(`[reviewer] 解析到 ${diffFiles.size} 个文件的变更信息`);
|
|
96
87
|
if (!config.ai.apiKey || !config.ai.endpoint) {
|
|
97
88
|
console.error("[reviewer] 缺少 API 配置");
|
|
98
89
|
return null;
|
|
@@ -115,14 +106,17 @@ const reviewCode = async (diff, config) => {
|
|
|
115
106
|
}
|
|
116
107
|
// 应用过滤和限制
|
|
117
108
|
let comments = result.comments || [];
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
109
|
+
// 先做“diff 行号归一化”,保证落点一定在 MR diff 的变更代码块上
|
|
110
|
+
{
|
|
111
|
+
const { comments: normalized, stats } = (0, utils_1.normalizeCommentsWithDiff)(comments, effectiveDiff);
|
|
112
|
+
comments = normalized;
|
|
113
|
+
if (stats.adjusted > 0) {
|
|
114
|
+
console.error(`[reviewer] 已纠偏 ${stats.adjusted} 条评论行号(old -> new)`);
|
|
115
|
+
}
|
|
116
|
+
if (stats.dropped > 0) {
|
|
117
|
+
console.error(`[reviewer] 已丢弃 ${stats.dropped} 条无法定位到 diff 变更行的评论(避免错块)`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
126
120
|
// 过滤 severity
|
|
127
121
|
if (config.review?.severity) {
|
|
128
122
|
const severityOrder = { info: 0, warning: 1, error: 2 };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/reviewer/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAGH,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/reviewer/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAGH,mCAAwE;AACxE,qDAAoE;AAEpE;;GAEG;AACH,MAAM,WAAW,GAAG;IAClB,0CAA0C;IAC1C,aAAa;IACb,iBAAiB;IACjB,kBAAkB;IAClB,aAAa;CACd,CAAC;AAEF;;GAEG;AACH,MAAM,iBAAiB,GAAG,GAAW,EAAE;IACrC,OAAO,+DAA+D,CAAC;AACzE,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,eAAe,GAAG,CAAC,IAAY,EAAE,KAAe,EAAU,EAAE;IAChE,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEpC,OAAO;QACL,gCAAgC;QAChC,yBAAyB;QACzB,GAAG;QACH,iBAAiB;QACjB,OAAO;QACP,8BAA8B;QAC9B,oBAAoB;QACpB,iDAAiD;QACjD,mCAAmC;QACnC,wCAAwC;QACxC,OAAO;QACP,KAAK;QACL,GAAG;QACH,KAAK;QACL,kCAAkC;QAClC,oCAAoC;QACpC,4EAA4E;QAC5E,6CAA6C;QAC7C,mDAAmD;QACnD,EAAE;QACF,WAAW;QACX,UAAU;QACV,EAAE;QACF,eAAe;QACf,IAAI;KACL,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,eAAe,GAAG,CAAC,OAAe,EAAqB,EAAE;IAC7D,4BAA4B;IAC5B,MAAM,WAAW,GAAG,OAAO;SACxB,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;SAChC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,IAAI,EAAE,CAAC;IAEV,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,UAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAC9C,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;QAC3C,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF;;GAEG;AACI,MAAM,UAAU,GAAG,KAAK,EAC7B,IAAY,EACZ,MAAwB,EACI,EAAE;IAC9B,gCAAgC;IAChC,MAAM,aAAa,GAAG,IAAA,0BAAkB,EAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEtE,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5C,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;QACzC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC1B,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC;QAC7C,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oBAAoB;IACpB,MAAM,KAAK,GAAG,CAAC,GAAG,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;IAEhE,YAAY;IACZ,MAAM,YAAY,GAAG,iBAAiB,EAAE,CAAC;IACzC,MAAM,UAAU,GAAG,eAAe,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IAEzD,kBAAkB;IAClB,MAAM,YAAY,GAAG,IAAA,mCAAyB,EAC5C,MAAM,CAAC,EAAE,CAAC,QAAQ,EAClB,MAAM,CAAC,EAAE,CAAC,MAAM,CACjB,CAAC;IACF,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,IAAI,CACxC,MAAM,CAAC,EAAE,CAAC,KAAK,EACf,YAAY,EACZ,UAAU,CACX,CAAC;IAEF,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;IACP,MAAM,MAAM,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAE3C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,UAAU;IACV,IAAI,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;IAErC,yCAAyC;IACzC,CAAC;QACC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,IAAA,iCAAyB,EAC/D,QAAQ,EACR,aAAa,CACd,CAAC;QACF,QAAQ,GAAG,UAAU,CAAC;QACtB,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,CACX,kBAAkB,KAAK,CAAC,QAAQ,oBAAoB,CACrD,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CACX,kBAAkB,KAAK,CAAC,OAAO,2BAA2B,CAC3D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,cAAc;IACd,IAAI,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC;QAC5B,MAAM,aAAa,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACxD,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvD,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,CAAC;IAC3E,CAAC;IAED,SAAS;IACT,IACE,MAAM,CAAC,MAAM,EAAE,WAAW;QAC1B,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,WAAW,EAC3C,CAAC;QACD,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CACV,4BAA4B,MAAM,CAAC,MAAM,CAAC,WAAW,IAAI,CAC1D,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,CAAC;AACtB,CAAC,CAAC;AAvFW,QAAA,UAAU,cAuFrB"}
|
package/dist/reviewer/utils.d.ts
CHANGED
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Diff 文件信息,包含行号映射
|
|
3
|
-
*/
|
|
4
|
-
export interface DiffFileInfo {
|
|
5
|
-
path: string;
|
|
6
|
-
changedLines: Set<number>;
|
|
7
|
-
lineRanges: Array<{
|
|
8
|
-
start: number;
|
|
9
|
-
count: number;
|
|
10
|
-
}>;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* 解析 Git diff,提取文件路径和变更行号
|
|
14
|
-
* 返回每个文件的变更信息
|
|
15
|
-
*/
|
|
16
|
-
export declare const parseDiffFiles: (diff: string) => Map<string, DiffFileInfo>;
|
|
17
|
-
/**
|
|
18
|
-
* 验证并修正评论的行号
|
|
19
|
-
* 如果行号不在变更行集合中,尝试找到最近的变更行
|
|
20
|
-
*/
|
|
21
|
-
export declare const validateAndFixLineNumber: (file: string, line: number, diffFiles: Map<string, DiffFileInfo>) => number;
|
|
22
1
|
/**
|
|
23
2
|
* 简单的 glob -> RegExp 转换,只覆盖当前项目常用模式:
|
|
24
3
|
*
|
|
@@ -36,4 +15,44 @@ export declare const shouldIgnoreFile: (filePath: string, ignorePatterns: string
|
|
|
36
15
|
* - 命中 ignore 的文件整块跳过
|
|
37
16
|
*/
|
|
38
17
|
export declare const filterDiffByIgnore: (diff: string, ignorePatterns: string[] | undefined) => string;
|
|
18
|
+
type DiffLineMappings = {
|
|
19
|
+
/**
|
|
20
|
+
* diff 中 new file 侧出现过的所有行号(包含 context + add)
|
|
21
|
+
* - 用于判断“这个 new 行号是否真的在 MR diff 里”
|
|
22
|
+
*/
|
|
23
|
+
newLinesInDiff: Set<number>;
|
|
24
|
+
/**
|
|
25
|
+
* diff 中 new file 侧真正变更的行号(仅 + 行)
|
|
26
|
+
* - 用于保证评论只落在改动行,避免 reviewdog 自动贴到邻近行造成“错块”
|
|
27
|
+
*/
|
|
28
|
+
changedNewLines: Set<number>;
|
|
29
|
+
/**
|
|
30
|
+
* old 行号 -> new 行号映射
|
|
31
|
+
* - 对 context 行:一一映射
|
|
32
|
+
* - 对替换行:尽量按顺序把 '-' 映射到后续的 '+'
|
|
33
|
+
*/
|
|
34
|
+
oldToNew: Map<number, number>;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* 解析 unified diff,构建每个文件的 old/new 行号映射
|
|
38
|
+
* - 仅支持常见的 `diff --git a/... b/...` + `@@ -a,b +c,d @@` 格式
|
|
39
|
+
*/
|
|
40
|
+
export declare const buildDiffLineMappingsByFile: (diff: string) => Map<string, DiffLineMappings>;
|
|
41
|
+
export type NormalizeCommentsStats = {
|
|
42
|
+
adjusted: number;
|
|
43
|
+
dropped: number;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* 将 AI 返回的 (file, line) 归一化到 “MR diff 的 new 行号(右侧)”
|
|
47
|
+
* - **保证不把评论贴到 diff 之外**(否则 reviewdog 会尝试找邻近位置,导致错块)
|
|
48
|
+
* - **默认只保留真正变更的 new 行(+ 行)**,确保评论落在改动代码块
|
|
49
|
+
*/
|
|
50
|
+
export declare const normalizeCommentsWithDiff: <T extends {
|
|
51
|
+
file: string;
|
|
52
|
+
line: number;
|
|
53
|
+
}>(comments: T[], diff: string) => {
|
|
54
|
+
comments: T[];
|
|
55
|
+
stats: NormalizeCommentsStats;
|
|
56
|
+
};
|
|
57
|
+
export {};
|
|
39
58
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/reviewer/utils.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/reviewer/utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,GAAI,SAAS,MAAM,KAAG,MAwB9C,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,UAAU,MAAM,EAAE,SAAS,MAAM,KAAG,OAG7D,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,UAAU,MAAM,EAChB,gBAAgB,MAAM,EAAE,GAAG,SAAS,KACnC,OAGF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAC7B,MAAM,MAAM,EACZ,gBAAgB,MAAM,EAAE,GAAG,SAAS,KACnC,MAiEF,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB;;;OAGG;IACH,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B;;;OAGG;IACH,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,2BAA2B,GACtC,MAAM,MAAM,KACX,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAiG9B,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GACpC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAExC,UAAU,CAAC,EAAE,EACb,MAAM,MAAM,KACX;IAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IAAC,KAAK,EAAE,sBAAsB,CAAA;CAqChD,CAAC"}
|
package/dist/reviewer/utils.js
CHANGED
|
@@ -1,108 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
/**
|
|
5
|
-
* 解析 Git diff,提取文件路径和变更行号
|
|
6
|
-
* 返回每个文件的变更信息
|
|
7
|
-
*/
|
|
8
|
-
const parseDiffFiles = (diff) => {
|
|
9
|
-
const files = new Map();
|
|
10
|
-
const lines = diff.split("\n");
|
|
11
|
-
let currentFile = null;
|
|
12
|
-
let currentFileInfo = null;
|
|
13
|
-
for (let i = 0; i < lines.length; i++) {
|
|
14
|
-
const line = lines[i];
|
|
15
|
-
// 检测新文件块:diff --git a/xxx b/xxx
|
|
16
|
-
if (line.startsWith("diff --git ")) {
|
|
17
|
-
const match = /^diff --git a\/(.+?) b\/(.+)$/.exec(line);
|
|
18
|
-
if (match) {
|
|
19
|
-
currentFile = match[2]; // 使用 b/ 路径(新文件路径)
|
|
20
|
-
currentFileInfo = {
|
|
21
|
-
path: currentFile,
|
|
22
|
-
changedLines: new Set(),
|
|
23
|
-
lineRanges: [],
|
|
24
|
-
};
|
|
25
|
-
files.set(currentFile, currentFileInfo);
|
|
26
|
-
}
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
// 解析行号范围标记:@@ -a,b +c,d @@
|
|
30
|
-
// -a,b 表示旧文件从第 a 行开始的 b 行
|
|
31
|
-
// +c,d 表示新文件从第 c 行开始的 d 行
|
|
32
|
-
if (line.startsWith("@@") && currentFileInfo) {
|
|
33
|
-
const match = /@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/.exec(line);
|
|
34
|
-
if (match) {
|
|
35
|
-
const newStart = parseInt(match[1], 10);
|
|
36
|
-
const newCount = match[2] ? parseInt(match[2], 10) : 1;
|
|
37
|
-
currentFileInfo.lineRanges.push({
|
|
38
|
-
start: newStart,
|
|
39
|
-
count: newCount,
|
|
40
|
-
});
|
|
41
|
-
// 记录从 @@ 标记后开始的实际行号
|
|
42
|
-
let lineNumber = newStart;
|
|
43
|
-
// 继续向下解析,直到遇到下一个 @@ 或 diff --git
|
|
44
|
-
for (let j = i + 1; j < lines.length; j++) {
|
|
45
|
-
const contentLine = lines[j];
|
|
46
|
-
// 遇到下一个块,停止
|
|
47
|
-
if (contentLine.startsWith("@@") ||
|
|
48
|
-
contentLine.startsWith("diff --git ")) {
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
// + 开头的是新增行
|
|
52
|
-
if (contentLine.startsWith("+") && !contentLine.startsWith("+++")) {
|
|
53
|
-
currentFileInfo.changedLines.add(lineNumber);
|
|
54
|
-
lineNumber++;
|
|
55
|
-
}
|
|
56
|
-
// 空格开头的是上下文行(未变更)
|
|
57
|
-
else if (contentLine.startsWith(" ")) {
|
|
58
|
-
lineNumber++;
|
|
59
|
-
}
|
|
60
|
-
// - 开头的是删除行,不增加新文件的行号
|
|
61
|
-
// 其他行(如 \ No newline)也忽略
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return files;
|
|
67
|
-
};
|
|
68
|
-
exports.parseDiffFiles = parseDiffFiles;
|
|
69
|
-
/**
|
|
70
|
-
* 验证并修正评论的行号
|
|
71
|
-
* 如果行号不在变更行集合中,尝试找到最近的变更行
|
|
72
|
-
*/
|
|
73
|
-
const validateAndFixLineNumber = (file, line, diffFiles) => {
|
|
74
|
-
const fileInfo = diffFiles.get(file);
|
|
75
|
-
if (!fileInfo) {
|
|
76
|
-
// 文件不在 diff 中,返回原始行号
|
|
77
|
-
console.warn(`[utils] 文件 ${file} 不在 diff 中,无法验证行号`);
|
|
78
|
-
return line;
|
|
79
|
-
}
|
|
80
|
-
// 如果行号正好在变更行集合中,直接返回
|
|
81
|
-
if (fileInfo.changedLines.has(line)) {
|
|
82
|
-
return line;
|
|
83
|
-
}
|
|
84
|
-
// 行号不在变更集合中,尝试找到最近的变更行
|
|
85
|
-
const changedLinesArray = Array.from(fileInfo.changedLines).sort((a, b) => a - b);
|
|
86
|
-
if (changedLinesArray.length === 0) {
|
|
87
|
-
console.warn(`[utils] 文件 ${file} 没有变更行,返回原始行号 ${line}`);
|
|
88
|
-
return line;
|
|
89
|
-
}
|
|
90
|
-
// 找到最接近的变更行
|
|
91
|
-
let closest = changedLinesArray[0];
|
|
92
|
-
let minDistance = Math.abs(line - closest);
|
|
93
|
-
for (const changedLine of changedLinesArray) {
|
|
94
|
-
const distance = Math.abs(line - changedLine);
|
|
95
|
-
if (distance < minDistance) {
|
|
96
|
-
minDistance = distance;
|
|
97
|
-
closest = changedLine;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (closest !== line) {
|
|
101
|
-
console.warn(`[utils] 行号修正: ${file}:${line} -> ${closest} (偏差 ${minDistance} 行)`);
|
|
102
|
-
}
|
|
103
|
-
return closest;
|
|
104
|
-
};
|
|
105
|
-
exports.validateAndFixLineNumber = validateAndFixLineNumber;
|
|
3
|
+
exports.normalizeCommentsWithDiff = exports.buildDiffLineMappingsByFile = exports.filterDiffByIgnore = exports.shouldIgnoreFile = exports.matchGlob = exports.globToRegExp = void 0;
|
|
106
4
|
/**
|
|
107
5
|
* 简单的 glob -> RegExp 转换,只覆盖当前项目常用模式:
|
|
108
6
|
*
|
|
@@ -202,4 +100,135 @@ const filterDiffByIgnore = (diff, ignorePatterns) => {
|
|
|
202
100
|
return kept.join("\n");
|
|
203
101
|
};
|
|
204
102
|
exports.filterDiffByIgnore = filterDiffByIgnore;
|
|
103
|
+
/**
|
|
104
|
+
* 解析 unified diff,构建每个文件的 old/new 行号映射
|
|
105
|
+
* - 仅支持常见的 `diff --git a/... b/...` + `@@ -a,b +c,d @@` 格式
|
|
106
|
+
*/
|
|
107
|
+
const buildDiffLineMappingsByFile = (diff) => {
|
|
108
|
+
const mappingsByFile = new Map();
|
|
109
|
+
if (!diff || !diff.trim())
|
|
110
|
+
return mappingsByFile;
|
|
111
|
+
const lines = diff.split("\n");
|
|
112
|
+
let currentFile = null;
|
|
113
|
+
let oldLine = 0;
|
|
114
|
+
let newLine = 0;
|
|
115
|
+
let inHunk = false;
|
|
116
|
+
let pendingDeletedOldLines = [];
|
|
117
|
+
const ensure = (file) => {
|
|
118
|
+
const existing = mappingsByFile.get(file);
|
|
119
|
+
if (existing)
|
|
120
|
+
return existing;
|
|
121
|
+
const created = {
|
|
122
|
+
newLinesInDiff: new Set(),
|
|
123
|
+
changedNewLines: new Set(),
|
|
124
|
+
oldToNew: new Map(),
|
|
125
|
+
};
|
|
126
|
+
mappingsByFile.set(file, created);
|
|
127
|
+
return created;
|
|
128
|
+
};
|
|
129
|
+
for (const rawLine of lines) {
|
|
130
|
+
// 文件块切换
|
|
131
|
+
if (rawLine.startsWith("diff --git ")) {
|
|
132
|
+
const match = /^diff --git a\/(.+?) b\/(.+)$/.exec(rawLine);
|
|
133
|
+
currentFile = match?.[2] ?? null;
|
|
134
|
+
inHunk = false;
|
|
135
|
+
oldLine = 0;
|
|
136
|
+
newLine = 0;
|
|
137
|
+
pendingDeletedOldLines = [];
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (!currentFile)
|
|
141
|
+
continue;
|
|
142
|
+
// 跳过二进制 / 无内容 diff
|
|
143
|
+
if (rawLine.startsWith("Binary files "))
|
|
144
|
+
continue;
|
|
145
|
+
// hunk 头
|
|
146
|
+
if (rawLine.startsWith("@@")) {
|
|
147
|
+
const hunk = /@@\s+-(\d+)(?:,(\d+))?\s+\+(\d+)(?:,(\d+))?\s+@@/.exec(rawLine);
|
|
148
|
+
if (!hunk) {
|
|
149
|
+
inHunk = false;
|
|
150
|
+
pendingDeletedOldLines = [];
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
oldLine = Number(hunk[1]);
|
|
154
|
+
newLine = Number(hunk[3]);
|
|
155
|
+
inHunk = true;
|
|
156
|
+
pendingDeletedOldLines = [];
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (!inHunk)
|
|
160
|
+
continue;
|
|
161
|
+
if (rawLine === "\")
|
|
162
|
+
continue;
|
|
163
|
+
const m = ensure(currentFile);
|
|
164
|
+
// 注意:diff 行可能是空行,rawLine[0] 也仍然存在(' ' / '+' / '-')
|
|
165
|
+
const prefix = rawLine[0];
|
|
166
|
+
if (prefix === " ") {
|
|
167
|
+
m.oldToNew.set(oldLine, newLine);
|
|
168
|
+
m.newLinesInDiff.add(newLine);
|
|
169
|
+
oldLine += 1;
|
|
170
|
+
newLine += 1;
|
|
171
|
+
// 回到对齐状态,清空未配对的删除行
|
|
172
|
+
pendingDeletedOldLines = [];
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (prefix === "-") {
|
|
176
|
+
pendingDeletedOldLines.push(oldLine);
|
|
177
|
+
oldLine += 1;
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (prefix === "+") {
|
|
181
|
+
m.newLinesInDiff.add(newLine);
|
|
182
|
+
m.changedNewLines.add(newLine);
|
|
183
|
+
// 尽量把替换行的 old 行号映射到 new 行号(按出现顺序配对)
|
|
184
|
+
const deletedOld = pendingDeletedOldLines.shift();
|
|
185
|
+
if (typeof deletedOld === "number") {
|
|
186
|
+
m.oldToNew.set(deletedOld, newLine);
|
|
187
|
+
}
|
|
188
|
+
newLine += 1;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return mappingsByFile;
|
|
193
|
+
};
|
|
194
|
+
exports.buildDiffLineMappingsByFile = buildDiffLineMappingsByFile;
|
|
195
|
+
/**
|
|
196
|
+
* 将 AI 返回的 (file, line) 归一化到 “MR diff 的 new 行号(右侧)”
|
|
197
|
+
* - **保证不把评论贴到 diff 之外**(否则 reviewdog 会尝试找邻近位置,导致错块)
|
|
198
|
+
* - **默认只保留真正变更的 new 行(+ 行)**,确保评论落在改动代码块
|
|
199
|
+
*/
|
|
200
|
+
const normalizeCommentsWithDiff = (comments, diff) => {
|
|
201
|
+
const stats = { adjusted: 0, dropped: 0 };
|
|
202
|
+
if (!Array.isArray(comments) || comments.length === 0) {
|
|
203
|
+
return { comments: [], stats };
|
|
204
|
+
}
|
|
205
|
+
const mappingsByFile = (0, exports.buildDiffLineMappingsByFile)(diff);
|
|
206
|
+
const normalized = [];
|
|
207
|
+
for (const c of comments) {
|
|
208
|
+
if (!c || !c.file || !c.line)
|
|
209
|
+
continue;
|
|
210
|
+
const m = mappingsByFile.get(c.file);
|
|
211
|
+
if (!m) {
|
|
212
|
+
// 文件不在 diff 中,直接丢弃避免错块
|
|
213
|
+
stats.dropped += 1;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
// 1) 优先认为 AI 给的是 new 行号
|
|
217
|
+
if (m.changedNewLines.has(c.line)) {
|
|
218
|
+
normalized.push(c);
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
// 2) 尝试把 old 行号映射到 new 行号
|
|
222
|
+
const mapped = m.oldToNew.get(c.line);
|
|
223
|
+
if (typeof mapped === "number" && m.changedNewLines.has(mapped)) {
|
|
224
|
+
normalized.push({ ...c, line: mapped });
|
|
225
|
+
stats.adjusted += 1;
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
// 3) 不在变更行:为了“绝不贴错块”,直接丢弃
|
|
229
|
+
stats.dropped += 1;
|
|
230
|
+
}
|
|
231
|
+
return { comments: normalized, stats };
|
|
232
|
+
};
|
|
233
|
+
exports.normalizeCommentsWithDiff = normalizeCommentsWithDiff;
|
|
205
234
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/reviewer/utils.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/reviewer/utils.ts"],"names":[],"mappings":"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"}
|