diff2html/src/printer-utils.js
2019-12-22 17:58:43 +00:00

264 lines
6.9 KiB
JavaScript

/*
*
* PrinterUtils (printer-utils.js)
* Author: rtfpessoa
*
*/
(function() {
const jsDiff = require("diff");
const utils = require("./utils.js").Utils;
const Rematch = require("./rematch.js").Rematch;
const separator = "/";
function PrinterUtils() {}
PrinterUtils.prototype.separatePrefix = function(isCombined, line) {
let prefix;
let lineWithoutPrefix;
if (isCombined) {
prefix = line.substring(0, 2);
lineWithoutPrefix = line.substring(2);
} else {
prefix = line.substring(0, 1);
lineWithoutPrefix = line.substring(1);
}
return {
prefix: prefix,
line: lineWithoutPrefix
};
};
PrinterUtils.prototype.getHtmlId = function(file) {
const hashCode = function(text) {
let i, chr, len;
let hash = 0;
for (i = 0, len = text.length; i < len; i++) {
chr = text.charCodeAt(i);
hash = (hash << 5) - hash + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
};
return (
"d2h-" +
hashCode(this.getDiffName(file))
.toString()
.slice(-6)
);
};
PrinterUtils.prototype.getDiffName = function(file) {
const oldFilename = unifyPath(file.oldName);
const newFilename = unifyPath(file.newName);
if (
oldFilename &&
newFilename &&
oldFilename !== newFilename &&
!isDevNullName(oldFilename) &&
!isDevNullName(newFilename)
) {
const prefixPaths = [];
const suffixPaths = [];
const oldFilenameParts = oldFilename.split(separator);
const newFilenameParts = newFilename.split(separator);
const oldFilenamePartsSize = oldFilenameParts.length;
const newFilenamePartsSize = newFilenameParts.length;
let i = 0;
let j = oldFilenamePartsSize - 1;
let k = newFilenamePartsSize - 1;
while (i < j && i < k) {
if (oldFilenameParts[i] === newFilenameParts[i]) {
prefixPaths.push(newFilenameParts[i]);
i += 1;
} else {
break;
}
}
while (j > i && k > i) {
if (oldFilenameParts[j] === newFilenameParts[k]) {
suffixPaths.unshift(newFilenameParts[k]);
j -= 1;
k -= 1;
} else {
break;
}
}
const finalPrefix = prefixPaths.join(separator);
const finalSuffix = suffixPaths.join(separator);
const oldRemainingPath = oldFilenameParts.slice(i, j + 1).join(separator);
const newRemainingPath = newFilenameParts.slice(i, k + 1).join(separator);
if (finalPrefix.length && finalSuffix.length) {
return (
finalPrefix + separator + "{" + oldRemainingPath + " → " + newRemainingPath + "}" + separator + finalSuffix
);
} else if (finalPrefix.length) {
return finalPrefix + separator + "{" + oldRemainingPath + " → " + newRemainingPath + "}";
} else if (finalSuffix.length) {
return "{" + oldRemainingPath + " → " + newRemainingPath + "}" + separator + finalSuffix;
}
return oldFilename + " → " + newFilename;
} else if (newFilename && !isDevNullName(newFilename)) {
return newFilename;
} else if (oldFilename) {
return oldFilename;
}
return "unknown/file/path";
};
PrinterUtils.prototype.getFileTypeIcon = function(file) {
let templateName = "file-changed";
if (file.isRename) {
templateName = "file-renamed";
} else if (file.isCopy) {
templateName = "file-renamed";
} else if (file.isNew) {
templateName = "file-added";
} else if (file.isDeleted) {
templateName = "file-deleted";
} else if (file.newName !== file.oldName) {
// If file is not Added, not Deleted and the names changed it must be a rename :)
templateName = "file-renamed";
}
return templateName;
};
PrinterUtils.prototype.diffHighlight = function(diffLine1, diffLine2, config) {
let linePrefix1, linePrefix2, unprefixedLine1, unprefixedLine2;
let prefixSize = 1;
if (config.isCombined) {
prefixSize = 2;
}
linePrefix1 = diffLine1.substr(0, prefixSize);
linePrefix2 = diffLine2.substr(0, prefixSize);
unprefixedLine1 = diffLine1.substr(prefixSize);
unprefixedLine2 = diffLine2.substr(prefixSize);
if (
unprefixedLine1.length > config.maxLineLengthHighlight ||
unprefixedLine2.length > config.maxLineLengthHighlight
) {
return {
first: {
prefix: linePrefix1,
line: utils.escape(unprefixedLine1)
},
second: {
prefix: linePrefix2,
line: utils.escape(unprefixedLine2)
}
};
}
let diff;
if (config.diffStyle === "char") {
diff = jsDiff.diffChars(unprefixedLine1, unprefixedLine2);
} else {
diff = jsDiff.diffWordsWithSpace(unprefixedLine1, unprefixedLine2);
}
let highlightedLine = "";
const changedWords = [];
if (config.diffStyle === "word" && config.matching === "words") {
let treshold = 0.25;
if (typeof config.matchWordsThreshold !== "undefined") {
treshold = config.matchWordsThreshold;
}
const matcher = Rematch.rematch(function(a, b) {
const amod = a.value;
const bmod = b.value;
return Rematch.distance(amod, bmod);
});
const removed = diff.filter(function isRemoved(element) {
return element.removed;
});
const added = diff.filter(function isAdded(element) {
return element.added;
});
const chunks = matcher(added, removed);
chunks.forEach(function(chunk) {
if (chunk[0].length === 1 && chunk[1].length === 1) {
const dist = Rematch.distance(chunk[0][0].value, chunk[1][0].value);
if (dist < treshold) {
changedWords.push(chunk[0][0]);
changedWords.push(chunk[1][0]);
}
}
});
}
diff.forEach(function(part) {
const addClass = changedWords.indexOf(part) > -1 ? ' class="d2h-change"' : "";
const elemType = part.added ? "ins" : part.removed ? "del" : null;
const escapedValue = utils.escape(part.value);
if (elemType !== null) {
highlightedLine += "<" + elemType + addClass + ">" + escapedValue + "</" + elemType + ">";
} else {
highlightedLine += escapedValue;
}
});
return {
first: {
prefix: linePrefix1,
line: removeIns(highlightedLine)
},
second: {
prefix: linePrefix2,
line: removeDel(highlightedLine)
}
};
};
function unifyPath(path) {
if (path) {
return path.replace("\\", "/");
}
return path;
}
function isDevNullName(name) {
return name.indexOf("dev/null") !== -1;
}
function removeIns(line) {
return line.replace(/(<ins[^>]*>((.|\n)*?)<\/ins>)/g, "");
}
function removeDel(line) {
return line.replace(/(<del[^>]*>((.|\n)*?)<\/del>)/g, "");
}
module.exports.PrinterUtils = new PrinterUtils();
})();