From 802fa9d63d7245899428e1847c3e2b876244505a Mon Sep 17 00:00:00 2001 From: Sidney Date: Wed, 12 Oct 2016 15:46:06 -0400 Subject: [PATCH 01/13] Split file using all possible line delimeter instead of hard-coded "/n" and join lines back using the original delimeters Change-Id: I8428395071744f78e19dd96e81c1b6bc7ca1126e Signed-off-by: Sidney --- src/patch/apply.js | 15 ++++++++++++--- src/patch/parse.js | 7 +++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/patch/apply.js b/src/patch/apply.js index e400a167..d720159d 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -15,7 +15,8 @@ export function applyPatch(source, uniDiff, options = {}) { } // Apply the diff to the input - let lines = source.split('\n'), + let lines = source.split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/), + delimiters = source.match(/\r\n|[\n\v\f\r\x85\u2028\u2029]/g), hunks = uniDiff.hunks, compareLine = options.compareLine || ((lineNumber, line, operation, patchContent) => line === patchContent), @@ -86,15 +87,18 @@ export function applyPatch(source, uniDiff, options = {}) { for (let j = 0; j < hunk.lines.length; j++) { let line = hunk.lines[j], operation = line[0], - content = line.substr(1); + content = line.substr(1), + delimiter = hunk.linedelimiters[j]; if (operation === ' ') { toPos++; } else if (operation === '-') { lines.splice(toPos, 1); + delimiters.splice(toPos, 1); /* istanbul ignore else */ } else if (operation === '+') { lines.splice(toPos, 0, content); + delimiters.splice(toPos, 0, delimiter); toPos++; } else if (operation === '\\') { let previousOperation = hunk.lines[j - 1] ? hunk.lines[j - 1][0] : null; @@ -111,11 +115,16 @@ export function applyPatch(source, uniDiff, options = {}) { if (removeEOFNL) { while (!lines[lines.length - 1]) { lines.pop(); + delimiters.pop() } } else if (addEOFNL) { lines.push(''); + delimiters.push('\n'); + } + for(var _k = 0; _k < lines.length; _k ++){ + lines[_k] = lines[_k] + delimiters[_k]; } - return lines.join('\n'); + return lines.join(''); } // Wrapper that supports multiple file patches via callbacks. diff --git a/src/patch/parse.js b/src/patch/parse.js index 6e546d02..0f88ada1 100755 --- a/src/patch/parse.js +++ b/src/patch/parse.js @@ -1,5 +1,6 @@ export function parsePatch(uniDiff, options = {}) { - let diffstr = uniDiff.split('\n'), + let diffstr = uniDiff.split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/), + delimiters = uniDiff.match(/\r\n|[\n\v\f\r\x85\u2028\u2029]/g), list = [], i = 0; @@ -75,7 +76,8 @@ export function parsePatch(uniDiff, options = {}) { oldLines: +chunkHeader[2] || 1, newStart: +chunkHeader[3], newLines: +chunkHeader[4] || 1, - lines: [] + lines: [], + linedelimiters:[] }; let addCount = 0, @@ -93,6 +95,7 @@ export function parsePatch(uniDiff, options = {}) { if (operation === '+' || operation === '-' || operation === ' ' || operation === '\\') { hunk.lines.push(diffstr[i]); + hunk.linedelimiters.push(delimiters[i]); if (operation === '+') { addCount++; From 8440a552ecbc6890a03452f6452860f1bfe03b53 Mon Sep 17 00:00:00 2001 From: Sidney Date: Wed, 12 Oct 2016 15:53:29 -0400 Subject: [PATCH 02/13] error fix Change-Id: Ibe1f1da43f4e7d2d246c3e3b4e31e515a76f45c3 Signed-off-by: Sidney --- 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 d720159d..91726e34 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -115,13 +115,13 @@ export function applyPatch(source, uniDiff, options = {}) { if (removeEOFNL) { while (!lines[lines.length - 1]) { lines.pop(); - delimiters.pop() + delimiters.pop(); } } else if (addEOFNL) { lines.push(''); delimiters.push('\n'); } - for(var _k = 0; _k < lines.length; _k ++){ + for (let _k = 0; _k < lines.length; _k++) { lines[_k] = lines[_k] + delimiters[_k]; } return lines.join(''); From 53ccd48922bc59272533d200728ea67d1d8fba77 Mon Sep 17 00:00:00 2001 From: Sidney Date: Wed, 12 Oct 2016 15:58:04 -0400 Subject: [PATCH 03/13] more error fix Change-Id: Idd56dfba2f2764a2937226fde566c8ef3abf487c Signed-off-by: Sidney --- src/patch/apply.js | 2 +- src/patch/parse.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/patch/apply.js b/src/patch/apply.js index 91726e34..18050edc 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -122,7 +122,7 @@ export function applyPatch(source, uniDiff, options = {}) { delimiters.push('\n'); } for (let _k = 0; _k < lines.length; _k++) { - lines[_k] = lines[_k] + delimiters[_k]; + lines[_k] = lines[_k] + delimiters[_k]; } return lines.join(''); } diff --git a/src/patch/parse.js b/src/patch/parse.js index 0f88ada1..0461d00b 100755 --- a/src/patch/parse.js +++ b/src/patch/parse.js @@ -77,7 +77,7 @@ export function parsePatch(uniDiff, options = {}) { newStart: +chunkHeader[3], newLines: +chunkHeader[4] || 1, lines: [], - linedelimiters:[] + linedelimiters: [] }; let addCount = 0, From 8913dd3e6efded4fed3e6c11b4a104c05d4aaafc Mon Sep 17 00:00:00 2001 From: Sidney Date: Wed, 12 Oct 2016 16:14:10 -0400 Subject: [PATCH 04/13] add default delimiter for test cases Change-Id: Ie464bfbde8d34d3f63c999226a646f01b71c012f Signed-off-by: Sidney --- 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 18050edc..2e54cba1 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -88,7 +88,7 @@ export function applyPatch(source, uniDiff, options = {}) { let line = hunk.lines[j], operation = line[0], content = line.substr(1), - delimiter = hunk.linedelimiters[j]; + delimiter = hunk.linedelimiters[j] || "/n"; if (operation === ' ') { toPos++; From 17e9a1b81378f9810798ca02cd33661039ca1410 Mon Sep 17 00:00:00 2001 From: Sidney Date: Wed, 12 Oct 2016 16:17:33 -0400 Subject: [PATCH 05/13] fix quotes Change-Id: I1e7ec5aa0c83148d3ffbb0e746fa8643b5c46b07 Signed-off-by: Sidney --- 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 2e54cba1..758c5bf7 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -88,7 +88,7 @@ export function applyPatch(source, uniDiff, options = {}) { let line = hunk.lines[j], operation = line[0], content = line.substr(1), - delimiter = hunk.linedelimiters[j] || "/n"; + delimiter = hunk.linedelimiters[j] || '\n'; if (operation === ' ') { toPos++; From b42b6798aed61fc0191139274a083836ecda517b Mon Sep 17 00:00:00 2001 From: Sidney Date: Wed, 12 Oct 2016 17:34:52 -0400 Subject: [PATCH 06/13] more changes Change-Id: I301f5e4822582689116bb5ba61228ed28d0fd1be Signed-off-by: Sidney --- src/patch/apply.js | 6 ++--- src/patch/parse.js | 6 ++--- test/patch/parse.js | 65 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/src/patch/apply.js b/src/patch/apply.js index 758c5bf7..453354c8 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -15,8 +15,8 @@ export function applyPatch(source, uniDiff, options = {}) { } // Apply the diff to the input - let lines = source.split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/), - delimiters = source.match(/\r\n|[\n\v\f\r\x85\u2028\u2029]/g), + let lines = source.split(/\r\n|[\n\v\f\r\x85]/), + delimiters = source.match(/\r\n|[\n\v\f\r\x85]/g) || [], hunks = uniDiff.hunks, compareLine = options.compareLine || ((lineNumber, line, operation, patchContent) => line === patchContent), @@ -121,7 +121,7 @@ export function applyPatch(source, uniDiff, options = {}) { lines.push(''); delimiters.push('\n'); } - for (let _k = 0; _k < lines.length; _k++) { + for (let _k = 0; _k < lines.length - 1; _k++) { lines[_k] = lines[_k] + delimiters[_k]; } return lines.join(''); diff --git a/src/patch/parse.js b/src/patch/parse.js index 0461d00b..08be7628 100755 --- a/src/patch/parse.js +++ b/src/patch/parse.js @@ -1,6 +1,6 @@ export function parsePatch(uniDiff, options = {}) { - let diffstr = uniDiff.split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/), - delimiters = uniDiff.match(/\r\n|[\n\v\f\r\x85\u2028\u2029]/g), + let diffstr = uniDiff.split(/\r\n|[\n\v\f\r\x85]/), + delimiters = uniDiff.match(/\r\n|[\n\v\f\r\x85]/g) || [], list = [], i = 0; @@ -95,7 +95,7 @@ export function parsePatch(uniDiff, options = {}) { if (operation === '+' || operation === '-' || operation === ' ' || operation === '\\') { hunk.lines.push(diffstr[i]); - hunk.linedelimiters.push(delimiters[i]); + hunk.linedelimiters.push(delimiters[i] || '\n'); if (operation === '+') { addCount++; diff --git a/test/patch/parse.js b/test/patch/parse.js index b5361634..f7aa9f98 100644 --- a/test/patch/parse.js +++ b/test/patch/parse.js @@ -21,6 +21,12 @@ describe('patch/parse', function() { ' line3', '+line4', ' line5' + ], + linedelimiters: [ + '\n', + '\n', + '\n', + '\n' ] } ] @@ -39,6 +45,10 @@ describe('patch/parse', function() { lines: [ '-line3', '+line4' + ], + linedelimiters: [ + '\n', + '\n' ] } ] @@ -66,6 +76,12 @@ describe('patch/parse', function() { ' line3', '+line4', ' line5' + ], + linedelimiters: [ + '\n', + '\n', + '\n', + '\n' ] }, { @@ -76,6 +92,12 @@ describe('patch/parse', function() { ' line3', '-line4', ' line5' + ], + linedelimiters: [ + '\n', + '\n', + '\n', + '\n' ] } ] @@ -107,6 +129,12 @@ describe('patch/parse', function() { ' line3', '+line4', ' line5' + ], + linedelimiters: [ + '\n', + '\n', + '\n', + '\n' ] } ] @@ -147,6 +175,12 @@ Index: test2 ' line3', '+line4', ' line5' + ], + linedelimiters: [ + '\n', + '\n', + '\n', + '\n' ] } ] @@ -165,6 +199,12 @@ Index: test2 ' line3', '+line4', ' line5' + ], + linedelimiters: [ + '\n', + '\n', + '\n', + '\n' ] } ] @@ -201,6 +241,12 @@ Index: test2 ' line3', '+line4', ' line5' + ], + linedelimiters: [ + '\n', + '\n', + '\n', + '\n' ] } ] @@ -218,6 +264,12 @@ Index: test2 ' line3', '+line4', ' line5' + ], + linedelimiters: [ + '\n', + '\n', + '\n', + '\n' ] } ] @@ -237,6 +289,10 @@ Index: test2 lines: [ '-line5', '\\ No newline at end of file' + ], + linedelimiters: [ + '\n', + '\n' ] } ] @@ -255,6 +311,10 @@ Index: test2 lines: [ '+line5', '\\ No newline at end of file' + ], + linedelimiters: [ + '\n', + '\n' ] } ] @@ -275,6 +335,11 @@ Index: test2 '+line4', ' line5', '\\ No newline at end of file' + ], + linedelimiters: [ + '\n', + '\n', + '\n' ] } ] From 563e50287f27fd4622b5255329eeba7ad5f32896 Mon Sep 17 00:00:00 2001 From: Sidney Date: Thu, 13 Oct 2016 10:07:28 -0400 Subject: [PATCH 07/13] removed the uncovered code Change-Id: Id3e3f4f23249e07d02b4dc34207368a7eeee7ad5 Signed-off-by: Sidney --- 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 453354c8..3cf472ab 100644 --- a/src/patch/apply.js +++ b/src/patch/apply.js @@ -88,7 +88,7 @@ export function applyPatch(source, uniDiff, options = {}) { let line = hunk.lines[j], operation = line[0], content = line.substr(1), - delimiter = hunk.linedelimiters[j] || '\n'; + delimiter = hunk.linedelimiters[j]; if (operation === ' ') { toPos++; From d1a76162f5d05caf2191e60e2c06d96b5c530b26 Mon Sep 17 00:00:00 2001 From: Wilfred van der Deijl Date: Thu, 20 Oct 2016 13:56:06 +0200 Subject: [PATCH 08/13] moved join to Diff so subclasses can override it --- src/diff/base.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/diff/base.js b/src/diff/base.js index 21a7eeaa..684782c0 100644 --- a/src/diff/base.js +++ b/src/diff/base.js @@ -160,6 +160,9 @@ Diff.prototype = { }, tokenize(value) { return value.split(''); + }, + join(chars) { + return chars.join(''); } }; @@ -179,9 +182,9 @@ function buildValues(diff, components, newString, oldString, useLongestToken) { return oldValue.length > value.length ? oldValue : value; }); - component.value = value.join(''); + component.value = diff.join(value); } else { - component.value = newString.slice(newPos, newPos + component.count).join(''); + component.value = diff.join(newString.slice(newPos, newPos + component.count)); } newPos += component.count; @@ -190,7 +193,7 @@ function buildValues(diff, components, newString, oldString, useLongestToken) { oldPos += component.count; } } else { - component.value = oldString.slice(oldPos, oldPos + component.count).join(''); + component.value = diff.join(oldString.slice(oldPos, oldPos + component.count)); oldPos += component.count; // Reverse add and remove so removes are output first to match common convention From 9aea80bec022e8210d633d966ebd39b2cd32897f Mon Sep 17 00:00:00 2001 From: Wilfred van der Deijl Date: Thu, 20 Oct 2016 14:10:11 +0200 Subject: [PATCH 09/13] moved join to Diff so subclasses can override it --- src/diff/base.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diff/base.js b/src/diff/base.js index 684782c0..7ce7e320 100644 --- a/src/diff/base.js +++ b/src/diff/base.js @@ -36,7 +36,7 @@ Diff.prototype = { let oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) { // Identity per the equality and tokenizer - return done([{value: newString.join(''), count: newString.length}]); + return done([{value: this.join(newString), count: newString.length}]); } // Main worker method. checks all permutations of a given edit length for acceptance. From 0bb9c4cff9ca811266d80688a4fb2d94972d5f95 Mon Sep 17 00:00:00 2001 From: Wilfred van der Deijl Date: Thu, 20 Oct 2016 14:11:11 +0200 Subject: [PATCH 10/13] added JsDiff.diffArrays compares each element in the arrays using equality (===) --- README.md | 4 ++++ src/diff/array.js | 8 ++++++++ src/index.js | 4 ++++ test/diff/array.js | 19 +++++++++++++++++++ test/index.js | 2 ++ 5 files changed, 37 insertions(+) create mode 100644 src/diff/array.js create mode 100644 test/diff/array.js diff --git a/README.md b/README.md index b5c48afa..03b5845d 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,10 @@ or Returns a list of change objects (See below). +* `JsDiff.diffArrays(oldArr, newArr[, options])` - diffs two arrays, comparing each item for strict equality (===). + + Returns a list of change objects (See below). + * `JsDiff.createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader)` - creates a unified diff patch. Parameters: diff --git a/src/diff/array.js b/src/diff/array.js new file mode 100644 index 00000000..13f4f406 --- /dev/null +++ b/src/diff/array.js @@ -0,0 +1,8 @@ +import Diff from './base'; + +export const arrayDiff = new Diff(); +arrayDiff.tokenize = arrayDiff.join = function(value) { + return value; +}; + +export function diffArrays(oldArr, newArr, callback) { return arrayDiff.diff(oldArr, newArr, callback); } diff --git a/src/index.js b/src/index.js index ae09ed1f..5c6340a4 100644 --- a/src/index.js +++ b/src/index.js @@ -23,6 +23,8 @@ import {diffSentences} from './diff/sentence'; import {diffCss} from './diff/css'; import {diffJson, canonicalize} from './diff/json'; +import {diffArrays} from './diff/array'; + import {applyPatch, applyPatches} from './patch/apply'; import {parsePatch} from './patch/parse'; import {structuredPatch, createTwoFilesPatch, createPatch} from './patch/create'; @@ -43,6 +45,8 @@ export { diffCss, diffJson, + diffArrays, + structuredPatch, createTwoFilesPatch, createPatch, diff --git a/test/diff/array.js b/test/diff/array.js new file mode 100644 index 00000000..1dde77bc --- /dev/null +++ b/test/diff/array.js @@ -0,0 +1,19 @@ +import {diffArrays} from '../../lib/diff/array'; + +import {expect} from 'chai'; + +describe('diff/array', function() { + describe('#diffArrays', function() { + it('Should diff arrays', function() { + const a = {a: 0}, b = {b: 1}, c = {c: 2}; + const diffResult = diffArrays([a, b, c], [a, c, b]); + console.log(diffResult); + expect(diffResult).to.deep.equals([ + {count: 1, value: [a]}, + {count: 1, value: [c], removed: undefined, added: true}, + {count: 1, value: [b]}, + {count: 1, value: [c], removed: true, added: undefined} + ]); + }); + }); +}); diff --git a/test/index.js b/test/index.js index 42ad2d97..100a867c 100644 --- a/test/index.js +++ b/test/index.js @@ -16,6 +16,8 @@ describe('root exports', function() { expect(Diff.diffCss).to.exist; expect(Diff.diffJson).to.exist; + expect(Diff.diffArrays).to.exist; + expect(Diff.structuredPatch).to.exist; expect(Diff.createTwoFilesPatch).to.exist; expect(Diff.createPatch).to.exist; From d5003de462121e0fa7e44c7d59d0ec42a394719a Mon Sep 17 00:00:00 2001 From: Wilfred van der Deijl Date: Thu, 20 Oct 2016 16:57:58 +0200 Subject: [PATCH 11/13] clone arrays so we don't alter input values --- src/diff/array.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diff/array.js b/src/diff/array.js index 13f4f406..4c2a3292 100644 --- a/src/diff/array.js +++ b/src/diff/array.js @@ -2,7 +2,7 @@ import Diff from './base'; export const arrayDiff = new Diff(); arrayDiff.tokenize = arrayDiff.join = function(value) { - return value; + return value.slice(); }; export function diffArrays(oldArr, newArr, callback) { return arrayDiff.diff(oldArr, newArr, callback); } From d42f1b3b2a9ef6b48d2a0ab7287ff1d308f1e7a3 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 27 Nov 2016 13:56:56 -0600 Subject: [PATCH 12/13] 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 a27b6cd9..cdc8de6d 100644 --- a/release-notes.md +++ b/release-notes.md @@ -2,7 +2,13 @@ ## Development -[Commits](https://github.com/kpdecker/jsdiff/compare/v3.0.1...master) +[Commits](https://github.com/kpdecker/jsdiff/compare/v3.1.0...master) + +## v3.1.0 - November 27th, 2016 +- [#146](https://github.com/kpdecker/jsdiff/pull/146) - JsDiff.diffArrays to compare arrays ([@wvanderdeijl](https://api.github.com/users/wvanderdeijl)) +- [#144](https://github.com/kpdecker/jsdiff/pull/144) - Split file using all possible line delimiter instead of hard-coded "/n" and join lines back using the original delimiters ([@soulbeing](https://api.github.com/users/soulbeing)) + +[Commits](https://github.com/kpdecker/jsdiff/compare/v3.0.1...v3.1.0) ## v3.0.1 - October 9th, 2016 - [#139](https://github.com/kpdecker/jsdiff/pull/139) - Make README.md look nicer in npmjs.com ([@takenspc](https://api.github.com/users/takenspc)) From 870aa158609ecdba74b11fbda62f583318481c68 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sun, 27 Nov 2016 13:57:11 -0600 Subject: [PATCH 13/13] v3.1.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 b9ab8ba1..7496edda 100644 --- a/components/bower.json +++ b/components/bower.json @@ -1,6 +1,6 @@ { "name": "jsdiff", - "version": "3.0.1", + "version": "3.1.0", "main": [ "diff.js" ], diff --git a/components/component.json b/components/component.json index e3b451d9..7c4c4463 100644 --- a/components/component.json +++ b/components/component.json @@ -6,7 +6,7 @@ "diff", "text" ], - "version": "3.0.1", + "version": "3.1.0", "scripts": [ "diff.js" ], "main": "diff.js", "license": "BSD" diff --git a/package.json b/package.json index 462b4a17..17cbd98d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "diff", - "version": "3.0.1", + "version": "3.1.0", "description": "A javascript text diff implementation.", "keywords": [ "diff",