diff --git a/README.md b/README.md index 986acf9f..60eacb18 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,8 @@ npm install diff --save Options * `ignoreWhitespace`: `true` to ignore leading and trailing whitespace. This is the same as `diffTrimmedLines` + * `stripTrailingCr`: `true` to remove all trailing CR (`\r`) characters before perfoming the diff. + This helps to get a useful diff when diffing UNIX text files against Windows text files. * `newlineIsToken`: `true` to treat newline characters as separate tokens. This allows for changes to the newline structure to occur independently of the line content and to be treated as such. In general this is the more human friendly form of `diffLines` and `diffLines` is better suited for patches and other computer friendly output. Returns a list of [change objects](#change-objects). @@ -81,6 +83,8 @@ npm install diff --save - `context` describes how many lines of context should be included. - `ignoreWhitespace`: `true` to ignore leading and trailing whitespace. - `newlineIsToken`: `true` to treat newline characters as separate tokens. This allows for changes to the newline structure to occur independently of the line content and to be treated as such. In general this is the more human friendly form of `diffLines` and `diffLines` is better suited for patches and other computer friendly output. + - `stripTrailingCr`: `true` to remove all trailing CR (`\r`) characters before perfoming the diff. + This helps to get a useful diff when diffing UNIX text files against Windows text files. * `Diff.createPatch(fileName, oldStr, newStr, oldHeader, newHeader)` - creates a unified diff patch. diff --git a/src/diff/line.js b/src/diff/line.js index f9b4f499..4ab01b2b 100644 --- a/src/diff/line.js +++ b/src/diff/line.js @@ -3,6 +3,11 @@ import {generateOptions} from '../util/params'; export const lineDiff = new Diff(); lineDiff.tokenize = function(value) { + if(this.options.stripTrailingCr) { + // remove one \r before \n to match GNU diff's --strip-trailing-cr behavior + value = value.replace(/\r\n/g, '\n'); + } + let retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/); diff --git a/test/diff/line.js b/test/diff/line.js index 6bc1e183..d38095f4 100644 --- a/test/diff/line.js +++ b/test/diff/line.js @@ -106,4 +106,10 @@ describe('diff/line', function() { {value: '\nhello', count: 2, added: true, removed: undefined} ]); }); + + describe('Strip trailing CR', function() { + expect(diffLines('line\nline', 'line\r\nline', {stripTrailingCr: true})).to.eql([ + {value: 'line\nline', count: 2} + ]); + }); }); diff --git a/test/patch/create.js b/test/patch/create.js index 8b8c05b5..2df4bb13 100644 --- a/test/patch/create.js +++ b/test/patch/create.js @@ -705,6 +705,45 @@ describe('patch/create', function() { }); }); + describe('stripTrailingCr', function() { + it('stripTrailingCr: false', function() { + const expectedResult = + '===================================================================\n' + + '--- foo\n' + + '+++ bar\n' + + '@@ -1,2 +1,2 @@\n' + + '\-line\n' + + '\+line\r\n' + + '\ line\n' + + '\\ No newline at end of file\n'; + expect(createTwoFilesPatch( + 'foo', + 'bar', + 'line\nline', + 'line\r\nline', + undefined, + undefined, + {stripTrailingCr: false} + )).to.equal(expectedResult); + }); + + it('stripTrailingCr: true', function() { + const expectedResult = + '===================================================================\n' + + '--- foo\n' + + '+++ bar\n'; + expect(createTwoFilesPatch( + 'foo', + 'bar', + 'line\nline', + 'line\r\nline', + undefined, + undefined, + {stripTrailingCr: true} + )).to.equal(expectedResult); + }); + }); + describe('#structuredPatch', function() { it('should handle files with the last line changed', function() { const res = structuredPatch(