git diff结果解析
Opened this issue · 0 comments
tiodot commented
在使用fecs检测代码是否符合规范时,其检测都是针对整个文件,而预期的是只针对文件修改处做检测。而要想对某一个文件修改处做检测,无非可以:
- fecs提供ReadableStream流的检测,可以只检测修改部门;
- 检测整个文件,然后筛选修改出的检测结果;
对应第一种方式,由于改的代码可能都是某一个函数中某几行,由于没有上下文,检测结果会包含需要无用的提示,例如变量未定义,缩进问题等。
所以只能尝试第二种方案了,要实现这种方案,前提是文件处于一个git仓库中,关键问题是如何解析文件修改部分。具体思路是:fecs检测结果中会包含不规范代码的位置信息,然后依据修改代码的位置过滤出相关结果。
1. 获取文件修改
git diff
命令提供了对比两个文件,输出其差异化的功能。
使用git diff
输出的是一个合并格式,相关说明请查看git-diff文件格式解析 。一眼看上去可以很清楚的知道改动点,但是却无法直观的知道改动的具体对应文件哪行?
2. 解析diff结果
对应git diff
的结果:
@@ -4,6 +4,8 @@
*/
function parseParams(search) {
+
+ console.log('dd解决');
let ret = {},
seg = search.replace(/^\?/, '').split('&');
for (let i of seg) {
头部@@ -4,6 +4,8 @@
显示了文件修改的大致范围,而具体的修改位置则在代码片段中+
标识,而目标就是解析这些别修改代码的具体位置。
- 使用正则解析代码修改的起始位置,以及对应的代码片段;
- 通过解析代码片段,结合起始位置,精确定位修改的具体位置;
- 合并所有修改代码的位置信息。
代码实现为:
// 匹配代码修改正则
const unifiedDiffRegex = /^@@ -([\d]+),([\d]+) [+]([\d]+),([\d]+) @@([\s\S]*?)(?=^@@)/gm;
module.exports = function (str) {
const chunks = parse(str);
// 解析每一个代码修改片段,然后合并所有位置信息
// chunks.map(parseChunk) => [[8, 9], [18]]
// [[0, 1], [2, 3], [4, 5]].reduce((a, b) => a.concat(b)) => [0, 1, 2, 3, 4, 5]
return chunks.map(parseChunk).reduce((result, chunkLine) => result.concat(chunkLine));
};
// 通过正则解析git diff出来的代码修改的地方
function parse(data) {
let match;
let chunks = [];
do {
match = unifiedDiffRegex.exec(`${data}\n@@`);
if (match === null)
break;
// Stops excessive memory usage
// https://bugs.chromium.org/p/v8/issues/detail?id=2869
let chunk = (' ' + match[5]).substr(1);
let currentStart = parseInt(match[3], 10);
chunks.push({
chunk,
start: currentStart,
end: currentStart + parseInt(match[4], 10)
})
} while (match !== null);
return chunks;
}
// 解析每一个代码修改片段的具体修改位置
function parseChunk(chunkData) {
const lines = chunkData.chunk.split('\n');
lines.shift(); // 代码修改片段以\n开头,所以移除
const start = chunkData.start;
const chunkLines = [];
let offset = 0;
for (const l of lines) {
switch (l[0]) {
case '+':
chunkLines.push(start + offset);
break;
case '-':
offset--;
break;
default:
break;
}
offset++;
}
return chunkLines;
}
应用到上述中的git diff结果中, 其输出结果为[ 7, 8, 17 ]
,然后就可以过滤出fecs中检测结果。
未过滤之前的结果是: