git-blame
Version:
Shelling out to git blame in a streaming Node fashion.
101 lines (80 loc) • 2.21 kB
JavaScript
/* eslint-disable no-cond-assign */
;
var debug = require('debug')('git-blame:parser');
var splitStream = require('split-transform-stream');
module.exports = function streamBlame(inputStream) {
var blameLine;
var commit;
var lastCommitId;
function write(line, enc, cb) {
var key;
var pos;
var val;
var tmp;
debug('line', line);
var matched = line.match(/^(\w{40}) (\d+) (\d+)/);
if (matched) {
if (blameLine) {
this.emit('data', 'line', blameLine);
}
if (commit) {
this.emit('data', 'commit', commit);
}
blameLine = {
hash: matched[1],
originalLine: matched[2],
finalLine: matched[3]
};
lastCommitId = matched[1];
commit = null;
} else if (line.substring(0, 1) === '\t') {
blameLine.content = line.substring(1, line.length);
} else if (line) {
if (!commit) {
commit = { hash: lastCommitId, author: {}, committer: {} };
}
if (matched = line.match(/^(author|committer) (.*)/)) {
key = 'name';
val = matched[2];
commit[matched[1]][key] = val;
} else if (matched = line.match(/^(author|committer)-mail <(.*)>/)) {
key = 'mail';
val = matched[2];
commit[matched[1]][key] = val;
} else if (matched = line.match(/^(author|committer)-(.*) (.*)/)) {
key = matched[2];
val = matched[3];
if (key === 'time') {
key = 'timestamp';
val = parseInt(val, 10);
}
commit[matched[1]][key] = val;
} else {
pos = line.indexOf(' ');
key = line.substring(0, pos);
val = line.substring(pos + 1, line.length);
if (key === 'previous') {
tmp = val.split(' ');
val = {
hash: tmp[0],
filename: tmp[1]
};
}
if (key && val) {
commit[key] = val;
}
}
}
cb();
}
function end(cb) {
if (blameLine) {
this.emit('data', 'line', blameLine);
}
if (commit) {
this.emit('data', 'commit', commit);
}
cb();
}
return splitStream(inputStream, write, end);
};