diff2html/src/line-by-line-printer.js

238 lines
7.8 KiB
JavaScript
Raw Normal View History

2015-04-11 23:34:33 +00:00
/*
*
* LineByLinePrinter (line-by-line-printer.js)
* Author: rtfpessoa
*
*/
(function() {
var diffParser = require('./diff-parser.js').DiffParser;
var printerUtils = require('./printer-utils.js').PrinterUtils;
var utils = require('./utils.js').Utils;
var Rematch = require('./rematch.js').Rematch;
2016-01-31 18:33:33 +00:00
2016-10-09 15:41:54 +00:00
var hoganUtils;
2016-05-20 23:33:22 +00:00
var genericTemplatesPath = 'generic';
2016-01-31 18:33:33 +00:00
var baseTemplatesPath = 'line-by-line';
var iconsBaseTemplatesPath = 'icon';
var tagsBaseTemplatesPath = 'tag';
2015-04-12 01:59:54 +00:00
function LineByLinePrinter(config) {
this.config = config;
2016-10-09 15:41:54 +00:00
var HoganJsUtils = require('./hoganjs-utils.js').HoganJsUtils;
hoganUtils = new HoganJsUtils(config);
2015-04-12 01:59:54 +00:00
}
LineByLinePrinter.prototype.makeFileDiffHtml = function(file, diffs) {
if (this.config.renderNothingWhenEmpty && file.blocks && !file.blocks.length) return '';
var fileDiffTemplate = hoganUtils.template(baseTemplatesPath, 'file-diff');
2016-05-20 23:33:22 +00:00
var filePathTemplate = hoganUtils.template(genericTemplatesPath, 'file-path');
var fileIconTemplate = hoganUtils.template(iconsBaseTemplatesPath, 'file');
var fileTagTemplate = hoganUtils.template(tagsBaseTemplatesPath, printerUtils.getFileTypeIcon(file));
return fileDiffTemplate.render({
2016-04-15 22:08:57 +00:00
file: file,
fileHtmlId: printerUtils.getHtmlId(file),
2016-05-20 22:59:37 +00:00
diffs: diffs,
filePath: filePathTemplate.render({
fileDiffName: printerUtils.getDiffName(file)
}, {
fileIcon: fileIconTemplate,
fileTag: fileTagTemplate
})
});
};
LineByLinePrinter.prototype.makeLineByLineHtmlWrapper = function(content) {
2016-05-20 23:33:22 +00:00
return hoganUtils.render(genericTemplatesPath, 'wrapper', {'content': content});
};
LineByLinePrinter.prototype.generateLineByLineJsonHtml = function(diffFiles) {
var that = this;
var htmlDiffs = diffFiles.map(function(file) {
2016-01-31 18:33:33 +00:00
var diffs;
if (file.blocks.length) {
diffs = that._generateFileHtml(file);
} else {
diffs = that._generateEmptyDiff();
}
return that.makeFileDiffHtml(file, diffs);
});
return this.makeLineByLineHtmlWrapper(htmlDiffs.join('\n'));
2015-04-12 01:59:54 +00:00
};
var matcher = Rematch.rematch(function(a, b) {
var amod = a.content.substr(1);
var bmod = b.content.substr(1);
return Rematch.distance(amod, bmod);
});
LineByLinePrinter.prototype.makeColumnLineNumberHtml = function(block) {
2016-05-20 23:33:22 +00:00
return hoganUtils.render(genericTemplatesPath, 'column-line-number', {
2016-04-15 22:08:57 +00:00
diffParser: diffParser,
2017-03-17 23:57:09 +00:00
blockHeader: utils.escape(block.header),
2016-05-20 23:33:22 +00:00
lineClass: 'd2h-code-linenumber',
contentClass: 'd2h-code-line'
2016-04-15 22:08:57 +00:00
});
};
2015-04-12 01:59:54 +00:00
LineByLinePrinter.prototype._generateFileHtml = function(file) {
var that = this;
return file.blocks.map(function(block) {
var lines = that.makeColumnLineNumberHtml(block);
var oldLines = [];
var newLines = [];
function processChangeBlock() {
2015-12-09 22:17:26 +00:00
var matches;
var insertType;
var deleteType;
2016-04-14 11:01:25 +00:00
var comparisons = oldLines.length * newLines.length;
var maxLineSizeInBlock = Math.max.apply(null,
[0].concat((oldLines.concat(newLines)).map(
function(elem) {
return elem.content.length;
}
)));
var doMatching = comparisons < that.config.matchingMaxComparisons &&
maxLineSizeInBlock < that.config.maxLineSizeInBlockForComparison &&
(that.config.matching === 'lines' || that.config.matching === 'words');
2015-12-09 22:17:26 +00:00
if (doMatching) {
matches = matcher(oldLines, newLines);
insertType = diffParser.LINE_TYPE.INSERT_CHANGES;
deleteType = diffParser.LINE_TYPE.DELETE_CHANGES;
} else {
matches = [[oldLines, newLines]];
2015-12-09 22:17:26 +00:00
insertType = diffParser.LINE_TYPE.INSERTS;
deleteType = diffParser.LINE_TYPE.DELETES;
}
matches.forEach(function(match) {
oldLines = match[0];
newLines = match[1];
var processedOldLines = [];
var processedNewLines = [];
var common = Math.min(oldLines.length, newLines.length);
var oldLine, newLine;
for (var j = 0; j < common; j++) {
oldLine = oldLines[j];
newLine = newLines[j];
that.config.isCombined = file.isCombined;
var diff = printerUtils.diffHighlight(oldLine.content, newLine.content, that.config);
processedOldLines +=
that.makeLineHtml(file.isCombined, deleteType, oldLine.oldNumber, oldLine.newNumber,
diff.first.line, diff.first.prefix);
processedNewLines +=
that.makeLineHtml(file.isCombined, insertType, newLine.oldNumber, newLine.newNumber,
diff.second.line, diff.second.prefix);
}
lines += processedOldLines + processedNewLines;
lines += that._processLines(file.isCombined, oldLines.slice(common), newLines.slice(common));
});
oldLines = [];
newLines = [];
}
for (var i = 0; i < block.lines.length; i++) {
var line = block.lines[i];
var escapedLine = utils.escape(line.content);
if (line.type !== diffParser.LINE_TYPE.INSERTS &&
(newLines.length > 0 || (line.type !== diffParser.LINE_TYPE.DELETES && oldLines.length > 0))) {
processChangeBlock();
}
if (line.type === diffParser.LINE_TYPE.CONTEXT) {
lines += that.makeLineHtml(file.isCombined, line.type, line.oldNumber, line.newNumber, escapedLine);
} else if (line.type === diffParser.LINE_TYPE.INSERTS && !oldLines.length) {
lines += that.makeLineHtml(file.isCombined, line.type, line.oldNumber, line.newNumber, escapedLine);
} else if (line.type === diffParser.LINE_TYPE.DELETES) {
oldLines.push(line);
} else if (line.type === diffParser.LINE_TYPE.INSERTS && Boolean(oldLines.length)) {
newLines.push(line);
} else {
console.error('Unknown state in html line-by-line generator');
processChangeBlock();
2015-04-11 23:34:33 +00:00
}
}
2015-04-12 01:59:54 +00:00
processChangeBlock();
2015-04-19 23:24:19 +00:00
2015-04-12 01:59:54 +00:00
return lines;
}).join('\n');
};
2015-04-12 01:59:54 +00:00
LineByLinePrinter.prototype._processLines = function(isCombined, oldLines, newLines) {
var lines = '';
2015-04-19 23:24:19 +00:00
for (var i = 0; i < oldLines.length; i++) {
var oldLine = oldLines[i];
2015-04-19 23:24:19 +00:00
var oldEscapedLine = utils.escape(oldLine.content);
lines += this.makeLineHtml(isCombined, oldLine.type, oldLine.oldNumber, oldLine.newNumber, oldEscapedLine);
2015-04-19 23:24:19 +00:00
}
for (var j = 0; j < newLines.length; j++) {
2015-04-19 23:24:19 +00:00
var newLine = newLines[j];
var newEscapedLine = utils.escape(newLine.content);
lines += this.makeLineHtml(isCombined, newLine.type, newLine.oldNumber, newLine.newNumber, newEscapedLine);
2015-04-19 23:24:19 +00:00
}
return lines;
};
2015-04-19 23:24:19 +00:00
LineByLinePrinter.prototype.makeLineHtml = function(isCombined, type, oldNumber, newNumber, content, possiblePrefix) {
2016-05-20 23:33:22 +00:00
var lineNumberTemplate = hoganUtils.render(baseTemplatesPath, 'numbers', {
oldNumber: utils.valueOrEmpty(oldNumber),
newNumber: utils.valueOrEmpty(newNumber)
});
var lineWithoutPrefix = content;
var prefix = possiblePrefix;
if (!prefix) {
var lineWithPrefix = printerUtils.separatePrefix(isCombined, content);
prefix = lineWithPrefix.prefix;
lineWithoutPrefix = lineWithPrefix.line;
}
if (prefix === ' ') {
prefix = '&nbsp;';
}
2016-05-20 23:33:22 +00:00
return hoganUtils.render(genericTemplatesPath, 'line',
2016-01-31 18:33:33 +00:00
{
type: type,
2016-05-20 23:33:22 +00:00
lineClass: 'd2h-code-linenumber',
contentClass: 'd2h-code-line',
prefix: prefix,
content: lineWithoutPrefix,
2016-05-20 23:33:22 +00:00
lineNumber: lineNumberTemplate
2016-01-31 18:33:33 +00:00
});
};
2015-04-12 01:59:54 +00:00
LineByLinePrinter.prototype._generateEmptyDiff = function() {
2016-05-20 23:33:22 +00:00
return hoganUtils.render(genericTemplatesPath, 'empty-diff', {
contentClass: 'd2h-code-line',
2016-04-15 22:08:57 +00:00
diffParser: diffParser
});
};
2015-04-19 23:24:19 +00:00
module.exports.LineByLinePrinter = LineByLinePrinter;
})();