Skip to content

Commit c64d178

Browse files
authored
Update to match quirks of unified diff format (#297)
1 parent e47ca0a commit c64d178

File tree

4 files changed

+184
-11
lines changed

4 files changed

+184
-11
lines changed

src/patch/create.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ export function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHea
7272
let oldEOFNewline = ((/\n$/).test(oldStr));
7373
let newEOFNewline = ((/\n$/).test(newStr));
7474
let noNlBeforeAdds = lines.length == 0 && curRange.length > hunk.oldLines;
75-
if (!oldEOFNewline && noNlBeforeAdds) {
75+
if (!oldEOFNewline && noNlBeforeAdds && oldStr.length > 0) {
7676
// special case: old has no eol and no trailing context; no-nl can end up before adds
77+
// however, if the old file is empty, do not output the no-nl line
7778
curRange.splice(hunk.oldLines, 0, '\\ No newline at end of file');
7879
}
7980
if ((!oldEOFNewline && !noNlBeforeAdds) || !newEOFNewline) {
@@ -110,6 +111,15 @@ export function formatPatch(diff) {
110111

111112
for (let i = 0; i < diff.hunks.length; i++) {
112113
const hunk = diff.hunks[i];
114+
// Unified Diff Format quirk: If the chunk size is 0,
115+
// the first number is one lower than one would expect.
116+
// https://www.artima.com/weblogs/viewpost.jsp?thread=164293
117+
if (hunk.oldLines === 0) {
118+
hunk.oldStart -= 1;
119+
}
120+
if (hunk.newLines === 0) {
121+
hunk.newStart -= 1;
122+
}
113123
ret.push(
114124
'@@ -' + hunk.oldStart + ',' + hunk.oldLines
115125
+ ' +' + hunk.newStart + ',' + hunk.newLines

src/patch/parse.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,23 @@ export function parsePatch(uniDiff, options = {}) {
7777

7878
let hunk = {
7979
oldStart: +chunkHeader[1],
80-
oldLines: +chunkHeader[2] || 1,
80+
oldLines: typeof chunkHeader[2] === 'undefined' ? 1 : +chunkHeader[2],
8181
newStart: +chunkHeader[3],
82-
newLines: +chunkHeader[4] || 1,
82+
newLines: typeof chunkHeader[4] === 'undefined' ? 1 : +chunkHeader[4],
8383
lines: [],
8484
linedelimiters: []
8585
};
8686

87+
// Unified Diff Format quirk: If the chunk size is 0,
88+
// the first number is one lower than one would expect.
89+
// https://www.artima.com/weblogs/viewpost.jsp?thread=164293
90+
if (hunk.oldLines === 0) {
91+
hunk.oldStart += 1;
92+
}
93+
if (hunk.newLines === 0) {
94+
hunk.newStart += 1;
95+
}
96+
8797
let addCount = 0,
8898
removeCount = 0;
8999
for (; i < diffstr.length; i++) {

test/patch/apply.js

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,160 @@ describe('patch/apply', function() {
355355
+ 'line5\n');
356356
});
357357

358+
it('should apply single line patches with zero context and zero removed', function() {
359+
expect(applyPatch(
360+
'line2\n'
361+
+ 'line3\n'
362+
+ 'line5\n',
363+
364+
'--- test\theader1\n'
365+
+ '+++ test\theader2\n'
366+
+ '@@ -2,0 +3 @@\n'
367+
+ '+line4\n'))
368+
.to.equal(
369+
'line2\n'
370+
+ 'line3\n'
371+
+ 'line4\n'
372+
+ 'line5\n');
373+
});
374+
375+
it('should apply multiline patches with zero context and zero removed', function() {
376+
expect(applyPatch(
377+
'line2\n'
378+
+ 'line3\n'
379+
+ 'line7\n',
380+
381+
'--- test\theader1\n'
382+
+ '+++ test\theader2\n'
383+
+ '@@ -2,0 +3,3 @@\n'
384+
+ '+line4\n'
385+
+ '+line5\n'
386+
+ '+line6\n'))
387+
.to.equal(
388+
'line2\n'
389+
+ 'line3\n'
390+
+ 'line4\n'
391+
+ 'line5\n'
392+
+ 'line6\n'
393+
+ 'line7\n');
394+
});
395+
396+
it('should apply single line patches with zero context and zero removed at start of file', function() {
397+
expect(applyPatch(
398+
'line2\n'
399+
+ 'line3\n',
400+
401+
'--- test\theader1\n'
402+
+ '+++ test\theader2\n'
403+
+ '@@ -0,0 +1 @@\n'
404+
+ '+line1\n'))
405+
.to.equal(
406+
'line1\n'
407+
+ 'line2\n'
408+
+ 'line3\n');
409+
});
410+
411+
it('should apply multi line patches with zero context and zero removed at start of file', function() {
412+
expect(applyPatch(
413+
'line3\n'
414+
+ 'line4\n',
415+
416+
'--- test\theader1\n'
417+
+ '+++ test\theader2\n'
418+
+ '@@ -0,0 +1,2 @@\n'
419+
+ '+line1\n'
420+
+ '+line2\n'))
421+
.to.equal(
422+
'line1\n'
423+
+ 'line2\n'
424+
+ 'line3\n'
425+
+ 'line4\n');
426+
});
427+
428+
it('should apply multi line patches with zero context and zero removed at end of file', function() {
429+
expect(applyPatch(
430+
'line1\n',
431+
432+
'--- test\theader1\n'
433+
+ '+++ test\theader2\n'
434+
+ '@@ -1,0 +2 @@\n'
435+
+ '+line2\n'))
436+
.to.equal(
437+
'line1\n'
438+
+ 'line2\n');
439+
});
440+
441+
it('should apply multi line patches with zero context and zero removed at end of file', function() {
442+
expect(applyPatch(
443+
'line1\n',
444+
445+
'--- test\theader1\n'
446+
+ '+++ test\theader2\n'
447+
+ '@@ -1,0 +2,2 @@\n'
448+
+ '+line2\n'
449+
+ '+line3\n'))
450+
.to.equal(
451+
'line1\n'
452+
+ 'line2\n'
453+
+ 'line3\n');
454+
});
455+
456+
it('should apply single line patches with zero context and zero added at beginning of file', function() {
457+
expect(applyPatch(
458+
'line1\n'
459+
+ 'line2\n',
460+
461+
'--- test\theader1\n'
462+
+ '+++ test\theader2\n'
463+
+ '@@ -1 +0,0 @@\n'
464+
+ '-line1\n'))
465+
.to.equal(
466+
'line2\n');
467+
});
468+
469+
it('should apply multi line patches with zero context and zero added at beginning of file', function() {
470+
expect(applyPatch(
471+
'line1\n'
472+
+ 'line2\n'
473+
+ 'line3\n',
474+
475+
'--- test\theader1\n'
476+
+ '+++ test\theader2\n'
477+
+ '@@ -1,2 +0,0 @@\n'
478+
+ '-line1\n'
479+
+ '-line2\n'))
480+
.to.equal(
481+
'line3\n');
482+
});
483+
484+
it('should apply single line patches with zero context and zero added at end of file', function() {
485+
expect(applyPatch(
486+
'line1\n'
487+
+ 'line2\n',
488+
489+
'--- test\theader1\n'
490+
+ '+++ test\theader2\n'
491+
+ '@@ -2 +1,0 @@\n'
492+
+ '-line2\n'))
493+
.to.equal(
494+
'line1\n');
495+
});
496+
497+
it('should apply multi line patches with zero context and zero added at end of file', function() {
498+
expect(applyPatch(
499+
'line1\n'
500+
+ 'line2\n'
501+
+ 'line3\n',
502+
503+
'--- test\theader1\n'
504+
+ '+++ test\theader2\n'
505+
+ '@@ -2,2 +1,0 @@\n'
506+
+ '-line2\n'
507+
+ '-line3\n'))
508+
.to.equal(
509+
'line1\n');
510+
});
511+
358512
it('should fail on mismatch', function() {
359513
expect(applyPatch(
360514
'line2\n'

test/patch/create.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,13 @@ describe('patch/create', function() {
120120
+ '\\ No newline at end of file\n');
121121
});
122122

123-
it('should output only one "no newline" at end of file message on empty file', function() {
123+
it('should output no "no newline" at end of file message on empty file', function() {
124124
expect(createPatch('test', '', 'line1\nline2\nline3\nline4', 'header1', 'header2')).to.equal(
125125
'Index: test\n'
126126
+ '===================================================================\n'
127127
+ '--- test\theader1\n'
128128
+ '+++ test\theader2\n'
129-
+ '@@ -1,0 +1,4 @@\n'
130-
+ '\\ No newline at end of file\n'
129+
+ '@@ -0,0 +1,4 @@\n'
131130
+ '+line1\n'
132131
+ '+line2\n'
133132
+ '+line3\n'
@@ -139,7 +138,7 @@ describe('patch/create', function() {
139138
+ '===================================================================\n'
140139
+ '--- test\theader1\n'
141140
+ '+++ test\theader2\n'
142-
+ '@@ -1,4 +1,0 @@\n'
141+
+ '@@ -1,4 +0,0 @@\n'
143142
+ '-line1\n'
144143
+ '-line2\n'
145144
+ '-line3\n'
@@ -528,7 +527,7 @@ describe('patch/create', function() {
528527
expect(diffResult).to.equal(expectedResult);
529528
});
530529

531-
it('should generatea a patch with context size 0', function() {
530+
it('should generate a patch with context size 0', function() {
532531
const expectedResult =
533532
'Index: testFileName\n'
534533
+ '===================================================================\n'
@@ -538,11 +537,11 @@ describe('patch/create', function() {
538537
+ '-value\n'
539538
+ '+new value\n'
540539
+ '+new value 2\n'
541-
+ '@@ -11,1 +12,0 @@\n'
540+
+ '@@ -11,1 +11,0 @@\n'
542541
+ '-remove value\n'
543-
+ '@@ -21,1 +21,0 @@\n'
542+
+ '@@ -21,1 +20,0 @@\n'
544543
+ '-remove value\n'
545-
+ '@@ -30,0 +29,1 @@\n'
544+
+ '@@ -29,0 +29,1 @@\n'
546545
+ '+add value\n'
547546
+ '@@ -34,1 +34,2 @@\n'
548547
+ '-value\n'

0 commit comments

Comments
 (0)