diff2html
Version:
Fast Diff to colorized HTML
246 lines • 9.21 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultRenderConfig = exports.CSSLineClass = void 0;
exports.toCSSClass = toCSSClass;
exports.colorSchemeToCss = colorSchemeToCss;
exports.escapeForHtml = escapeForHtml;
exports.deconstructLine = deconstructLine;
exports.filenameDiff = filenameDiff;
exports.getHtmlId = getHtmlId;
exports.getFileIcon = getFileIcon;
exports.diffHighlight = diffHighlight;
const jsDiff = __importStar(require("diff"));
const utils_1 = require("./utils");
const rematch = __importStar(require("./rematch"));
const types_1 = require("./types");
exports.CSSLineClass = {
INSERTS: 'd2h-ins',
DELETES: 'd2h-del',
CONTEXT: 'd2h-cntx',
INFO: 'd2h-info',
INSERT_CHANGES: 'd2h-ins d2h-change',
DELETE_CHANGES: 'd2h-del d2h-change',
};
exports.defaultRenderConfig = {
matching: types_1.LineMatchingType.NONE,
matchWordsThreshold: 0.25,
maxLineLengthHighlight: 10000,
diffStyle: types_1.DiffStyleType.WORD,
colorScheme: types_1.ColorSchemeType.LIGHT,
};
const separator = '/';
const distance = rematch.newDistanceFn((change) => change.value);
const matcher = rematch.newMatcherFn(distance);
function isDevNullName(name) {
return name.indexOf('dev/null') !== -1;
}
function removeInsElements(line) {
return line.replace(/(<ins[^>]*>((.|\n)*?)<\/ins>)/g, '');
}
function removeDelElements(line) {
return line.replace(/(<del[^>]*>((.|\n)*?)<\/del>)/g, '');
}
function toCSSClass(lineType) {
switch (lineType) {
case types_1.LineType.CONTEXT:
return exports.CSSLineClass.CONTEXT;
case types_1.LineType.INSERT:
return exports.CSSLineClass.INSERTS;
case types_1.LineType.DELETE:
return exports.CSSLineClass.DELETES;
}
}
function colorSchemeToCss(colorScheme) {
switch (colorScheme) {
case types_1.ColorSchemeType.DARK:
return 'd2h-dark-color-scheme';
case types_1.ColorSchemeType.AUTO:
return 'd2h-auto-color-scheme';
case types_1.ColorSchemeType.LIGHT:
default:
return 'd2h-light-color-scheme';
}
}
function prefixLength(isCombined) {
return isCombined ? 2 : 1;
}
function escapeForHtml(str) {
return str
.slice(0)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/\//g, '/');
}
function deconstructLine(line, isCombined, escape = true) {
const indexToSplit = prefixLength(isCombined);
return {
prefix: line.substring(0, indexToSplit),
content: escape ? escapeForHtml(line.substring(indexToSplit)) : line.substring(indexToSplit),
};
}
function filenameDiff(file) {
const oldFilename = (0, utils_1.unifyPath)(file.oldName);
const newFilename = (0, utils_1.unifyPath)(file.newName);
if (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 (!isDevNullName(newFilename)) {
return newFilename;
}
else {
return oldFilename;
}
}
function getHtmlId(file) {
return `d2h-${(0, utils_1.hashCode)(filenameDiff(file)).toString().slice(-6)}`;
}
function getFileIcon(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) {
templateName = 'file-renamed';
}
return templateName;
}
function diffHighlight(diffLine1, diffLine2, isCombined, config = {}) {
const { matching, maxLineLengthHighlight, matchWordsThreshold, diffStyle } = Object.assign(Object.assign({}, exports.defaultRenderConfig), config);
const line1 = deconstructLine(diffLine1, isCombined, false);
const line2 = deconstructLine(diffLine2, isCombined, false);
if (line1.content.length > maxLineLengthHighlight || line2.content.length > maxLineLengthHighlight) {
return {
oldLine: {
prefix: line1.prefix,
content: escapeForHtml(line1.content),
},
newLine: {
prefix: line2.prefix,
content: escapeForHtml(line2.content),
},
};
}
const diff = diffStyle === 'char'
? jsDiff.diffChars(line1.content, line2.content)
: jsDiff.diffWordsWithSpace(line1.content, line2.content);
const changedWords = [];
if (diffStyle === 'word' && matching === 'words') {
const removed = diff.filter(element => element.removed);
const added = diff.filter(element => element.added);
const chunks = matcher(added, removed);
chunks.forEach(chunk => {
if (chunk[0].length === 1 && chunk[1].length === 1) {
const dist = distance(chunk[0][0], chunk[1][0]);
if (dist < matchWordsThreshold) {
changedWords.push(chunk[0][0]);
changedWords.push(chunk[1][0]);
}
}
});
}
const highlightedLine = diff.reduce((highlightedLine, part) => {
const elemType = part.added ? 'ins' : part.removed ? 'del' : null;
const addClass = changedWords.indexOf(part) > -1 ? ' class="d2h-change"' : '';
const escapedValue = escapeForHtml(part.value);
return elemType !== null
? `${highlightedLine}<${elemType}${addClass}>${escapedValue}</${elemType}>`
: `${highlightedLine}${escapedValue}`;
}, '');
return {
oldLine: {
prefix: line1.prefix,
content: removeInsElements(highlightedLine),
},
newLine: {
prefix: line2.prefix,
content: removeDelElements(highlightedLine),
},
};
}
//# sourceMappingURL=render-utils.js.map
;