From 3d031b63c6de2f0da80a40dfdaf4c5ee2b077d14 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 18 Oct 2015 12:17:12 -0500 Subject: [PATCH 001/356] Fix travis unit test failure Hack around whatever this root issue is https://github.com/webpack/webpack/issues/1071 --- karma.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/karma.conf.js b/karma.conf.js index eb005407d..ba470c735 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -40,7 +40,7 @@ module.exports = function(config) { }, webpack: { - devtool: 'inline-source-map', + devtool: 'eval', module: { loaders: [ { From a3c8d94366d6495eaa5d0632e6a06c122382105f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Fri, 16 Oct 2015 00:37:51 +0200 Subject: [PATCH 002/356] Updated dependencies --- package.json | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 4865110fc..97e8e35a8 100644 --- a/package.json +++ b/package.json @@ -27,39 +27,39 @@ }, "dependencies": {}, "devDependencies": { - "async": "^1.4.0", - "babel": "^5.8.20", - "babel-core": "^5.8.20", + "async": "^1.4.2", + "babel": "^5.8.23", + "babel-core": "^5.8.25", "babel-loader": "^5.3.2", - "chai": "^3.2.0", - "colors": "^1.1.0", - "eslint": "^1.0.0", + "chai": "^3.3.0", + "colors": "^1.1.2", + "eslint": "^1.6.0", "grunt": "^0.4.5", - "grunt-babel": "^5.0.1", + "grunt-babel": "^5.0.3", "grunt-clean": "^0.4.0", "grunt-cli": "^0.1.13", "grunt-contrib-clean": "^0.6.0", - "grunt-contrib-copy": "^0.8.0", - "grunt-contrib-uglify": "^0.9.1", + "grunt-contrib-copy": "^0.8.1", + "grunt-contrib-uglify": "^0.9.2", "grunt-contrib-watch": "^0.6.1", - "grunt-eslint": "^17.0.0", - "grunt-karma": "^0.12.0", - "grunt-mocha-istanbul": "^2.4.0", + "grunt-eslint": "^17.3.1", + "grunt-karma": "^0.12.1", + "grunt-mocha-istanbul": "^3.0.1", "grunt-mocha-test": "^0.12.7", "grunt-webpack": "^1.0.11", - "istanbul": "^0.3.2", - "karma": "^0.13.8", + "istanbul": "^0.3.22", + "karma": "^0.13.11", "karma-mocha": "^0.2.0", "karma-mocha-reporter": "^1.1.1", "karma-phantomjs-launcher": "^0.2.1", "karma-sauce-launcher": "^0.2.14", - "karma-sourcemap-loader": "^0.3.5", + "karma-sourcemap-loader": "^0.3.6", "karma-webpack": "^1.7.0", - "mocha": "^2.2.4", - "phantomjs": "^1.9.17", - "semver": "^5.0.1", - "webpack": "^1.10.5", - "webpack-dev-server": "^1.10.1" + "mocha": "^2.3.3", + "phantomjs": "^1.9.18", + "semver": "^5.0.3", + "webpack": "^1.12.2", + "webpack-dev-server": "^1.12.0" }, "optionalDependencies": {} } From 0c9dd6d0e622d8a32b441b45baa797a7e86a4c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Thu, 15 Oct 2015 10:08:45 +0200 Subject: [PATCH 003/356] Allow patchs in diff format --- src/patch/parse.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/patch/parse.js b/src/patch/parse.js index e00619a6d..f00b474af 100644 --- a/src/patch/parse.js +++ b/src/patch/parse.js @@ -9,13 +9,13 @@ export function parsePatch(uniDiff, options = {}) { // Ignore any leading junk while (i < diffstr.length) { - if ((/^Index:/.test(diffstr[i])) || (/^@@/.test(diffstr[i]))) { + if (/^(Index:|diff -r|@@)/.test(diffstr[i])) { break; } i++; } - let header = (/^Index: (.*)/.exec(diffstr[i])); + let header = (/^(?:Index:|diff -r (?:\w+)) (.*)/.exec(diffstr[i])); if (header) { index.index = header[1]; i++; @@ -35,7 +35,7 @@ export function parsePatch(uniDiff, options = {}) { index.hunks = []; while (i < diffstr.length) { - if (/^Index:/.test(diffstr[i])) { + if (/^(Index:|diff -r)/.test(diffstr[i])) { break; } else if (/^@@/.test(diffstr[i])) { index.hunks.push(parseHunk()); From d501881150e4f93b3a47c9a82b04c6767b8165c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Thu, 15 Oct 2015 12:10:27 +0200 Subject: [PATCH 004/356] Allow headers with several revisions --- src/patch/parse.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/patch/parse.js b/src/patch/parse.js index f00b474af..4d0466dbd 100644 --- a/src/patch/parse.js +++ b/src/patch/parse.js @@ -15,7 +15,7 @@ export function parsePatch(uniDiff, options = {}) { i++; } - let header = (/^(?:Index:|diff -r (?:\w+)) (.*)/.exec(diffstr[i])); + let header = (/^(?:Index:|diff(?: -r \w+)+) (.*)/.exec(diffstr[i])); if (header) { index.index = header[1]; i++; From c238f85e34627cf020a7ce174733ff0dcb89d1c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Fri, 16 Oct 2015 00:47:14 +0200 Subject: [PATCH 005/356] Fix call to 'options.loadFile' with empty index --- src/patch/apply.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/patch/apply.js b/src/patch/apply.js index c86cae261..d3a85a2d8 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -84,7 +84,7 @@ export function applyPatches(uniDiff, options) { function processIndex() { let index = uniDiff[currentIndex++]; if (!index) { - options.complete(); + return options.complete(); } options.loadFile(index, function(err, data) { From 54edda72a054729c302152a1991a0fda894ca9c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Fri, 16 Oct 2015 01:44:27 +0200 Subject: [PATCH 006/356] Separated hunk sanity check from applyPatch algorythm --- src/patch/apply.js | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/patch/apply.js b/src/patch/apply.js index d3a85a2d8..5e2d2e3dc 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -24,25 +24,40 @@ export function applyPatch(source, uniDiff, options = {}) { removeEOFNL, addEOFNL; - for (let i = 0; i < hunks.length; i++) { - let hunk = hunks[i], - toPos = hunk.newStart - 1; - - // Sanity check the input string. Bail if we don't match. + // Sanity check the input string. Fail if we don't match. + function sanityCheck(hunk, toPos) { for (let j = 0; j < hunk.lines.length; j++) { let line = hunk.lines[j], operation = line[0], content = line.substr(1); + if (operation === ' ' || operation === '-') { // Context sanity check if (!compareLine(toPos + 1, lines[toPos], operation, content)) { errorCount++; if (errorCount > fuzzFactor) { - return false; + return true; } } + toPos++; } + } + } + + for (let i = 0; i < hunks.length; i++) { + let hunk = hunks[i], + toPos = hunk.newStart - 1; + + // Sanity check the input string. Fail if we don't match. + if (sanityCheck(hunk, toPos)) { + return false; + } + + for (let j = 0; j < hunk.lines.length; j++) { + let line = hunk.lines[j], + operation = line[0], + content = line.substr(1); if (operation === ' ') { toPos++; From 836a2f88b4b41291dd0d79f4157fd1b3b50860eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Fri, 16 Oct 2015 02:48:00 +0200 Subject: [PATCH 007/356] Do sanity check of all hunks on the diff at once before start applying them --- src/patch/apply.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/patch/apply.js b/src/patch/apply.js index 5e2d2e3dc..a5ddb58fa 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -24,8 +24,7 @@ export function applyPatch(source, uniDiff, options = {}) { removeEOFNL, addEOFNL; - // Sanity check the input string. Fail if we don't match. - function sanityCheck(hunk, toPos) { + function hunkFits(hunk, toPos) { for (let j = 0; j < hunk.lines.length; j++) { let line = hunk.lines[j], operation = line[0], @@ -37,22 +36,28 @@ export function applyPatch(source, uniDiff, options = {}) { errorCount++; if (errorCount > fuzzFactor) { - return true; + return false; } } toPos++; } } + + return true; } - for (let i = 0; i < hunks.length; i++) { - let hunk = hunks[i], - toPos = hunk.newStart - 1; + // Sanity check the input string. Fail if we don't match. + for (let i = 0; i < hunks.length; i++) { + let hunk = hunks[i]; - // Sanity check the input string. Fail if we don't match. - if (sanityCheck(hunk, toPos)) { + if (!hunkFits(hunk, hunk.oldStart - 1)) { return false; } + } + + for (let i = 0; i < hunks.length; i++) { + let hunk = hunks[i], + toPos = hunk.newStart - 1; for (let j = 0; j < hunk.lines.length; j++) { let line = hunk.lines[j], From 720f5aede23e20223f46cd0d3ef534efdcf56dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Fri, 16 Oct 2015 13:16:37 +0200 Subject: [PATCH 008/356] Calculate and apply location offset where hunk context can fit --- src/patch/apply.js | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/patch/apply.js b/src/patch/apply.js index a5ddb58fa..b2a727a62 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -19,6 +19,7 @@ export function applyPatch(source, uniDiff, options = {}) { compareLine = options.compareLine || ((lineNumber, line, operation, patchContent) => line === patchContent), errorCount = 0, + offset = 0, fuzzFactor = options.fuzzFactor || 0, removeEOFNL, @@ -46,18 +47,34 @@ export function applyPatch(source, uniDiff, options = {}) { return true; } - // Sanity check the input string. Fail if we don't match. + // Search best fit offsets for each hunk based on the previous ones for (let i = 0; i < hunks.length; i++) { - let hunk = hunks[i]; + let hunk = hunks[i], + minLine = 0, + toPos = offset + hunk.oldStart - 1; + + for (let localOffset = 0; ; localOffset++) { + if (toPos - localOffset < minLine + || lines.length < toPos + localOffset + hunk.oldLines) { + return false; + } - if (!hunkFits(hunk, hunk.oldStart - 1)) { - return false; + if (hunkFits(hunk, toPos - localOffset)) { + hunk.offset = offset -= localOffset; + minLine = hunk.offset + hunk.oldStart + hunk.oldLines; + break; + } + if (hunkFits(hunk, toPos + localOffset)) { + hunk.offset = offset += localOffset; + minLine = hunk.offset + hunk.oldStart + hunk.oldLines; + break; + } } } for (let i = 0; i < hunks.length; i++) { let hunk = hunks[i], - toPos = hunk.newStart - 1; + toPos = hunk.offset + hunk.newStart - 1; for (let j = 0; j < hunk.lines.length; j++) { let line = hunk.lines[j], From 0c2af7b132a578c3741404bbf6313b6fdb5c0a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Fri, 16 Oct 2015 15:07:15 +0200 Subject: [PATCH 009/356] Consider correctly both text limits instead of fail when reaching one --- src/patch/apply.js | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/patch/apply.js b/src/patch/apply.js index b2a727a62..8d0440421 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -50,28 +50,43 @@ export function applyPatch(source, uniDiff, options = {}) { // Search best fit offsets for each hunk based on the previous ones for (let i = 0; i < hunks.length; i++) { let hunk = hunks[i], + outOfLimits = 0, + localOffset = 0, minLine = 0, toPos = offset + hunk.oldStart - 1; - for (let localOffset = 0; ; localOffset++) { - if (toPos - localOffset < minLine - || lines.length < toPos + localOffset + hunk.oldLines) { - return false; + for (;;) { + if (toPos + localOffset + hunk.oldLines <= lines.length) { + if (hunkFits(hunk, toPos + localOffset)) { + hunk.offset = offset += localOffset; + break; + } + } else { + outOfLimits++; } - if (hunkFits(hunk, toPos - localOffset)) { - hunk.offset = offset -= localOffset; - minLine = hunk.offset + hunk.oldStart + hunk.oldLines; - break; + // If trying to fit hunk outside both limits, return error + if (outOfLimits === 2) { + return false; } - if (hunkFits(hunk, toPos + localOffset)) { - hunk.offset = offset += localOffset; - minLine = hunk.offset + hunk.oldStart + hunk.oldLines; - break; + + outOfLimits = 0; + localOffset++; + + if (minLine <= toPos - localOffset) { + if (hunkFits(hunk, toPos - localOffset)) { + hunk.offset = offset -= localOffset; + break; + } + } else { + outOfLimits++; } } + + minLine = hunk.offset + hunk.oldStart + hunk.oldLines; } + // Apply patch hunks for (let i = 0; i < hunks.length; i++) { let hunk = hunks[i], toPos = hunk.offset + hunk.newStart - 1; From d723875cd90b973c5ed89d06a6bfe99bc774d621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Fri, 16 Oct 2015 15:17:37 +0200 Subject: [PATCH 010/356] Test for hunk offsets --- test/patch/apply.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/patch/apply.js b/test/patch/apply.js index d15d8d0fd..d952ef8fe 100644 --- a/test/patch/apply.js +++ b/test/patch/apply.js @@ -374,6 +374,27 @@ describe('patch/apply', function() { + 'line5\n'); }); + it('should succeed when hunk has an offset', function() { + expect(applyPatch( + 'line1\n' + + 'line3\n' + + 'line4\n' + + 'line5\n', + + '--- test\theader1\n' + + '+++ test\theader2\n' + + '@@ -3,2 +3,3 @@\n' + + ' line1\n' + + '+line2\n' + + ' line3\n')) + .to.equal( + 'line1\n' + + 'line2\n' + + 'line3\n' + + 'line4\n' + + 'line5\n'); + }); + it('should allow custom line comparison', function() { expect(applyPatch( 'line2\n' From c6b6a02b0f7847762a781abf812b7d657b364676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Wed, 21 Oct 2015 13:29:57 +0200 Subject: [PATCH 011/356] Improved code documentation --- src/patch/apply.js | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/patch/apply.js b/src/patch/apply.js index 8d0440421..805d07b2b 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -19,12 +19,16 @@ export function applyPatch(source, uniDiff, options = {}) { compareLine = options.compareLine || ((lineNumber, line, operation, patchContent) => line === patchContent), errorCount = 0, - offset = 0, fuzzFactor = options.fuzzFactor || 0, + minLine = 0, + offset = 0, removeEOFNL, addEOFNL; + /** + * Checks if the hunk exactly fits on the provided location + */ function hunkFits(hunk, toPos) { for (let j = 0; j < hunk.lines.length; j++) { let line = hunk.lines[j], @@ -47,42 +51,46 @@ export function applyPatch(source, uniDiff, options = {}) { return true; } - // Search best fit offsets for each hunk based on the previous ones - for (let i = 0; i < hunks.length; i++) { + // Search best fit offsets for each hunk based on the previous ones + for (let i = 0; i < hunks.length; i++) { let hunk = hunks[i], outOfLimits = 0, localOffset = 0, - minLine = 0, toPos = offset + hunk.oldStart - 1; for (;;) { - if (toPos + localOffset + hunk.oldLines <= lines.length) { - if (hunkFits(hunk, toPos + localOffset)) { - hunk.offset = offset += localOffset; - break; - } - } else { + // Check if trying to fit beyond text length, and if not, check it fits + // after offset location (or desired location on first iteration) + if (lines.length < toPos + localOffset + hunk.oldLines) { outOfLimits++; + } else if (hunkFits(hunk, toPos + localOffset)) { + hunk.offset = offset += localOffset; + break; } - // If trying to fit hunk outside both limits, return error + // If we tried to fit hunk before text beginning and beyond text lenght, + // then hunk can't be fit on the text so we raise an error if (outOfLimits === 2) { return false; } + // Reset checks of trying to fit outside text limits and increase offset + // of the current hunk relative to its desired location outOfLimits = 0; localOffset++; - if (minLine <= toPos - localOffset) { - if (hunkFits(hunk, toPos - localOffset)) { - hunk.offset = offset -= localOffset; - break; - } - } else { + // Check if trying to fit before text beginning, and if not, check it fits + // before offset location + if (toPos - localOffset < minLine) { outOfLimits++; + } else if (hunkFits(hunk, toPos - localOffset)) { + hunk.offset = offset -= localOffset; + break; } } + // Set lower text limit to end of the current hunk, so next ones don't try + // to fit over already patched text minLine = hunk.offset + hunk.oldStart + hunk.oldLines; } From 3908658d05a1d853d5069445772c1e6cda79247e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Mon, 26 Oct 2015 11:52:12 +0100 Subject: [PATCH 012/356] Made code easier to understand & minor optimizations --- src/patch/apply.js | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/patch/apply.js b/src/patch/apply.js index 805d07b2b..53488df92 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -54,36 +54,42 @@ export function applyPatch(source, uniDiff, options = {}) { // Search best fit offsets for each hunk based on the previous ones for (let i = 0; i < hunks.length; i++) { let hunk = hunks[i], - outOfLimits = 0, + backwardExhausted = false, + forwardExhausted = false, localOffset = 0, - toPos = offset + hunk.oldStart - 1; + toPos = offset + hunk.oldStart - 1, + maxLine = lines.length - hunk.oldLines, + toCheck; for (;;) { // Check if trying to fit beyond text length, and if not, check it fits // after offset location (or desired location on first iteration) - if (lines.length < toPos + localOffset + hunk.oldLines) { - outOfLimits++; - } else if (hunkFits(hunk, toPos + localOffset)) { + toCheck = toPos + localOffset; + if (maxLine < toCheck) { + forwardExhausted = true; + } else if (hunkFits(hunk, toCheck)) { hunk.offset = offset += localOffset; break; } // If we tried to fit hunk before text beginning and beyond text lenght, // then hunk can't be fit on the text so we raise an error - if (outOfLimits === 2) { + if (backwardExhausted && forwardExhausted) { return false; } // Reset checks of trying to fit outside text limits and increase offset // of the current hunk relative to its desired location - outOfLimits = 0; + backwardExhausted = false; + forwardExhausted = false; localOffset++; // Check if trying to fit before text beginning, and if not, check it fits // before offset location - if (toPos - localOffset < minLine) { - outOfLimits++; - } else if (hunkFits(hunk, toPos - localOffset)) { + toCheck = toPos - localOffset; + if (toCheck < minLine) { + backwardExhausted = true; + } else if (hunkFits(hunk, toCheck)) { hunk.offset = offset -= localOffset; break; } From 09b7efe54f6cc26ba3bb8b8a2c31fe911b0a51ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Mon, 26 Oct 2015 16:51:04 +0100 Subject: [PATCH 013/356] Split logic for fit candidates on an iterator --- src/patch/apply.js | 81 ++++++++++++++++++++++++++++----------------- test/patch/apply.js | 23 ++++++++++++- 2 files changed, 72 insertions(+), 32 deletions(-) diff --git a/src/patch/apply.js b/src/patch/apply.js index 53488df92..e8af5cd70 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -51,50 +51,69 @@ export function applyPatch(source, uniDiff, options = {}) { return true; } - // Search best fit offsets for each hunk based on the previous ones - for (let i = 0; i < hunks.length; i++) { - let hunk = hunks[i], + function distanceIterator(toPos, minLine, maxLine) { + let wantForward = true, backwardExhausted = false, forwardExhausted = false, - localOffset = 0, - toPos = offset + hunk.oldStart - 1, - maxLine = lines.length - hunk.oldLines, - toCheck; + localOffset = 1; + + return function iterator() { + if (wantForward && !forwardExhausted) { + if (backwardExhausted) { + localOffset++; + } else { + wantForward = false; + } + + // Check if trying to fit beyond text length, and if not, check it fits + // after offset location (or desired location on first iteration) + if (toPos + localOffset <= maxLine) { + return localOffset; + } - for (;;) { - // Check if trying to fit beyond text length, and if not, check it fits - // after offset location (or desired location on first iteration) - toCheck = toPos + localOffset; - if (maxLine < toCheck) { forwardExhausted = true; - } else if (hunkFits(hunk, toCheck)) { - hunk.offset = offset += localOffset; - break; } - // If we tried to fit hunk before text beginning and beyond text lenght, - // then hunk can't be fit on the text so we raise an error - if (backwardExhausted && forwardExhausted) { - return false; - } + if (!backwardExhausted) { + if (!forwardExhausted) { + wantForward = true; + } - // Reset checks of trying to fit outside text limits and increase offset - // of the current hunk relative to its desired location - backwardExhausted = false; - forwardExhausted = false; - localOffset++; + // Check if trying to fit before text beginning, and if not, check it fits + // before offset location + if (minLine <= toPos - localOffset) { + return -localOffset++; + } - // Check if trying to fit before text beginning, and if not, check it fits - // before offset location - toCheck = toPos - localOffset; - if (toCheck < minLine) { backwardExhausted = true; - } else if (hunkFits(hunk, toCheck)) { - hunk.offset = offset -= localOffset; + return iterator(); + } + + // We tried to fit hunk before text beginning and beyond text lenght, then + // hunk can't fit on the text. Return undefined + }; + } + + // Search best fit offsets for each hunk based on the previous ones + for (let i = 0; i < hunks.length; i++) { + let hunk = hunks[i], + maxLine = lines.length - hunk.oldLines, + localOffset = 0, + toPos = offset + hunk.oldStart - 1; + + let iterator = distanceIterator(toPos, minLine, maxLine); + + for (; localOffset != undefined; localOffset = iterator()) { + if (hunkFits(hunk, toPos + localOffset)) { + hunk.offset = offset += localOffset; break; } } + if (localOffset == undefined) { + return false; + } + // Set lower text limit to end of the current hunk, so next ones don't try // to fit over already patched text minLine = hunk.offset + hunk.oldStart + hunk.oldLines; diff --git a/test/patch/apply.js b/test/patch/apply.js index d952ef8fe..236753150 100644 --- a/test/patch/apply.js +++ b/test/patch/apply.js @@ -374,7 +374,7 @@ describe('patch/apply', function() { + 'line5\n'); }); - it('should succeed when hunk has an offset', function() { + it('should succeed when hunk needs a negative offset', function() { expect(applyPatch( 'line1\n' + 'line3\n' @@ -395,6 +395,27 @@ describe('patch/apply', function() { + 'line5\n'); }); + it('should succeed when hunk needs a positive offset', function() { + expect(applyPatch( + 'line1\n' + + 'line2\n' + + 'line3\n' + + 'line5\n', + + '--- test\theader1\n' + + '+++ test\theader2\n' + + '@@ -1,2 +1,3 @@\n' + + ' line3\n' + + '+line4\n' + + ' line5\n')) + .to.equal( + 'line1\n' + + 'line2\n' + + 'line3\n' + + 'line4\n' + + 'line5\n'); + }); + it('should allow custom line comparison', function() { expect(applyPatch( 'line2\n' From 88bafde906d2d9bbda1cc4bdc0b362843c4391c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Mon, 26 Oct 2015 18:51:02 +0100 Subject: [PATCH 014/356] Use explicit undefined --- src/patch/apply.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/patch/apply.js b/src/patch/apply.js index e8af5cd70..d4ce8b777 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -103,14 +103,14 @@ export function applyPatch(source, uniDiff, options = {}) { let iterator = distanceIterator(toPos, minLine, maxLine); - for (; localOffset != undefined; localOffset = iterator()) { + for (; localOffset !== undefined; localOffset = iterator()) { if (hunkFits(hunk, toPos + localOffset)) { hunk.offset = offset += localOffset; break; } } - if (localOffset == undefined) { + if (localOffset === undefined) { return false; } From 048e7f726a6bda714b6a8711dfeffc50a69c6196 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Thu, 29 Oct 2015 01:23:39 -0500 Subject: [PATCH 015/356] Break distance iterator out into separate module --- src/patch/apply.js | 44 +--------------------------------- src/util/distance-iterator.js | 45 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 43 deletions(-) create mode 100644 src/util/distance-iterator.js diff --git a/src/patch/apply.js b/src/patch/apply.js index d4ce8b777..fda26ece3 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -1,4 +1,5 @@ import {parsePatch} from './parse'; +import distanceIterator from '../util/distance-iterator'; export function applyPatch(source, uniDiff, options = {}) { if (typeof uniDiff === 'string') { @@ -51,49 +52,6 @@ export function applyPatch(source, uniDiff, options = {}) { return true; } - function distanceIterator(toPos, minLine, maxLine) { - let wantForward = true, - backwardExhausted = false, - forwardExhausted = false, - localOffset = 1; - - return function iterator() { - if (wantForward && !forwardExhausted) { - if (backwardExhausted) { - localOffset++; - } else { - wantForward = false; - } - - // Check if trying to fit beyond text length, and if not, check it fits - // after offset location (or desired location on first iteration) - if (toPos + localOffset <= maxLine) { - return localOffset; - } - - forwardExhausted = true; - } - - if (!backwardExhausted) { - if (!forwardExhausted) { - wantForward = true; - } - - // Check if trying to fit before text beginning, and if not, check it fits - // before offset location - if (minLine <= toPos - localOffset) { - return -localOffset++; - } - - backwardExhausted = true; - return iterator(); - } - - // We tried to fit hunk before text beginning and beyond text lenght, then - // hunk can't fit on the text. Return undefined - }; - } - // Search best fit offsets for each hunk based on the previous ones for (let i = 0; i < hunks.length; i++) { let hunk = hunks[i], diff --git a/src/util/distance-iterator.js b/src/util/distance-iterator.js new file mode 100644 index 000000000..8360f43ed --- /dev/null +++ b/src/util/distance-iterator.js @@ -0,0 +1,45 @@ +// Iterator that traverses in the range of [min, max], stepping +// by distance from a given start position. I.e. for [0, 4], with +// start of 2, this will iterate 2, 3, 1, 4, 0. +export default function(start, minLine, maxLine) { + let wantForward = true, + backwardExhausted = false, + forwardExhausted = false, + localOffset = 1; + + return function iterator() { + if (wantForward && !forwardExhausted) { + if (backwardExhausted) { + localOffset++; + } else { + wantForward = false; + } + + // Check if trying to fit beyond text length, and if not, check it fits + // after offset location (or desired location on first iteration) + if (start + localOffset <= maxLine) { + return localOffset; + } + + forwardExhausted = true; + } + + if (!backwardExhausted) { + if (!forwardExhausted) { + wantForward = true; + } + + // Check if trying to fit before text beginning, and if not, check it fits + // before offset location + if (minLine <= start - localOffset) { + return -localOffset++; + } + + backwardExhausted = true; + return iterator(); + } + + // We tried to fit hunk before text beginning and beyond text lenght, then + // hunk can't fit on the text. Return undefined + }; +} From fad5197d900a618cc81f37fea88b4c1c20289cad Mon Sep 17 00:00:00 2001 From: kpdecker Date: Thu, 29 Oct 2015 01:45:07 -0500 Subject: [PATCH 016/356] Update release notes --- release-notes.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/release-notes.md b/release-notes.md index 9dcae9b12..24e49ed0f 100644 --- a/release-notes.md +++ b/release-notes.md @@ -2,7 +2,12 @@ ## Development -[Commits](https://github.com/kpdecker/jsdiff/compare/v2.1.3...master) +[Commits](https://github.com/kpdecker/jsdiff/compare/v2.2.0...master) + +## v2.2.0 - October 29th, 2015 +- [#80](https://github.com/kpdecker/jsdiff/pull/80) - Fix a typo: applyPath -> applyPatch ([@fluxxu](https://api.github.com/users/fluxxu)) +- [#83](https://github.com/kpdecker/jsdiff/pull/83) - Add basic fuzzy matching to applyPatch ([@piranna](https://github.com/piranna)) +[Commits](https://github.com/kpdecker/jsdiff/compare/v2.1.3...v2.2.0) ## v2.1.3 - September 30th, 2015 - [#78](https://github.com/kpdecker/jsdiff/pull/78) - fix: error throwing when apply patch to empty string ([@21paradox](https://api.github.com/users/21paradox)) From 8ebe13847a9596c810106a6e6594caa4feade8da Mon Sep 17 00:00:00 2001 From: kpdecker Date: Thu, 29 Oct 2015 01:46:08 -0500 Subject: [PATCH 017/356] Update release notes --- release-notes.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/release-notes.md b/release-notes.md index 24e49ed0f..3fef24383 100644 --- a/release-notes.md +++ b/release-notes.md @@ -4,6 +4,11 @@ [Commits](https://github.com/kpdecker/jsdiff/compare/v2.2.0...master) +## v2.2.0 - October 29th, 2015 +- [#80](https://github.com/kpdecker/jsdiff/pull/80) - Fix a typo: applyPath -> applyPatch ([@fluxxu](https://api.github.com/users/fluxxu)) +- [#83](https://github.com/kpdecker/jsdiff/pull/83) - Add basic fuzzy matching to applyPatch ([@piranna](https://github.com/piranna)) +[Commits](https://github.com/kpdecker/jsdiff/compare/v2.2.0...v2.2.0) + ## v2.2.0 - October 29th, 2015 - [#80](https://github.com/kpdecker/jsdiff/pull/80) - Fix a typo: applyPath -> applyPatch ([@fluxxu](https://api.github.com/users/fluxxu)) - [#83](https://github.com/kpdecker/jsdiff/pull/83) - Add basic fuzzy matching to applyPatch ([@piranna](https://github.com/piranna)) From 9aefc2a5286e7b30ba24b2e01cc897854e0c75c2 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Thu, 29 Oct 2015 01:46:20 -0500 Subject: [PATCH 018/356] v2.2.0 --- components/bower.json | 2 +- components/component.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/bower.json b/components/bower.json index 65f994184..6e8e891be 100644 --- a/components/bower.json +++ b/components/bower.json @@ -1,6 +1,6 @@ { "name": "jsdiff", - "version": "2.1.3", + "version": "2.2.0", "main": [ "diff.js" ], diff --git a/components/component.json b/components/component.json index 52e869811..de3239fc3 100644 --- a/components/component.json +++ b/components/component.json @@ -6,7 +6,7 @@ "diff", "text" ], - "version": "2.1.3", + "version": "2.2.0", "scripts": [ "diff.js" ], "main": "diff.js", "license": "BSD" diff --git a/package.json b/package.json index 97e8e35a8..f2f2d6aff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "diff", - "version": "2.1.3", + "version": "2.2.0", "description": "A javascript text diff implementation.", "keywords": [ "diff", From acb20d3c4fb32b4e34f5ce9f54223f6412c7f843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Thu, 29 Oct 2015 17:00:23 +0100 Subject: [PATCH 019/356] Split diffs based on file headers instead of 'Index:' metadata --- src/patch/parse.js | 45 +++++++++++++++++++++------------------------ test/patch/parse.js | 4 ++-- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/patch/parse.js b/src/patch/parse.js index 4d0466dbd..c804c6696 100644 --- a/src/patch/parse.js +++ b/src/patch/parse.js @@ -7,41 +7,38 @@ export function parsePatch(uniDiff, options = {}) { let index = {}; list.push(index); - // Ignore any leading junk - while (i < diffstr.length) { - if (/^(Index:|diff -r|@@)/.test(diffstr[i])) { + // Parse diff metadata + for (; i < diffstr.length; i++) { + let line = diffstr[i]; + + // File header found, end parsing diff metadata + if (/^(\-\-\-|\+\+\+|@@)/.test(line)) { break; } - i++; - } - let header = (/^(?:Index:|diff(?: -r \w+)+) (.*)/.exec(diffstr[i])); - if (header) { - index.index = header[1]; - i++; - - if (/^===/.test(diffstr[i])) { - i++; + // Diff index + let header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line); + if (header) { + index.index = header[1]; } - - parseFileHeader(index); - parseFileHeader(index); - } else { - // Ignore erant header components that might occur at the start of the file - parseFileHeader({}); - parseFileHeader({}); } + parseFileHeader(index); + parseFileHeader(index); + + // Parse hunks index.hunks = []; while (i < diffstr.length) { - if (/^(Index:|diff -r)/.test(diffstr[i])) { + let line = diffstr[i]; + + if (/^(Index:|diff|\-\-\-|\+\+\+)\s/.test(line)) { break; - } else if (/^@@/.test(diffstr[i])) { + } else if (/^@@\s/.test(line)) { index.hunks.push(parseHunk()); - } else if (diffstr[i] && options.strict) { + } else if (line && options.strict) { // Ignore unexpected content unless in strict mode - throw new Error('Unknown line ' + (i + 1) + ' ' + JSON.stringify(diffstr[i])); + throw new Error('Unknown line ' + (i + 1) + ' ' + JSON.stringify(line)); } else { i++; } @@ -51,7 +48,7 @@ export function parsePatch(uniDiff, options = {}) { // Parses the --- and +++ headers, if none are found, no lines // are consumed. function parseFileHeader(index) { - let fileHeader = (/^(\-\-\-|\+\+\+)\s(\S+)\s?(.*)/.exec(diffstr[i])); + let fileHeader = /^(\-\-\-|\+\+\+)\s+(\S+)\s?(.+)/.exec(diffstr[i]); if (fileHeader) { let keyPrefix = fileHeader[1] === '---' ? 'old' : 'new'; index[keyPrefix + 'FileName'] = fileHeader[2]; diff --git a/test/patch/parse.js b/test/patch/parse.js index a7a9cb2d9..cbe0350b3 100644 --- a/test/patch/parse.js +++ b/test/patch/parse.js @@ -248,8 +248,8 @@ Index: test2 }); it('should throw on invalid input in strict mode', function() { expect(function() { - parsePatch('Index: foo\nfoo', {strict: true}); - }).to['throw'](/Unknown line 2 "foo"/); + parsePatch('Index: foo\n+++', {strict: true}); + }).to['throw'](/Unknown line 2 "\+\+\+"/); }); }); }); From a4178de3c16a88c2715533bf2e7cafa721a29b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro?= Date: Thu, 29 Oct 2015 19:05:55 +0100 Subject: [PATCH 020/356] Removed style changes --- src/patch/parse.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/patch/parse.js b/src/patch/parse.js index c804c6696..65a0f9861 100644 --- a/src/patch/parse.js +++ b/src/patch/parse.js @@ -8,7 +8,7 @@ export function parsePatch(uniDiff, options = {}) { list.push(index); // Parse diff metadata - for (; i < diffstr.length; i++) { + while (i < diffstr.length) { let line = diffstr[i]; // File header found, end parsing diff metadata @@ -21,6 +21,8 @@ export function parsePatch(uniDiff, options = {}) { if (header) { index.index = header[1]; } + + i++; } parseFileHeader(index); From 41e3e292929204c5923dccf4eb850478b17d9da6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Thu, 5 Nov 2015 14:17:25 +0100 Subject: [PATCH 021/356] Fix lint on regexp --- src/patch/parse.js | 6 +++--- test/patch/parse.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/patch/parse.js b/src/patch/parse.js index c804c6696..6e3672af3 100644 --- a/src/patch/parse.js +++ b/src/patch/parse.js @@ -12,12 +12,12 @@ export function parsePatch(uniDiff, options = {}) { let line = diffstr[i]; // File header found, end parsing diff metadata - if (/^(\-\-\-|\+\+\+|@@)/.test(line)) { + if (/^(\-\-\-|\+\+\+|@@)\s/.test(line)) { break; } // Diff index - let header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line); + let header = (/^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/).exec(line); if (header) { index.index = header[1]; } @@ -48,7 +48,7 @@ export function parsePatch(uniDiff, options = {}) { // Parses the --- and +++ headers, if none are found, no lines // are consumed. function parseFileHeader(index) { - let fileHeader = /^(\-\-\-|\+\+\+)\s+(\S+)\s?(.+)/.exec(diffstr[i]); + let fileHeader = (/^(\-\-\-|\+\+\+)\s+(\S+)\s?(.+)/).exec(diffstr[i]); if (fileHeader) { let keyPrefix = fileHeader[1] === '---' ? 'old' : 'new'; index[keyPrefix + 'FileName'] = fileHeader[2]; diff --git a/test/patch/parse.js b/test/patch/parse.js index cbe0350b3..61818cf2f 100644 --- a/test/patch/parse.js +++ b/test/patch/parse.js @@ -248,8 +248,8 @@ Index: test2 }); it('should throw on invalid input in strict mode', function() { expect(function() { - parsePatch('Index: foo\n+++', {strict: true}); - }).to['throw'](/Unknown line 2 "\+\+\+"/); + parsePatch('Index: foo\n+++ bar\nblah', {strict: true}); + }).to['throw'](/Unknown line 3 "blah"/); }); }); }); From 3ab1df8a3f9beeaf2ca65edede90a9ab35fafcd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s=20Combarro=20=22piranna?= Date: Fri, 6 Nov 2015 11:50:36 +0100 Subject: [PATCH 022/356] Less restrictive regexp & 'should handle patches without Index' test --- src/patch/parse.js | 6 ++++-- test/patch/apply.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/patch/parse.js b/src/patch/parse.js index c948edafc..bbcff5fdc 100644 --- a/src/patch/parse.js +++ b/src/patch/parse.js @@ -25,6 +25,8 @@ export function parsePatch(uniDiff, options = {}) { i++; } + // Parse file headers if they are defined. Unified diff requires them, but + // there's no technical issues to have an isolated hunk without file header parseFileHeader(index); parseFileHeader(index); @@ -36,7 +38,7 @@ export function parsePatch(uniDiff, options = {}) { if (/^(Index:|diff|\-\-\-|\+\+\+)\s/.test(line)) { break; - } else if (/^@@\s/.test(line)) { + } else if (/^@@/.test(line)) { index.hunks.push(parseHunk()); } else if (line && options.strict) { // Ignore unexpected content unless in strict mode @@ -50,7 +52,7 @@ export function parsePatch(uniDiff, options = {}) { // Parses the --- and +++ headers, if none are found, no lines // are consumed. function parseFileHeader(index) { - let fileHeader = (/^(\-\-\-|\+\+\+)\s+(\S+)\s?(.+)/).exec(diffstr[i]); + let fileHeader = (/^(\-\-\-|\+\+\+)\s+(\S+)\s?(.+?)\s*$/).exec(diffstr[i]); if (fileHeader) { let keyPrefix = fileHeader[1] === '---' ? 'old' : 'new'; index[keyPrefix + 'FileName'] = fileHeader[2]; diff --git a/test/patch/apply.js b/test/patch/apply.js index 236753150..dbf24277f 100644 --- a/test/patch/apply.js +++ b/test/patch/apply.js @@ -554,5 +554,36 @@ describe('patch/apply', function() { } }); }); + it('should handle patches without Index', function(done) { + const patch = + '===================================================================\n' + + '--- test\theader1\n' + + '+++ test\theader2\n' + + '@@ -1,3 +1,4 @@\n' + + ' line2\n' + + ' line3\n' + + '+line4\n' + + ' line5\n' + + '===================================================================\n' + + '--- test2\theader1\n' + + '+++ test2\theader2\n' + + '@@ -1,3 +1,4 @@\n' + + ' foo2\n' + + ' foo3\n' + + '+foo4\n' + + ' foo5\n'; + + applyPatches(patch, { + loadFile(index, callback) { + callback(undefined, contents[index.oldFileName]); + }, + patched(index, content) { + expect(content) + .to.equal(expected[index.newFileName]) + .to.not.be.undefined; + }, + complete: done + }); + }); }); }); From fd3f0dc8a81f215490e7430b10383e5e86f13a06 Mon Sep 17 00:00:00 2001 From: Francisco Dias Date: Mon, 9 Nov 2015 18:18:05 -0500 Subject: [PATCH 023/356] add in display selector --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ca00a744d..286e0f674 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ var one = 'beep boop'; var other = 'beep boob blah'; var diff = JsDiff.diffChars(one, other); +var display = document.getElementById('display'); diff.forEach(function(part){ // green for additions, red for deletions From 74311ce0e002db1c3cd5914b5b41aa81c6560a1f Mon Sep 17 00:00:00 2001 From: kpdecker Date: Thu, 12 Nov 2015 22:25:49 -0600 Subject: [PATCH 024/356] Update release notes --- release-notes.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/release-notes.md b/release-notes.md index 3fef24383..9c075e50b 100644 --- a/release-notes.md +++ b/release-notes.md @@ -2,7 +2,13 @@ ## Development -[Commits](https://github.com/kpdecker/jsdiff/compare/v2.2.0...master) +[Commits](https://github.com/kpdecker/jsdiff/compare/v2.2.1...master) + +## v2.2.1 - November 12th, 2015 +- [#89](https://github.com/kpdecker/jsdiff/pull/89) - add in display selector to readme ([@FranDias](https://api.github.com/users/FranDias)) +- [#88](https://github.com/kpdecker/jsdiff/pull/88) - Split diffs based on file headers instead of 'Index:' metadata ([@piranna](https://api.github.com/users/piranna)) + +[Commits](https://github.com/kpdecker/jsdiff/compare/v2.2.0...v2.2.1) ## v2.2.0 - October 29th, 2015 - [#80](https://github.com/kpdecker/jsdiff/pull/80) - Fix a typo: applyPath -> applyPatch ([@fluxxu](https://api.github.com/users/fluxxu)) From 0b8e83f6208c98f28d5a833b32d86b44fdabea1c Mon Sep 17 00:00:00 2001 From: kpdecker Date: Thu, 12 Nov 2015 22:26:02 -0600 Subject: [PATCH 025/356] v2.2.1 --- components/bower.json | 2 +- components/component.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/bower.json b/components/bower.json index 6e8e891be..57413fb38 100644 --- a/components/bower.json +++ b/components/bower.json @@ -1,6 +1,6 @@ { "name": "jsdiff", - "version": "2.2.0", + "version": "2.2.1", "main": [ "diff.js" ], diff --git a/components/component.json b/components/component.json index de3239fc3..dec6bee1d 100644 --- a/components/component.json +++ b/components/component.json @@ -6,7 +6,7 @@ "diff", "text" ], - "version": "2.2.0", + "version": "2.2.1", "scripts": [ "diff.js" ], "main": "diff.js", "license": "BSD" diff --git a/package.json b/package.json index f2f2d6aff..451cdd226 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "diff", - "version": "2.2.0", + "version": "2.2.1", "description": "A javascript text diff implementation.", "keywords": [ "diff", From abc8e32daa42d30707ef4962660ec79e307f61a0 Mon Sep 17 00:00:00 2001 From: Brandon Gonzalez Date: Sat, 19 Dec 2015 23:44:01 -0800 Subject: [PATCH 026/356] Fixes typo in the readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 286e0f674..d2df2eaf3 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ or * `oldStr` : Original string value * `newStr` : New string value * `oldHeader` : Additional information to include in the old file header - * `newHeader` : Additional information to include in thew new file header + * `newHeader` : Additional information to include in the new file header * `options` : An object with options. Currently, only `context` is supported and describes how many lines of context should be included. * `JsDiff.createPatch(fileName, oldStr, newStr, oldHeader, newHeader)` - creates a unified diff patch. From a8df4be634b12702fed6bfc36e7999e586009e51 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Wed, 24 Feb 2016 01:38:34 -0600 Subject: [PATCH 027/356] Relax parser when no file header name is provided Fixes #101 --- src/patch/parse.js | 2 +- test/patch/parse.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/patch/parse.js b/src/patch/parse.js index bbcff5fdc..e371a07d8 100644 --- a/src/patch/parse.js +++ b/src/patch/parse.js @@ -52,7 +52,7 @@ export function parsePatch(uniDiff, options = {}) { // Parses the --- and +++ headers, if none are found, no lines // are consumed. function parseFileHeader(index) { - let fileHeader = (/^(\-\-\-|\+\+\+)\s+(\S+)\s?(.+?)\s*$/).exec(diffstr[i]); + let fileHeader = (/^(\-\-\-|\+\+\+)\s+(\S*)\s?(.*?)\s*$/).exec(diffstr[i]); if (fileHeader) { let keyPrefix = fileHeader[1] === '---' ? 'old' : 'new'; index[keyPrefix + 'FileName'] = fileHeader[2]; diff --git a/test/patch/parse.js b/test/patch/parse.js index 61818cf2f..fc06afcaf 100644 --- a/test/patch/parse.js +++ b/test/patch/parse.js @@ -251,5 +251,9 @@ Index: test2 parsePatch('Index: foo\n+++ bar\nblah', {strict: true}); }).to['throw'](/Unknown line 3 "blah"/); }); + + it('should handle OOM case', function() { + parsePatch('Index: \n===================================================================\n--- \n+++ \n@@ -1,1 +1,2 @@\n-1\n\\ No newline at end of file\n+1\n+2\n'); + }); }); }); From e48c7dd5313b34d66d64e606f1941a223a2854cf Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 12 Mar 2016 22:34:53 -0600 Subject: [PATCH 028/356] Update to babel 6 --- Gruntfile.js | 10 +--------- package.json | 20 ++++++++++++++------ runtime.js | 3 +++ test/mocha.opts | 2 +- 4 files changed, 19 insertions(+), 16 deletions(-) create mode 100644 runtime.js diff --git a/Gruntfile.js b/Gruntfile.js index 65bd332d9..a1d0085fb 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -17,15 +17,7 @@ module.exports = function(grunt) { clean: ['lib', 'dist'], babel: { - options: { - sourceMaps: 'inline', - loose: ['es6.modules'], - auxiliaryCommentBefore: 'istanbul ignore next' - }, cjs: { - options: { - modules: 'common' - }, files: [{ cwd: 'src/', expand: true, @@ -54,7 +46,7 @@ module.exports = function(grunt) { mochaTest: { test: { options: { - require: ['babel/register'], + require: ['babel-core/register'], reporter: 'dot' }, src: ['test/**/*.js'] diff --git a/package.json b/package.json index 451cdd226..6836f9bcf 100644 --- a/package.json +++ b/package.json @@ -28,14 +28,14 @@ "dependencies": {}, "devDependencies": { "async": "^1.4.2", - "babel": "^5.8.23", - "babel-core": "^5.8.25", - "babel-loader": "^5.3.2", + "babel-core": "^6.0.0", + "babel-loader": "^6.0.0", + "babel-preset-es2015-mod": "^6.3.13", "chai": "^3.3.0", "colors": "^1.1.2", "eslint": "^1.6.0", "grunt": "^0.4.5", - "grunt-babel": "^5.0.3", + "grunt-babel": "^6.0.0", "grunt-clean": "^0.4.0", "grunt-cli": "^0.1.13", "grunt-contrib-clean": "^0.6.0", @@ -47,7 +47,7 @@ "grunt-mocha-istanbul": "^3.0.1", "grunt-mocha-test": "^0.12.7", "grunt-webpack": "^1.0.11", - "istanbul": "^0.3.22", + "istanbul": "github:kpdecker/istanbul", "karma": "^0.13.11", "karma-mocha": "^0.2.0", "karma-mocha-reporter": "^1.1.1", @@ -61,5 +61,13 @@ "webpack": "^1.12.2", "webpack-dev-server": "^1.12.0" }, - "optionalDependencies": {} + "optionalDependencies": {}, + "babel": { + "sourceMaps": "inline", + "presets": [ + "es2015-mod" + ], + "auxiliaryCommentBefore": "istanbul ignore start", + "auxiliaryCommentAfter": "istanbul ignore end" + } } diff --git a/runtime.js b/runtime.js new file mode 100644 index 000000000..fd8ca6ea2 --- /dev/null +++ b/runtime.js @@ -0,0 +1,3 @@ +require('babel-core/register')({ + ignore: /\/lib\/|\/node_modules\// +}); diff --git a/test/mocha.opts b/test/mocha.opts index d03dc610f..3d148a1df 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -1,2 +1,2 @@ ---require babel/register +--require ./runtime --reporter spec From 71ba9fc3f5df157c4fafff9abd9e967bcebf218f Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 13 Mar 2016 00:22:39 -0600 Subject: [PATCH 029/356] Update module versions --- package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 6836f9bcf..30b0ba48c 100644 --- a/package.json +++ b/package.json @@ -38,10 +38,10 @@ "grunt-babel": "^6.0.0", "grunt-clean": "^0.4.0", "grunt-cli": "^0.1.13", - "grunt-contrib-clean": "^0.6.0", - "grunt-contrib-copy": "^0.8.1", - "grunt-contrib-uglify": "^0.9.2", - "grunt-contrib-watch": "^0.6.1", + "grunt-contrib-clean": "^1.0.0", + "grunt-contrib-copy": "^1.0.0", + "grunt-contrib-uglify": "^1.0.0", + "grunt-contrib-watch": "^1.0.0", "grunt-eslint": "^17.3.1", "grunt-karma": "^0.12.1", "grunt-mocha-istanbul": "^3.0.1", @@ -50,13 +50,13 @@ "istanbul": "github:kpdecker/istanbul", "karma": "^0.13.11", "karma-mocha": "^0.2.0", - "karma-mocha-reporter": "^1.1.1", - "karma-phantomjs-launcher": "^0.2.1", - "karma-sauce-launcher": "^0.2.14", + "karma-mocha-reporter": "^2.0.0", + "karma-phantomjs-launcher": "^1.0.0", + "karma-sauce-launcher": "^0.3.0", "karma-sourcemap-loader": "^0.3.6", "karma-webpack": "^1.7.0", "mocha": "^2.3.3", - "phantomjs": "^1.9.18", + "phantomjs-prebuilt": "^2.1.5", "semver": "^5.0.3", "webpack": "^1.12.2", "webpack-dev-server": "^1.12.0" From 40ad336895f1033982f2e35675dd35ceb20bfc20 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 13 Mar 2016 00:23:28 -0600 Subject: [PATCH 030/356] Safely handle empty diffs with whitespace Fixes #97 --- src/diff/base.js | 4 +++- test/diff/word.js | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/diff/base.js b/src/diff/base.js index 3296d3970..21a7eeaa3 100644 --- a/src/diff/base.js +++ b/src/diff/base.js @@ -207,7 +207,9 @@ function buildValues(diff, components, newString, oldString, useLongestToken) { // Special case handle for when one terminal is ignored. For this case we merge the // terminal into the prior string and drop the change. let lastComponent = components[componentLen - 1]; - if ((lastComponent.added || lastComponent.removed) && diff.equals('', lastComponent.value)) { + if (componentLen > 1 + && (lastComponent.added || lastComponent.removed) + && diff.equals('', lastComponent.value)) { components[componentLen - 2].value += lastComponent.value; components.pop(); } diff --git a/test/diff/word.js b/test/diff/word.js index ebac87cca..1df2fd767 100644 --- a/test/diff/word.js +++ b/test/diff/word.js @@ -90,6 +90,14 @@ describe('WordDiff', function() { const diffResult = diffWords('New Value', 'New ValueMoreData', {ignoreWhitespace: false}); expect(convertChangesToXML(diffResult)).to.equal('New Value ValueMoreData'); }); + + it('should diff with only whitespace', function() { + let diffResult = diffWords('', ' '); + expect(convertChangesToXML(diffResult)).to.equal(' '); + + diffResult = diffWords(' ', ''); + expect(convertChangesToXML(diffResult)).to.equal(' '); + }); }); describe('#diffWords - async', function() { From 23163b2f6742d281a3e42530dca7150c934f0a16 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 13 Mar 2016 00:25:01 -0600 Subject: [PATCH 031/356] Add toJSON support in diffJson Fixes #102 --- src/diff/json.js | 9 ++++++++- test/diff/json.js | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/diff/json.js b/src/diff/json.js index 72c046a80..26cb22faf 100644 --- a/src/diff/json.js +++ b/src/diff/json.js @@ -45,7 +45,14 @@ export function canonicalize(obj, stack, replacementStack) { } stack.pop(); replacementStack.pop(); - } else if (typeof obj === 'object' && obj !== null) { + return canonicalizedObj; + } + + if (obj && obj.toJSON) { + obj = obj.toJSON(); + } + + if (typeof obj === 'object' && obj !== null) { stack.push(obj); canonicalizedObj = {}; replacementStack.push(canonicalizedObj); diff --git a/test/diff/json.js b/test/diff/json.js index 433d78d4c..f8e06fdfb 100644 --- a/test/diff/json.js +++ b/test/diff/json.js @@ -37,6 +37,20 @@ describe('diff/json', function() { ]); }); + it('should accept dates', function() { + expect(diffJson( + {a: new Date(123), b: new Date(456), c: new Date(789)}, + {a: new Date(124), b: new Date(456)} + )).to.eql([ + { count: 1, value: '{\n' }, + { count: 1, value: ' "a": "1970-01-01T00:00:00.123Z",\n', added: undefined, removed: true }, + { count: 1, value: ' "a": "1970-01-01T00:00:00.124Z",\n', added: true, removed: undefined }, + { count: 1, value: ' "b": "1970-01-01T00:00:00.456Z",\n' }, + { count: 1, value: ' "c": "1970-01-01T00:00:00.789Z"\n', added: undefined, removed: true }, + { count: 1, value: '}' } + ]); + }); + it('should accept already stringified JSON', function() { expect(diffJson( JSON.stringify({a: 123, b: 456, c: 789}, undefined, ' '), From 1d7eef041ad8c38e4ce8791e3c268aec76111848 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 13 Mar 2016 00:29:36 -0600 Subject: [PATCH 032/356] Add test coverage for json diff missing values --- test/diff/json.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/diff/json.js b/test/diff/json.js index f8e06fdfb..395fa70ac 100644 --- a/test/diff/json.js +++ b/test/diff/json.js @@ -51,6 +51,23 @@ describe('diff/json', function() { ]); }); + it('should accept undefined keys', function() { + expect(diffJson( + {a: 123, b: 456, c: null}, + {a: 123, b: 456} + )).to.eql([ + { count: 3, value: '{\n "a": 123,\n "b": 456,\n' }, + { count: 1, value: ' "c": null\n', added: undefined, removed: true }, + { count: 1, value: '}' } + ]); + expect(diffJson( + {a: 123, b: 456, c: undefined}, + {a: 123, b: 456} + )).to.eql([ + { count: 4, value: '{\n "a": 123,\n "b": 456\n}' } + ]); + }); + it('should accept already stringified JSON', function() { expect(diffJson( JSON.stringify({a: 123, b: 456, c: 789}, undefined, ' '), From 2edfe1999293760c0e53eb141ad2ee959dff393a Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 13 Mar 2016 00:33:53 -0600 Subject: [PATCH 033/356] Drop node 0.10 from travis tests --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9731b6e43..505b9e6d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,6 @@ script: grunt travis matrix: include: - - node_js: "0.10" - env: KARMA=false - node_js: "node" env: KARMA= - node_js: "iojs" From f54173b59310923594adef8869ab382fca968523 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 13 Mar 2016 00:35:31 -0600 Subject: [PATCH 034/356] Drop iojs from travis tests --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 505b9e6d1..243c65904 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,6 @@ matrix: include: - node_js: "node" env: KARMA= - - node_js: "iojs" - env: KARMA=false cache: directories: From ef1ba9c856a641cc4c701c8ca01bfeda8cbd5bce Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 13 Mar 2016 00:38:46 -0600 Subject: [PATCH 035/356] Fix babel config for karma --- karma.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/karma.conf.js b/karma.conf.js index ba470c735..d1a75b6b1 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -46,7 +46,7 @@ module.exports = function(config) { { test: /\.jsx?$/, exclude: /node_modules/, - loader: 'babel-loader?loose=es6.modules' + loader: 'babel-loader' } ] } From e20b706630b25cf8bda086e6ce617b20ff8569c6 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 13 Mar 2016 00:45:44 -0600 Subject: [PATCH 036/356] Update release notes --- release-notes.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/release-notes.md b/release-notes.md index 9c075e50b..3172175cd 100644 --- a/release-notes.md +++ b/release-notes.md @@ -2,7 +2,14 @@ ## Development -[Commits](https://github.com/kpdecker/jsdiff/compare/v2.2.1...master) +[Commits](https://github.com/kpdecker/jsdiff/compare/v2.2.2...master) + +## v2.2.2 - March 13th, 2016 +- [#102](https://github.com/kpdecker/jsdiff/issues/102) - diffJson with dates, returns empty curly braces ([@dr-dimitru](https://api.github.com/users/dr-dimitru)) +- [#97](https://github.com/kpdecker/jsdiff/issues/97) - Whitespaces & diffWords ([@faiwer](https://api.github.com/users/faiwer)) +- [#92](https://github.com/kpdecker/jsdiff/pull/92) - Fixes typo in the readme ([@bg451](https://api.github.com/users/bg451)) + +[Commits](https://github.com/kpdecker/jsdiff/compare/v2.2.1...v2.2.2) ## v2.2.1 - November 12th, 2015 - [#89](https://github.com/kpdecker/jsdiff/pull/89) - add in display selector to readme ([@FranDias](https://api.github.com/users/FranDias)) From 215195fabd356a11aa840d289b193bb44b3b9f44 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 13 Mar 2016 00:45:58 -0600 Subject: [PATCH 037/356] v2.2.2 --- components/bower.json | 2 +- components/component.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/bower.json b/components/bower.json index 57413fb38..efdfba2c2 100644 --- a/components/bower.json +++ b/components/bower.json @@ -1,6 +1,6 @@ { "name": "jsdiff", - "version": "2.2.1", + "version": "2.2.2", "main": [ "diff.js" ], diff --git a/components/component.json b/components/component.json index dec6bee1d..ce9dd4e01 100644 --- a/components/component.json +++ b/components/component.json @@ -6,7 +6,7 @@ "diff", "text" ], - "version": "2.2.1", + "version": "2.2.2", "scripts": [ "diff.js" ], "main": "diff.js", "license": "BSD" diff --git a/package.json b/package.json index 30b0ba48c..3194fcd07 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "diff", - "version": "2.2.1", + "version": "2.2.2", "description": "A javascript text diff implementation.", "keywords": [ "diff", From 9795c6b46dd985d9573785d1fc5e520659417704 Mon Sep 17 00:00:00 2001 From: vmazare Date: Thu, 5 May 2016 09:57:56 -0700 Subject: [PATCH 038/356] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d2df2eaf3..2e769803e 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ or This method will iterate over the contents of the patch and apply to data provided through callbacks. The general flow for each patch index is: - `options.loadFile(index, callback)` is called. The caller should then load the contents of the file and then pass that to the `callback(err, data)` callback. Passing an `err` will terminate further patch execution. - - `options.patched(index, content)` is called once the patch has been applied. `content` will be the return value frmo `applyPatch`. + - `options.patched(index, content)` is called once the patch has been applied. `content` will be the return value from `applyPatch`. Once all patches have been applied or an error occurs, the `options.complete(err)` callback is made. From dc06c52892cf63683efb815132529f0a92960922 Mon Sep 17 00:00:00 2001 From: Christophe Vidal Date: Sat, 28 May 2016 14:52:19 +0700 Subject: [PATCH 039/356] Fixed grammar in README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2e769803e..39842cc22 100644 --- a/README.md +++ b/README.md @@ -70,10 +70,10 @@ or Just like JsDiff.createTwoFilesPatch, but with oldFileName being equal to newFileName. - + * `JsDiff.structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options)` - returns an object with an array of hunk objects. - This method is similar to createTwoFilesPatch, but returns a data structure + This method is similar to createTwoFilesPatch, but returns a data structure suitable for further processing. Parameters are the same as createTwoFilesPatch. The data structure returned may look like this: ```js @@ -115,7 +115,7 @@ or All methods above which accept the optional `callback` method will run in sync mode when that parameter is omitted and in async mode when supplied. This allows for larger diffs without blocking the event loop. This may be passed either directly as the final parameter or as the `callback` field in the `options` object. ### Change Objects -Many of the methods above return change objects. These objects are consist of the following fields: +Many of the methods above return change objects. These objects consist of the following fields: * `value`: Text content * `added`: True if the value was inserted into the new string From 78b8857c155b2f145d368b92ed6b5b869f729c50 Mon Sep 17 00:00:00 2001 From: abnbgist Date: Mon, 30 May 2016 00:37:18 -0400 Subject: [PATCH 040/356] Make more usable with long strings. --- examples/web_example.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/web_example.html b/examples/web_example.html index 7f2cb6365..7a5f52e91 100644 --- a/examples/web_example.html +++ b/examples/web_example.html @@ -17,4 +17,7 @@ .createTextNode(part.value)); display.appendChild(span); }); - \ No newline at end of file + + From d20f367576161b1a43e9c0d6d31542cdb3731fc8 Mon Sep 17 00:00:00 2001 From: Charlie Ozinga Date: Tue, 31 May 2016 12:25:47 -0600 Subject: [PATCH 041/356] Add a fix for applying 0-length destination patches --- src/patch/apply.js | 1 + test/patch/apply.js | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/patch/apply.js b/src/patch/apply.js index fda26ece3..864d52da1 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -81,6 +81,7 @@ export function applyPatch(source, uniDiff, options = {}) { for (let i = 0; i < hunks.length; i++) { let hunk = hunks[i], toPos = hunk.offset + hunk.newStart - 1; + if (hunk.newLines == 0) { toPos++; } for (let j = 0; j < hunk.lines.length; j++) { let line = hunk.lines[j], diff --git a/test/patch/apply.js b/test/patch/apply.js index dbf24277f..3e278f61d 100644 --- a/test/patch/apply.js +++ b/test/patch/apply.js @@ -416,6 +416,23 @@ describe('patch/apply', function() { + 'line5\n'); }); + it('should erase a file', function() { + expect(applyPatch( + 'line1\n' + + 'line2\n' + + 'line3\n' + + 'line4\n', + + '--- test\theader1\n' + + '+++ test\theader2\n' + + '@@ -1,4 +0,0 @@\n' + + '-line1\n' + + '-line2\n' + + '-line3\n' + + '-line4\n')) + .to.equal(''); + }); + it('should allow custom line comparison', function() { expect(applyPatch( 'line2\n' From 06eaeee2711fcbda31e6c249a14ad75d7ba1cd5f Mon Sep 17 00:00:00 2001 From: kpdecker Date: Tue, 31 May 2016 15:06:24 -0500 Subject: [PATCH 042/356] Update release notes --- release-notes.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/release-notes.md b/release-notes.md index 3172175cd..9dfa3c0b5 100644 --- a/release-notes.md +++ b/release-notes.md @@ -2,7 +2,14 @@ ## Development -[Commits](https://github.com/kpdecker/jsdiff/compare/v2.2.2...master) +[Commits](https://github.com/kpdecker/jsdiff/compare/v2.2.3...master) + +## v2.2.3 - May 31st, 2016 +- [#118](https://github.com/kpdecker/jsdiff/pull/118) - Add a fix for applying 0-length destination patches ([@chaaz](https://api.github.com/users/chaaz)) +- [#115](https://github.com/kpdecker/jsdiff/pull/115) - Fixed grammar in README ([@krizalys](https://api.github.com/users/krizalys)) +- [#113](https://github.com/kpdecker/jsdiff/pull/113) - fix typo ([@vmazare](https://api.github.com/users/vmazare)) + +[Commits](https://github.com/kpdecker/jsdiff/compare/v2.2.2...v2.2.3) ## v2.2.2 - March 13th, 2016 - [#102](https://github.com/kpdecker/jsdiff/issues/102) - diffJson with dates, returns empty curly braces ([@dr-dimitru](https://api.github.com/users/dr-dimitru)) From ec007c364e88c37ccc6b3f94a4cfe163d8389b85 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Tue, 31 May 2016 15:06:36 -0500 Subject: [PATCH 043/356] v2.2.3 --- components/bower.json | 2 +- components/component.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/bower.json b/components/bower.json index efdfba2c2..7a8404b34 100644 --- a/components/bower.json +++ b/components/bower.json @@ -1,6 +1,6 @@ { "name": "jsdiff", - "version": "2.2.2", + "version": "2.2.3", "main": [ "diff.js" ], diff --git a/components/component.json b/components/component.json index ce9dd4e01..e90ac11db 100644 --- a/components/component.json +++ b/components/component.json @@ -6,7 +6,7 @@ "diff", "text" ], - "version": "2.2.2", + "version": "2.2.3", "scripts": [ "diff.js" ], "main": "diff.js", "license": "BSD" diff --git a/package.json b/package.json index 3194fcd07..f0466532e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "diff", - "version": "2.2.2", + "version": "2.2.3", "description": "A javascript text diff implementation.", "keywords": [ "diff", From 6c829046e2a41ab363a3178d2c425dcc1a6840c2 Mon Sep 17 00:00:00 2001 From: wifiextender Date: Thu, 2 Jun 2016 02:06:52 +0200 Subject: [PATCH 044/356] Do single reflow --- README.md | 19 ++++++++++++------- examples/web_example.html | 18 ++++++++++++------ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 39842cc22..dab7189dd 100644 --- a/README.md +++ b/README.md @@ -156,23 +156,28 @@ Basic example in a web page

 
 
 ```
 
diff --git a/examples/web_example.html b/examples/web_example.html
index 7a5f52e91..c4c1ed426 100644
--- a/examples/web_example.html
+++ b/examples/web_example.html
@@ -1,22 +1,28 @@