UNPKG

jsondiffpatch

Version:
137 lines (126 loc) 4.13 kB
/* global diff_match_patch */ var TEXT_DIFF = 2; var DEFAULT_MIN_LENGTH = 60; var cachedDiffPatch = null; var getDiffMatchPatch = function(required) { /*jshint camelcase: false */ if (!cachedDiffPatch) { var instance; if (typeof diff_match_patch !== 'undefined') { // already loaded, probably a browser instance = typeof diff_match_patch === 'function' ? new diff_match_patch() : new diff_match_patch.diff_match_patch(); } else if (typeof require === 'function') { try { var dmpModuleName = 'diff_match_patch_uncompressed'; var dmp = require('../../public/external/' + dmpModuleName); instance = new dmp.diff_match_patch(); } catch (err) { instance = null; } } if (!instance) { if (!required) { return null; } var error = new Error('text diff_match_patch library not found'); error.diff_match_patch_not_found = true; throw error; } cachedDiffPatch = { diff: function(txt1, txt2) { return instance.patch_toText(instance.patch_make(txt1, txt2)); }, patch: function(txt1, patch) { var results = instance.patch_apply(instance.patch_fromText(patch), txt1); for (var i = 0; i < results[1].length; i++) { if (!results[1][i]) { var error = new Error('text patch failed'); error.textPatchFailed = true; } } return results[0]; } }; } return cachedDiffPatch; }; var diffFilter = function textsDiffFilter(context) { if (context.leftType !== 'string') { return; } var minLength = (context.options && context.options.textDiff && context.options.textDiff.minLength) || DEFAULT_MIN_LENGTH; if (context.left.length < minLength || context.right.length < minLength) { context.setResult([context.left, context.right]).exit(); return; } // large text, try to use a text-diff algorithm var diffMatchPatch = getDiffMatchPatch(); if (!diffMatchPatch) { // diff-match-patch library not available, fallback to regular string replace context.setResult([context.left, context.right]).exit(); return; } var diff = diffMatchPatch.diff; context.setResult([diff(context.left, context.right), 0, TEXT_DIFF]).exit(); }; diffFilter.filterName = 'texts'; var patchFilter = function textsPatchFilter(context) { if (context.nested) { return; } if (context.delta[2] !== TEXT_DIFF) { return; } // text-diff, use a text-patch algorithm var patch = getDiffMatchPatch(true).patch; context.setResult(patch(context.left, context.delta[0])).exit(); }; patchFilter.filterName = 'texts'; var textDeltaReverse = function(delta) { var i, l, lines, line, lineTmp, header = null, headerRegex = /^@@ +\-(\d+),(\d+) +\+(\d+),(\d+) +@@$/, lineHeader, lineAdd, lineRemove; lines = delta.split('\n'); for (i = 0, l = lines.length; i < l; i++) { line = lines[i]; var lineStart = line.slice(0, 1); if (lineStart === '@') { header = headerRegex.exec(line); lineHeader = i; lineAdd = null; lineRemove = null; // fix header lines[lineHeader] = '@@ -' + header[3] + ',' + header[4] + ' +' + header[1] + ',' + header[2] + ' @@'; } else if (lineStart === '+') { lineAdd = i; lines[i] = '-' + lines[i].slice(1); if (lines[i - 1].slice(0, 1) === '+') { // swap lines to keep default order (-+) lineTmp = lines[i]; lines[i] = lines[i - 1]; lines[i - 1] = lineTmp; } } else if (lineStart === '-') { lineRemove = i; lines[i] = '+' + lines[i].slice(1); } } return lines.join('\n'); }; var reverseFilter = function textsReverseFilter(context) { if (context.nested) { return; } if (context.delta[2] !== TEXT_DIFF) { return; } // text-diff, use a text-diff algorithm context.setResult([textDeltaReverse(context.delta[0]), 0, TEXT_DIFF]).exit(); }; reverseFilter.filterName = 'texts'; exports.diffFilter = diffFilter; exports.patchFilter = patchFilter; exports.reverseFilter = reverseFilter;