diffparser
Version:
Unified diff parser
211 lines (180 loc) • 7.51 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); /**
* Parse unified diff input
* see: http://www.gnu.org/software/diffutils/manual/diffutils.html#Unified-Format
*/
exports.default = function (input) {
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (!input) return [];
if (input.match(/^\s+$/)) return [];
var lines = input.split('\n');
if (lines.length == 0) return [];
var files = [];
var file = null;
var oldLine = 0;
var newLine = 0;
var position = 0;
var current = null;
function start(line) {
var _parseFile = parseFile(line),
_parseFile2 = _slicedToArray(_parseFile, 2),
from = _parseFile2[0],
to = _parseFile2[1];
file = {
from: from,
to: to,
chunks: [],
deletions: 0,
additions: 0
};
files.push(file);
position = 0;
}
function restart() {
if (!file || file.chunks.length) start();
}
function newFile() {
restart();
file.new = true;
file.from = '/dev/null';
}
function deletedFile() {
restart();
file.deleted = true;
file.to = '/dev/null';
}
function index(line) {
restart();
file.index = line.split(' ').slice(1);
}
function fromFile(line) {
restart();
file.from = parseFileFallback(line);
}
function toFile(line) {
restart();
file.to = parseFileFallback(line);
}
function chunk(line, match) {
var _match$map = match.map(function (l) {
return +(l || 0);
}),
_match$map2 = _slicedToArray(_match$map, 5),
oldStart = _match$map2[1],
oldLines = _match$map2[2],
newStart = _match$map2[3],
newLines = _match$map2[4];
oldLine = oldStart;
newLine = newStart;
current = {
content: line,
changes: [],
oldStart: oldStart,
oldLines: oldLines,
newStart: newStart,
newLines: newLines
};
file.chunks.push(current);
if (!position) position = 1;
}
function del(line) {
current.changes.push({
type: 'del',
del: true,
oldLine: oldLine++,
position: position++,
content: line
});
file.deletions++;
}
function add(line) {
current.changes.push({
type: 'add',
add: true,
newLine: newLine++,
position: position++,
content: line
});
file.additions++;
}
var noeol = '\\ No newline at end of file';
function normal(line) {
if (!file) return;
current.changes.push({
type: 'normal',
normal: true,
oldLine: line !== noeol ? oldLine++ : undefined,
newLine: line !== noeol ? newLine++ : undefined,
position: position++,
content: line
});
}
var schema = [[/^\s+/, normal], [/^diff\s/, start], [/^new file mode \d+$/, newFile], [/^deleted file mode \d+$/, deletedFile], [/^index\s[\da-zA-Z]+\.\.[\da-zA-Z]+(\s(\d+))?$/, index], [/^---\s/, fromFile], [/^\+\+\+\s/, toFile], [/^@@\s+\-(\d+),?(\d*)\s+\+(\d+),?(\d*)\s@@/, chunk], [/^-/, del], [/^\+/, add]];
function parse(line) {
return schema.some(function (p) {
var _p = _slicedToArray(p, 2),
pattern = _p[0],
handler = _p[1];
if (typeof handler !== 'function') {
throw new Error(pattern + ' has no handler');
}
var m = line.match(pattern);
if (m) {
handler(line, m);
return true;
}
return false;
});
}
lines.forEach(parse);
if (opts.findRenames) consolidateRenames(files);
return files;
};
function getContent(file) {
return file.chunks.map(function (chunk) {
return chunk.changes.map(function (c) {
return c.content.slice(1);
});
}).join('\n');
}
function consolidateRenames(files) {
var newFiles = files.filter(function (f) {
return f.new;
});
newFiles.forEach(function (newFile) {
var newContent = getContent(newFile);
var i = files.findIndex(function (f) {
return f.deleted && getContent(f) == newContent;
});
if (~i) {
var oldFile = files[i];
files.splice(i, 1);
delete newFile.new;
delete newFile.chunks;
delete newFile.deletions;
delete newFile.additions;
delete newFile.index;
newFile.renamed = true;
newFile.from = oldFile.from;
}
});
}
function parseFile(s) {
if (!s) return [];
var fileNames = s.split(' ').slice(-2);
return fileNames.map(function (f) {
return f.replace(/^(a|b)\//, '');
});
}
function parseFileFallback(s) {
s = s.replace(/^\s*(\++|-+)/, '').trim();
// ignore possible timestamp
var t = /\t.*|\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d(.\d+)?\s(\+|-)\d\d\d\d/.exec(s);
if (t) s = s.substring(0, t.index).trim();
// ignore git prefixes a/ or b/
return s.match(/^(a|b)\//) ? s.substr(2) : s;
}
module.exports = exports['default'];