From f5d3bd15620fa96001b225752f6a5bf75f05a5bb Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Fri, 10 Jul 2015 20:07:25 +0800 Subject: [PATCH 001/232] Use svg instead of png to get better image quality --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b867e19a..7ff7fffc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # jsdiff -[![Build Status](https://secure.travis-ci.org/kpdecker/jsdiff.png)](http://travis-ci.org/kpdecker/jsdiff) +[![Build Status](https://secure.travis-ci.org/kpdecker/jsdiff.svg)](http://travis-ci.org/kpdecker/jsdiff) A javascript text differencing implementation. From b257c312567da10726cf92ec3510b206ca831a07 Mon Sep 17 00:00:00 2001 From: Quest Date: Wed, 22 Jul 2015 18:19:12 +0200 Subject: [PATCH 002/232] Allow retreiving the patch data as a list of hunk objects --- diff.js | 101 ++++++++++++++++++++++++---------------- test/createPatch.js | 76 +++++++++++++++++++++++++++++- test/structuredPatch.js | 26 +++++++++++ 3 files changed, 162 insertions(+), 41 deletions(-) create mode 100644 test/structuredPatch.js diff --git a/diff.js b/diff.js index 421854a1..1c9e5c5d 100644 --- a/diff.js +++ b/diff.js @@ -398,39 +398,22 @@ callback ); }, - - createTwoFilesPatch: function(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader) { - var ret = []; - - if (oldFileName == newFileName) { - ret.push('Index: ' + oldFileName); + + structuredPatch: function(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) { + if(!options) { + options = { context: 4 }; } - ret.push('==================================================================='); - ret.push('--- ' + oldFileName + (typeof oldHeader === 'undefined' ? '' : '\t' + oldHeader)); - ret.push('+++ ' + newFileName + (typeof newHeader === 'undefined' ? '' : '\t' + newHeader)); - + var diff = PatchDiff.diff(oldStr, newStr); diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier - - // Formats a given set of lines for printing as context lines in a patch + function contextLines(lines) { return map(lines, function(entry) { return ' ' + entry; }); } - // Outputs the no newline at end of file warning if needed - function eofNL(curRange, i, current) { - var last = diff[diff.length - 2], - isLast = i === diff.length - 2, - isLastOfType = i === diff.length - 3 && current.added !== last.added; - - // Figure out if this is the last line for the given file and missing NL - if (!(/\n$/.test(current.value)) && (isLast || isLastOfType)) { - curRange.push('\\ No newline at end of file'); - } - } - + var hunks = []; var oldRangeStart = 0, newRangeStart = 0, curRange = [], - oldLine = 1, newLine = 1; + oldLine = 1, newLine = 1; for (var i = 0; i < diff.length; i++) { var current = diff[i], lines = current.lines || current.value.replace(/\n$/, '').split('\n'); @@ -444,7 +427,7 @@ newRangeStart = newLine; if (prev) { - curRange = contextLines(prev.lines.slice(-4)); + curRange = options.context > 0 ? contextLines(prev.lines.slice(-options.context)) : []; oldRangeStart -= curRange.length; newRangeStart -= curRange.length; } @@ -454,7 +437,6 @@ curRange.push.apply(curRange, map(lines, function(entry) { return (current.added ? '+' : '-') + entry; })); - eofNL(curRange, i, current); // Track the updated file position if (current.added) { @@ -466,21 +448,34 @@ // Identical context lines. Track line changes if (oldRangeStart) { // Close out any changes that have been output (or join overlapping) - if (lines.length <= 8 && i < diff.length - 2) { + if (lines.length <= options.context * 2 && i < diff.length - 2) { // Overlapping curRange.push.apply(curRange, contextLines(lines)); } else { // end the range and output - var contextSize = Math.min(lines.length, 4); - ret.push( - '@@ -' + oldRangeStart + ',' + (oldLine - oldRangeStart + contextSize) - + ' +' + newRangeStart + ',' + (newLine - newRangeStart + contextSize) - + ' @@'); - ret.push.apply(ret, curRange); - ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); - if (lines.length <= 4) { - eofNL(ret, i, current); + var contextSize = Math.min(lines.length, options.context); + var hunklines = []; + hunklines.push.apply(hunklines, curRange); + hunklines.push.apply(hunklines, contextLines(lines.slice(0, contextSize))); + + var hunk = { + oldStart: oldRangeStart, + oldLines: (oldLine - oldRangeStart + contextSize), + newStart: newRangeStart, + newLines: (newLine - newRangeStart + contextSize), + lines: hunklines + } + if(i >= diff.length - 2 && lines.length <= options.context) { + // EOF is inside this hunk + var oldEOFNewline = /\n$/.test(oldStr); + var newEOFNewline = /\n$/.test(newStr); + if(lines.length == 0 && !oldEOFNewline) { + hunklines.splice(hunk.oldLines, 0, '\\ No newline at end of file') + } else if (!oldEOFNewline || !newEOFNewline) { + hunklines.push('\\ No newline at end of file') + } } + hunks.push(hunk); oldRangeStart = 0; newRangeStart = 0; @@ -491,12 +486,40 @@ newLine += lines.length; } } + + return { + oldFileName: oldFileName, newFileName: newFileName, + oldHeader: oldHeader, newHeader: newHeader, + hunks: hunks + }; + }, + createTwoFilesPatch: function(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) { + var diff = JsDiff.structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options); + + var ret = []; + if (oldFileName == newFileName) { + ret.push('Index: ' + oldFileName); + } + ret.push('==================================================================='); + ret.push('--- ' + diff.oldFileName + (typeof diff.oldHeader === 'undefined' ? '' : '\t' + diff.oldHeader)); + ret.push('+++ ' + diff.newFileName + (typeof diff.newHeader === 'undefined' ? '' : '\t' + diff.newHeader)); + + for(var i = 0; i < diff.hunks.length; i++) { + var hunk = diff.hunks[i]; + ret.push( + '@@ -' + hunk.oldStart + ',' + hunk.oldLines + + ' +' + hunk.newStart + ',' + hunk.newLines + + ' @@' + ); + ret.push.apply(ret, hunk.lines); + } + return ret.join('\n') + '\n'; }, - createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { - return JsDiff.createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader); + createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader, options) { + return JsDiff.createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader, options); }, applyPatch: function(oldStr, uniDiff) { diff --git a/test/createPatch.js b/test/createPatch.js index 62665acf..fea4aa83 100644 --- a/test/createPatch.js +++ b/test/createPatch.js @@ -56,7 +56,7 @@ describe('#createPatch', function() { + '+line5\n'); }); - it('should output no newline at end of file message', function() { + it('should output "no newline" at end of file message on new missing nl', function() { diff.createPatch('test', 'line1\nline2\nline3\nline4\n', 'line1\nline2\nline3\nline4', 'header1', 'header2').should.equal( 'Index: test\n' + '===================================================================\n' @@ -69,7 +69,9 @@ describe('#createPatch', function() { + '-line4\n' + '+line4\n' + '\\ No newline at end of file\n'); + }); + it('should output "no newline" at end of file message on old missing nl', function() { diff.createPatch('test', 'line1\nline2\nline3\nline4', 'line1\nline2\nline3\nline4\n', 'header1', 'header2').should.equal( 'Index: test\n' + '===================================================================\n' @@ -82,7 +84,9 @@ describe('#createPatch', function() { + '-line4\n' + '\\ No newline at end of file\n' + '+line4\n'); + }); + it('should output "no newline" at end of file message on context missing nl', function() { diff.createPatch('test', 'line11\nline2\nline3\nline4', 'line1\nline2\nline3\nline4', 'header1', 'header2').should.equal( 'Index: test\n' + '===================================================================\n' @@ -95,7 +99,9 @@ describe('#createPatch', function() { + ' line3\n' + ' line4\n' + '\\ No newline at end of file\n'); + }); + it('should not output no newline at end of file message when eof outside hunk', function() { diff.createPatch('test', 'line11\nline2\nline3\nline4\nline4\nline4\nline4', 'line1\nline2\nline3\nline4\nline4\nline4\nline4', 'header1', 'header2').should.equal( 'Index: test\n' + '===================================================================\n' @@ -422,7 +428,7 @@ describe('#createPatch', function() { + 'context\n' + 'context'; - it('should generate a patch', function() { + it('should generate a patch with default context size', function() { var expectedResult = 'Index: testFileName\n' + '===================================================================\n' @@ -475,6 +481,72 @@ describe('#createPatch', function() { var diffResult = diff.createPatch('testFileName', oldFile, newFile, 'Old Header', 'New Header'); diffResult.should.equal(expectedResult); }); + + it('should generatea a patch with context size 0', function() { + var expectedResult = + 'Index: testFileName\n' + + '===================================================================\n' + + '--- testFileName\tOld Header\n' + + '+++ testFileName\tNew Header\n' + + '@@ -1,1 +1,2 @@\n' + + '-value\n' + + '+new value\n' + + '+new value 2\n' + + '@@ -11,1 +12,0 @@\n' + + '-remove value\n' + + '@@ -21,1 +21,0 @@\n' + + '-remove value\n' + + '@@ -30,0 +29,1 @@\n' + + '+add value\n' + + '@@ -34,1 +34,2 @@\n' + + '-value\n' + + '+new value\n' + + '+new value 2\n'; + var diffResult = diff.createPatch('testFileName', oldFile, newFile, 'Old Header', 'New Header', { context: 0 }); + diffResult.should.equal(expectedResult); + }); + + it('should generate a patch with context size 2', function() { + var expectedResult = + 'Index: testFileName\n' + + '===================================================================\n' + + '--- testFileName\tOld Header\n' + + '+++ testFileName\tNew Header\n' + + '@@ -1,3 +1,4 @@\n' + + '-value\n' + + '+new value\n' + + '+new value 2\n' + + ' context\n' + + ' context\n' + + '@@ -9,5 +10,4 @@\n' + + ' context\n' + + ' context\n' + + '-remove value\n' + + ' context\n' + + ' context\n' + + '@@ -19,5 +19,4 @@\n' + + ' context\n' + + ' context\n' + + '-remove value\n' + + ' context\n' + + ' context\n' + + '@@ -28,9 +27,11 @@\n' + + ' context\n' + + ' context\n' + + '+add value\n' + + ' context\n' + + ' context\n' + + ' context\n' + + ' context\n' + + '-value\n' + + '+new value\n' + + '+new value 2\n' + + ' context\n' + + ' context\n' + + '\\ No newline at end of file\n'; + var diffResult = diff.createPatch('testFileName', oldFile, newFile, 'Old Header', 'New Header', { context: 2 }); + diffResult.should.equal(expectedResult); + }); it('should output headers only for identical files', function() { var expectedResult = diff --git a/test/structuredPatch.js b/test/structuredPatch.js new file mode 100644 index 00000000..08201b81 --- /dev/null +++ b/test/structuredPatch.js @@ -0,0 +1,26 @@ +const VERBOSE = false; + +var diff = require('../diff'); + +function log() { + VERBOSE && console.log.apply(console, arguments); +} + +describe('#structuredPatch', function() { + it('should handle files with the last line changed', function() { + var res = diff.structuredPatch( + 'oldfile', 'newfile', + 'line2\nline3\nline5\n', 'line2\nline3\nline4\nline5\n', + 'header1', 'header2' + ); + res.should.eql({ + oldFileName: 'oldfile', newFileName: 'newfile', + oldHeader: 'header1', newHeader: 'header2', + hunks: [{ + oldStart: 1, oldLines: 3, newStart: 1, newLines: 4, + lines: [' line2', ' line3', '+line4', ' line5'], + oldEOFNewline: true, newEOFNewline: true, + }] + }); + }); +}); From bc11bccc0fcebefc2655081928407fb548804d3b Mon Sep 17 00:00:00 2001 From: Quest Date: Wed, 22 Jul 2015 22:46:55 +0200 Subject: [PATCH 003/232] Test on structured patch method updated --- test/structuredPatch.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/structuredPatch.js b/test/structuredPatch.js index 08201b81..d88077c5 100644 --- a/test/structuredPatch.js +++ b/test/structuredPatch.js @@ -10,16 +10,15 @@ describe('#structuredPatch', function() { it('should handle files with the last line changed', function() { var res = diff.structuredPatch( 'oldfile', 'newfile', - 'line2\nline3\nline5\n', 'line2\nline3\nline4\nline5\n', + 'line2\nline3\nline4\n', 'line2\nline3\nline5', 'header1', 'header2' ); res.should.eql({ oldFileName: 'oldfile', newFileName: 'newfile', oldHeader: 'header1', newHeader: 'header2', hunks: [{ - oldStart: 1, oldLines: 3, newStart: 1, newLines: 4, - lines: [' line2', ' line3', '+line4', ' line5'], - oldEOFNewline: true, newEOFNewline: true, + oldStart: 1, oldLines: 3, newStart: 1, newLines: 3, + lines: [' line2', ' line3', '-line4', '+line5', '\\ No newline at end of file'], }] }); }); From 8209a6bf8becad36a010a1575b6c0e4df9f27636 Mon Sep 17 00:00:00 2001 From: Quest Date: Fri, 31 Jul 2015 01:32:20 +0200 Subject: [PATCH 004/232] As per @kpdecker comments to PR #62 --- diff.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/diff.js b/diff.js index 1c9e5c5d..66f4a02d 100644 --- a/diff.js +++ b/diff.js @@ -400,7 +400,7 @@ }, structuredPatch: function(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) { - if(!options) { + if (!options) { options = { context: 4 }; } @@ -413,7 +413,7 @@ var hunks = []; var oldRangeStart = 0, newRangeStart = 0, curRange = [], - oldLine = 1, newLine = 1; + oldLine = 1, newLine = 1; for (var i = 0; i < diff.length; i++) { var current = diff[i], lines = current.lines || current.value.replace(/\n$/, '').split('\n'); @@ -454,25 +454,24 @@ } else { // end the range and output var contextSize = Math.min(lines.length, options.context); - var hunklines = []; - hunklines.push.apply(hunklines, curRange); - hunklines.push.apply(hunklines, contextLines(lines.slice(0, contextSize))); + curRange.push.apply(curRange, contextLines(lines.slice(0, contextSize))); var hunk = { oldStart: oldRangeStart, oldLines: (oldLine - oldRangeStart + contextSize), newStart: newRangeStart, newLines: (newLine - newRangeStart + contextSize), - lines: hunklines + lines: curRange } - if(i >= diff.length - 2 && lines.length <= options.context) { + if (i >= diff.length - 2 && lines.length <= options.context) { // EOF is inside this hunk var oldEOFNewline = /\n$/.test(oldStr); var newEOFNewline = /\n$/.test(newStr); - if(lines.length == 0 && !oldEOFNewline) { - hunklines.splice(hunk.oldLines, 0, '\\ No newline at end of file') + if (lines.length == 0 && !oldEOFNewline) { + // special case: old has no eol and no trailing context; no-nl can end up before adds + curRange.splice(hunk.oldLines, 0, '\\ No newline at end of file') } else if (!oldEOFNewline || !newEOFNewline) { - hunklines.push('\\ No newline at end of file') + curRange.push('\\ No newline at end of file') } } hunks.push(hunk); @@ -505,7 +504,7 @@ ret.push('--- ' + diff.oldFileName + (typeof diff.oldHeader === 'undefined' ? '' : '\t' + diff.oldHeader)); ret.push('+++ ' + diff.newFileName + (typeof diff.newHeader === 'undefined' ? '' : '\t' + diff.newHeader)); - for(var i = 0; i < diff.hunks.length; i++) { + for (var i = 0; i < diff.hunks.length; i++) { var hunk = diff.hunks[i]; ret.push( '@@ -' + hunk.oldStart + ',' + hunk.oldLines From cf440256a4548722319838be7b7bee44434e77aa Mon Sep 17 00:00:00 2001 From: Quest Date: Fri, 31 Jul 2015 16:25:00 +0200 Subject: [PATCH 005/232] Documentationn for structuredPatch --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 7ff7fffc..6f415f8c 100644 --- a/README.md +++ b/README.md @@ -62,11 +62,29 @@ or * `newStr` : New string value * `oldHeader` : Additional information to include in the old file header * `newHeader` : Additional information to include in thew 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. 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 + suitable for further processing. Parameters are the same as createTwoFilesPatch. The data structure returned may look like this: + + ```js + { + oldFileName: 'oldfile', newFileName: 'newfile', + oldHeader: 'header1', newHeader: 'header2', + hunks: [{ + oldStart: 1, oldLines: 3, newStart: 1, newLines: 3, + lines: [' line2', ' line3', '-line4', '+line5', '\\ No newline at end of file'], + }] + } + ``` + * `JsDiff.applyPatch(oldStr, diffStr)` - applies a unified diff patch. Return a string containing new version of provided data. From b49299afd6f59e4b07369d07dd53b7f60a7f3c8f Mon Sep 17 00:00:00 2001 From: Quest Date: Fri, 31 Jul 2015 16:26:54 +0200 Subject: [PATCH 006/232] Documentationn for structuredPatch --- README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 6f415f8c..8308de6a 100644 --- a/README.md +++ b/README.md @@ -69,20 +69,20 @@ 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 - suitable for further processing. Parameters are the same as createTwoFilesPatch. The data structure returned may look like this: - - ```js - { - oldFileName: 'oldfile', newFileName: 'newfile', - oldHeader: 'header1', newHeader: 'header2', - hunks: [{ - oldStart: 1, oldLines: 3, newStart: 1, newLines: 3, - lines: [' line2', ' line3', '-line4', '+line5', '\\ No newline at end of file'], - }] - } +* `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 + suitable for further processing. Parameters are the same as createTwoFilesPatch. The data structure returned may look like this: + +```js +{ + oldFileName: 'oldfile', newFileName: 'newfile', + oldHeader: 'header1', newHeader: 'header2', + hunks: [{ + oldStart: 1, oldLines: 3, newStart: 1, newLines: 3, + lines: [' line2', ' line3', '-line4', '+line5', '\\ No newline at end of file'], + }] +} ``` * `JsDiff.applyPatch(oldStr, diffStr)` - applies a unified diff patch. From 30189fbe094fd0eca9e89539cc816bf9e74fa3f0 Mon Sep 17 00:00:00 2001 From: Quest Date: Fri, 31 Jul 2015 16:30:03 +0200 Subject: [PATCH 007/232] Documentationn for structuredPatch --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8308de6a..65ea13f2 100644 --- a/README.md +++ b/README.md @@ -74,15 +74,15 @@ or 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 -{ - oldFileName: 'oldfile', newFileName: 'newfile', - oldHeader: 'header1', newHeader: 'header2', - hunks: [{ - oldStart: 1, oldLines: 3, newStart: 1, newLines: 3, - lines: [' line2', ' line3', '-line4', '+line5', '\\ No newline at end of file'], - }] -} + ```js + { + oldFileName: 'oldfile', newFileName: 'newfile', + oldHeader: 'header1', newHeader: 'header2', + hunks: [{ + oldStart: 1, oldLines: 3, newStart: 1, newLines: 3, + lines: [' line2', ' line3', '-line4', '+line5', '\\ No newline at end of file'], + }] + } ``` * `JsDiff.applyPatch(oldStr, diffStr)` - applies a unified diff patch. From 091aeef6fc5fc8ac1247758ffb608dde4090f6a1 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Tue, 4 Aug 2015 17:05:30 -0500 Subject: [PATCH 008/232] Add eslint style checking to build --- .eslintrc | 178 ++++++++++++++++++++++++++++++++++++++++ diff.js | 38 ++++----- package.json | 3 +- test/.eslintrc | 14 ++++ test/createPatch.js | 10 +-- test/structuredPatch.js | 16 ++-- 6 files changed, 223 insertions(+), 36 deletions(-) create mode 100644 .eslintrc create mode 100644 test/.eslintrc diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..15ecb91b --- /dev/null +++ b/.eslintrc @@ -0,0 +1,178 @@ +{ + "env": { + "browser": true + }, + "rules": { + // Possible Errors // + //-----------------// + + "comma-dangle": [2, "never"], + "no-cond-assign": [2, "except-parens"], + + // Allow for debugging + "no-console": 1, + + "no-constant-condition": 2, + "no-control-regex": 2, + + // Allow for debugging + "no-debugger": 1, + + "no-dupe-args": 2, + "no-dupe-keys": 2, + "no-duplicate-case": 2, + "no-empty": 2, + "no-empty-character-class": 2, + "no-ex-assign": 2, + "no-extra-boolean-cast": 2, + "no-extra-parens": [2, "functions"], + "no-extra-semi": 2, + "no-func-assign": 2, + + // Stylistic... might consider disallowing in the future + "no-inner-declarations": 0, + + "no-invalid-regexp": 2, + "no-irregular-whitespace": 2, + "no-negated-in-lhs": 2, + "no-obj-calls": 2, + "no-regex-spaces": 2, + "no-sparse-arrays": 0, + + // Optimizer and coverage will handle/highlight this and can be useful for debugging + "no-unreachable": 1, + + "use-isnan": 2, + "valid-jsdoc": 0, + "valid-typeof": 2, + + + // Best Practices // + //----------------// + "block-scoped-var": 0, + "complexity": 0, + "consistent-return": 0, + "curly": 2, + "default-case": 1, + "dot-notation": [2, {"allowKeywords": false}], + "eqeqeq": 0, + "guard-for-in": 1, + "no-alert": 2, + "no-caller": 2, + "no-div-regex": 1, + "no-else-return": 0, + "no-empty-label": 2, + "no-eq-null": 0, + "no-eval": 2, + "no-extend-native": 2, + "no-extra-bind": 2, + "no-fallthrough": 2, + "no-floating-decimal": 2, + "no-implied-eval": 2, + "no-iterator": 2, + "no-labels": 2, + "no-lone-blocks": 2, + "no-loop-func": 0, + "no-multi-spaces": 2, + "no-multi-str": 1, + "no-native-reassign": 2, + "no-new": 2, + "no-new-func": 2, + "no-new-wrappers": 2, + "no-octal": 2, + "no-octal-escape": 2, + "no-param-reassign": 0, + "no-process-env": 2, + "no-proto": 2, + "no-redeclare": 2, + "no-return-assign": 2, + "no-script-url": 2, + "no-self-compare": 2, + "no-sequences": 2, + "no-throw-literal": 2, + "no-unused-expressions": 2, + "no-void": 0, + "no-warning-comments": 1, + "no-with": 2, + "radix": 2, + "vars-on-top": 0, + "wrap-iife": 2, + "yoda": 0, + + + // Strict // + //--------// + "strict": 0, + + + // Variables // + //-----------// + "no-catch-shadow": 2, + "no-delete-var": 2, + "no-label-var": 2, + "no-shadow": 0, + "no-shadow-restricted-names": 0, + "no-undef": 2, + "no-undef-init": 2, + "no-undefined": 0, + "no-unused-vars": [2, {"vars": "all", "args": "after-used"}], + "no-use-before-define": [2, "nofunc"], + + + // Node.js // + //---------// + // Others left to environment defaults + "no-mixed-requires": 0, + + + // Stylistic // + //-----------// + "indent": 0, + "brace-style": [2, "1tbs", {"allowSingleLine": true}], + "camelcase": 2, + "comma-spacing": [2, {"before": false, "after": true}], + "comma-style": [2, "last"], + "consistent-this": [1, "self"], + "eol-last": 2, + "func-names": 0, + "func-style": [2, "declaration"], + "key-spacing": [2, { + "beforeColon": false, + "afterColon": true + }], + "max-nested-callbacks": 0, + "new-cap": 2, + "new-parens": 2, + "newline-after-var": 0, + "no-array-constructor": 2, + "no-continue": 0, + "no-inline-comments": 0, + "no-lonely-if": 2, + "no-mixed-spaces-and-tabs": 2, + "no-multiple-empty-lines": 0, + "no-nested-ternary": 1, + "no-new-object": 2, + "no-spaced-func": 2, + "no-ternary": 0, + "no-trailing-spaces": 2, + "no-underscore-dangle": 0, + "one-var": 0, + "operator-assignment": 0, + "padded-blocks": 0, + "quote-props": [2, "as-needed", {"keywords": true}], + "quotes": [2, "single", "avoid-escape"], + "semi": 2, + "semi-spacing": [2, {"before": false, "after": true}], + "sort-vars": 0, + "space-after-keywords": [2, "always"], + "space-before-blocks": [2, "always"], + "space-before-function-paren": [2, {"anonymous": "never", "named": "never"}], + "space-in-brackets": 0, + "space-in-parens": [2, "never"], + "space-infix-ops": 2, + "space-return-throw-case": 2, + "space-unary-ops": 2, + "spaced-comment": [2, "always"], + "wrap-regex": 1 + } +} \ No newline at end of file diff --git a/diff.js b/diff.js index 66f4a02d..dae487df 100644 --- a/diff.js +++ b/diff.js @@ -17,7 +17,7 @@ (function(global, undefined) { var objectPrototypeToString = Object.prototype.toString; - /*istanbul ignore next*/ + /* istanbul ignore next*/ function map(arr, mapper, that) { if (Array.prototype.map) { return Array.prototype.map.call(arr, mapper, that); @@ -238,7 +238,7 @@ (function exec() { setTimeout(function() { // This should not happen, but we want to be safe. - /*istanbul ignore next */ + /* istanbul ignore next */ if (editLength > maxEditLength) { return callback(); } @@ -398,15 +398,15 @@ callback ); }, - + structuredPatch: function(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) { if (!options) { options = { context: 4 }; } - + var diff = PatchDiff.diff(oldStr, newStr); diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier - + function contextLines(lines) { return map(lines, function(entry) { return ' ' + entry; }); } @@ -456,22 +456,22 @@ var contextSize = Math.min(lines.length, options.context); curRange.push.apply(curRange, contextLines(lines.slice(0, contextSize))); - var hunk = { - oldStart: oldRangeStart, - oldLines: (oldLine - oldRangeStart + contextSize), - newStart: newRangeStart, + var hunk = { + oldStart: oldRangeStart, + oldLines: (oldLine - oldRangeStart + contextSize), + newStart: newRangeStart, newLines: (newLine - newRangeStart + contextSize), lines: curRange - } + }; if (i >= diff.length - 2 && lines.length <= options.context) { // EOF is inside this hunk - var oldEOFNewline = /\n$/.test(oldStr); - var newEOFNewline = /\n$/.test(newStr); + var oldEOFNewline = (/\n$/.test(oldStr)); + var newEOFNewline = (/\n$/.test(newStr)); if (lines.length == 0 && !oldEOFNewline) { // special case: old has no eol and no trailing context; no-nl can end up before adds - curRange.splice(hunk.oldLines, 0, '\\ No newline at end of file') + curRange.splice(hunk.oldLines, 0, '\\ No newline at end of file'); } else if (!oldEOFNewline || !newEOFNewline) { - curRange.push('\\ No newline at end of file') + curRange.push('\\ No newline at end of file'); } } hunks.push(hunk); @@ -485,7 +485,7 @@ newLine += lines.length; } } - + return { oldFileName: oldFileName, newFileName: newFileName, oldHeader: oldHeader, newHeader: newHeader, @@ -513,7 +513,7 @@ ); ret.push.apply(ret, hunk.lines); } - + return ret.join('\n') + '\n'; }, @@ -628,12 +628,12 @@ canonicalize: canonicalize }; - /*istanbul ignore next */ - /*global module */ + /* istanbul ignore next */ + /* global module */ if (typeof module !== 'undefined' && module.exports) { module.exports = JsDiff; } else if (typeof define === 'function' && define.amd) { - /*global define */ + /* global define */ define([], function() { return JsDiff; }); } else if (typeof global.JsDiff === 'undefined') { global.JsDiff = JsDiff; diff --git a/package.json b/package.json index 2bd81f89..70764eed 100644 --- a/package.json +++ b/package.json @@ -28,11 +28,12 @@ }, "main": "./diff", "scripts": { - "test": "istanbul cover node_modules/.bin/_mocha test/*.js && istanbul check-coverage --statements 100 --functions 100 --branches 100 --lines 100 coverage/coverage.json" + "test": "eslint *.js test/ && istanbul cover node_modules/.bin/_mocha test/*.js && istanbul check-coverage --statements 100 --functions 100 --branches 100 --lines 100 coverage/coverage.json" }, "dependencies": {}, "devDependencies": { "colors": "^1.1.0", + "eslint": "^1.0.0", "istanbul": "^0.3.2", "mocha": "^2.2.4", "should": "^6.0.1" diff --git a/test/.eslintrc b/test/.eslintrc new file mode 100644 index 00000000..bc43bc2e --- /dev/null +++ b/test/.eslintrc @@ -0,0 +1,14 @@ +{ + "env": { + "node": true, + "mocha": true + }, + "rules": { + // Disabling for tests, for now. + "no-unused-expressions": 0, + "no-path-concat": 0, + + "no-var": 0, + "no-console": 0 + } +} \ No newline at end of file diff --git a/test/createPatch.js b/test/createPatch.js index fea4aa83..365e7c2c 100644 --- a/test/createPatch.js +++ b/test/createPatch.js @@ -1,4 +1,4 @@ -const VERBOSE = false; +var VERBOSE = false; var diff = require('../diff'); @@ -314,11 +314,11 @@ describe('#createPatch', function() { var largeNewValue = largeTest, len = largeTest.length, count = nextRandom() % 20, - removeBound = len-(count*100), + removeBound = len - (count * 100), logData = []; for (; count > 0; count--) { var removePos = nextRandom() % removeBound, - removeLength = 1+nextRandom()%100; + removeLength = 1 + nextRandom() % 100; logData.push('(' + removePos + ', ' + removeLength + ')'); largeNewValue = largeNewValue.substring(0, removePos) + largeNewValue.substring(removePos + removeLength); @@ -481,7 +481,7 @@ describe('#createPatch', function() { var diffResult = diff.createPatch('testFileName', oldFile, newFile, 'Old Header', 'New Header'); diffResult.should.equal(expectedResult); }); - + it('should generatea a patch with context size 0', function() { var expectedResult = 'Index: testFileName\n' @@ -505,7 +505,7 @@ describe('#createPatch', function() { var diffResult = diff.createPatch('testFileName', oldFile, newFile, 'Old Header', 'New Header', { context: 0 }); diffResult.should.equal(expectedResult); }); - + it('should generate a patch with context size 2', function() { var expectedResult = 'Index: testFileName\n' diff --git a/test/structuredPatch.js b/test/structuredPatch.js index d88077c5..6d3d4ef9 100644 --- a/test/structuredPatch.js +++ b/test/structuredPatch.js @@ -1,24 +1,18 @@ -const VERBOSE = false; - var diff = require('../diff'); -function log() { - VERBOSE && console.log.apply(console, arguments); -} - describe('#structuredPatch', function() { it('should handle files with the last line changed', function() { var res = diff.structuredPatch( - 'oldfile', 'newfile', - 'line2\nline3\nline4\n', 'line2\nline3\nline5', + 'oldfile', 'newfile', + 'line2\nline3\nline4\n', 'line2\nline3\nline5', 'header1', 'header2' ); res.should.eql({ - oldFileName: 'oldfile', newFileName: 'newfile', + oldFileName: 'oldfile', newFileName: 'newfile', oldHeader: 'header1', newHeader: 'header2', - hunks: [{ + hunks: [{ oldStart: 1, oldLines: 3, newStart: 1, newLines: 3, - lines: [' line2', ' line3', '-line4', '+line5', '\\ No newline at end of file'], + lines: [' line2', ' line3', '-line4', '+line5', '\\ No newline at end of file'] }] }); }); From f01f57a1c65183e62fe6cecd6fd7f55951feac8c Mon Sep 17 00:00:00 2001 From: kpdecker Date: Tue, 4 Aug 2015 17:09:43 -0500 Subject: [PATCH 009/232] Run removeEmpty on all tokenize calls This is the most likely behavior that users will want. Should it not be desired for whatever reason, subclasses may override the removeEmpty field. Fixes #64 --- diff.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/diff.js b/diff.js index dae487df..ba1b063b 100644 --- a/diff.js +++ b/diff.js @@ -33,15 +33,6 @@ function clonePath(path) { return { newPos: path.newPos, components: path.components.slice(0) }; } - function removeEmpty(array) { - var ret = []; - for (var i = 0; i < array.length; i++) { - if (array[i]) { - ret.push(array[i]); - } - } - return ret; - } function escapeHTML(s) { var n = s; n = n.replace(/&/g, '&'); @@ -170,8 +161,8 @@ return done([{ value: newString, added: true }]); } - newString = this.tokenize(newString); - oldString = this.tokenize(oldString); + newString = this.removeEmpty(this.tokenize(newString)); + oldString = this.removeEmpty(this.tokenize(oldString)); var newLen = newString.length, oldLen = oldString.length; var editLength = 1; @@ -293,6 +284,15 @@ var reWhitespace = /\S/; return left === right || (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)); }, + removeEmpty: function(array) { + var ret = []; + for (var i = 0; i < array.length; i++) { + if (array[i]) { + ret.push(array[i]); + } + } + return ret; + }, tokenize: function(value) { return value.split(''); } @@ -303,12 +303,12 @@ var WordDiff = new Diff(true); var WordWithSpaceDiff = new Diff(); WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) { - return removeEmpty(value.split(/(\s+|\b)/)); + return value.split(/(\s+|\b)/); }; var CssDiff = new Diff(true); CssDiff.tokenize = function(value) { - return removeEmpty(value.split(/([{}:;,]|\s+)/)); + return value.split(/([{}:;,]|\s+)/); }; var LineDiff = new Diff(); @@ -367,7 +367,7 @@ var SentenceDiff = new Diff(); SentenceDiff.tokenize = function(value) { - return removeEmpty(value.split(/(\S.+?[.!?])(?=\s+|$)/)); + return value.split(/(\S.+?[.!?])(?=\s+|$)/); }; var JsonDiff = new Diff(); From bcb87ec2f8383013bf530e653b264c23c518bd10 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Wed, 5 Aug 2015 12:58:52 -0500 Subject: [PATCH 010/232] Convert to webpack and babel built library --- .gitignore | 1 + Gruntfile.js | 90 +++++++++++++++++++++++++++++++++++++++ examples/node_example.js | 2 +- examples/web_example.html | 2 +- package.json | 19 +++++++-- diff.js => src/diff.js | 0 test/applyPatch.js | 2 +- test/canonicalize.js | 2 +- test/createPatch.js | 2 +- test/diffTest.js | 2 +- test/structuredPatch.js | 2 +- 11 files changed, 113 insertions(+), 11 deletions(-) create mode 100644 Gruntfile.js rename diff.js => src/diff.js (100%) diff --git a/.gitignore b/.gitignore index df9af16b..b034aafe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ coverage node_modules npm-debug.log +dist \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 00000000..814174c4 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,90 @@ +/* esline-env node */ +/* eslint-disable no-process-env, camelcase */ +module.exports = function(grunt) { + + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + + clean: ['dist'], + + eslint: { + options: { + }, + files: [ + 'src/**/*.js', + 'test/**/*.js' + ] + }, + + clean: ['dist'], + + webpack: { + options: { + context: __dirname, + module: { + loaders: [ + // the optional 'runtime' transformer tells babel to require the runtime instead of inlining it. + { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader?optional=runtime&loose=es6.modules&auxiliaryCommentBefore=istanbul%20ignore%20next' } + ] + }, + output: { + path: 'dist/', + library: 'JsDiff', + libraryTarget: 'umd' + } + }, + dist: { + entry: './src/diff.js', + output: { + filename: 'diff.js' + } + } + }, + + mocha_istanbul: { + coverage: { + src: 'test' + } + }, + istanbul_check_coverage: { + 'default': { + options: { + coverageFolder: 'coverage*', // will check both coverage folders and merge the coverage results + check: { + statements: 100, + functions: 100, + branches: 100, + lines: 100 + } + } + } + }, + + watch: { + scripts: { + options: { + atBegin: true + }, + + files: ['src/**/*.js', 'test/**/*.js'], + tasks: ['build', 'test'] + } + } + }); + + // Build a new version of the library + this.registerTask('build', 'Builds a distributable version of the current project', ['eslint', 'webpack']); + this.registerTask('test', ['mocha_istanbul:coverage', 'istanbul_check_coverage']); + + // Load tasks from npm + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-eslint'); + grunt.loadNpmTasks('grunt-mocha-istanbul'); + grunt.loadNpmTasks('grunt-webpack'); + + grunt.registerTask('travis', 'default'); + + grunt.registerTask('dev', ['clean', 'watch']); + grunt.registerTask('default', ['clean', 'build', 'test']); +}; diff --git a/examples/node_example.js b/examples/node_example.js index 0c62ca1b..8e696caf 100644 --- a/examples/node_example.js +++ b/examples/node_example.js @@ -1,5 +1,5 @@ require('colors') -var jsdiff = require('../diff'); +var jsdiff = require('../'); var one = 'beep boop'; var other = 'beep boob blah'; diff --git a/examples/web_example.html b/examples/web_example.html index fc58df7e..7f2cb636 100644 --- a/examples/web_example.html +++ b/examples/web_example.html @@ -1,5 +1,5 @@

-
+
 
\ 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 126/232] 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 fda26ece..864d52da 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 dbf24277..3e278f61 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 127/232] 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 3172175c..9dfa3c0b 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 128/232] 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 efdfba2c..7a8404b3 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 ce9dd4e0..e90ac11d 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 3194fcd0..f0466532 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 129/232] 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 39842cc2..dab7189d 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 7a5f52e9..c4c1ed42 100644
--- a/examples/web_example.html
+++ b/examples/web_example.html
@@ -1,22 +1,28 @@