diff --git a/src/diff/base.js b/src/diff/base.js index b709585d4..b11e7e523 100644 --- a/src/diff/base.js +++ b/src/diff/base.js @@ -30,6 +30,10 @@ Diff.prototype = { let newLen = newString.length, oldLen = oldString.length; let editLength = 1; let maxEditLength = newLen + oldLen; + if(options.maxEditLength) { + maxEditLength = Math.min(maxEditLength, options.maxEditLength); + } + let bestPath = [{ newPos: -1, components: [] }]; // Seed editLength = 0, i.e. the content starts with the same values @@ -87,12 +91,11 @@ Diff.prototype = { // Performs the length of edit iteration. Is a bit fugly as this has to support the // sync and async mode which is never fun. Loops over execEditLength until a value - // is produced. + // is produced, or until the edit length exceeds options.maxEditLength (if given), + // in which case it will return undefined. if (callback) { (function exec() { setTimeout(function() { - // This should not happen, but we want to be safe. - /* istanbul ignore next */ if (editLength > maxEditLength) { return callback(); } diff --git a/src/patch/create.js b/src/patch/create.js index a48e1615c..384865457 100644 --- a/src/patch/create.js +++ b/src/patch/create.js @@ -9,6 +9,10 @@ export function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHea } const diff = diffLines(oldStr, newStr, options); + if(!diff) { + return; + } + diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier function contextLines(lines) { diff --git a/test/diff/line.js b/test/diff/line.js index 5c2c76578..6bc1e1832 100644 --- a/test/diff/line.js +++ b/test/diff/line.js @@ -46,6 +46,24 @@ describe('diff/line', function() { ''); expect(convertChangesToXML(diffResult)).to.equal('line\n\nold value \n\nline'); }); + + describe('given options.maxEditLength', function() { + it('terminates early', function() { + const diffResult = diffLines( + 'line\nold value\nline', + 'line\nnew value\nline', { maxEditLength: 1 }); + expect(diffResult).to.be.undefined; + }); + it('terminates early - async', function(done) { + function callback(diffResult) { + expect(diffResult).to.be.undefined; + done(); + } + diffLines( + 'line\nold value\nline', + 'line\nnew value\nline', { callback, maxEditLength: 1 }); + }); + }); }); // Trimmed Line Diff diff --git a/test/patch/create.js b/test/patch/create.js index 1315df564..5870b654b 100644 --- a/test/patch/create.js +++ b/test/patch/create.js @@ -649,6 +649,19 @@ describe('patch/create', function() { }] }); }); + + describe('given options.maxEditLength', function() { + const options = { maxEditLength: 1 }; + + it('terminates early', function() { + const res = structuredPatch( + 'oldfile', 'newfile', + 'line2\nline3\nline4\n', 'line2\nline3\nline5', + 'header1', 'header2', options + ); + expect(res).to.be.undefined; + }); + }); }); describe('#formatPatch', function() {