@@ -425,5 +425,103 @@ Index: test2
425425 }
426426 ] ) ;
427427 } ) ;
428+
429+ it ( 'should tolerate patches with extra trailing newlines after hunks' , ( ) => {
430+ // Regression test for https://github.com/kpdecker/jsdiff/issues/524
431+ // Not only are these considered valid by GNU patch, but jsdiff's own formatPatch method
432+ // emits patches like this, which jsdiff used to then be unable to parse!
433+ const patchStr = `--- foo 2024-06-14 22:16:31.444276792 +0100
434+ +++ bar 2024-06-14 22:17:14.910611219 +0100
435+ @@ -1,7 +1,7 @@
436+ first
437+ second
438+ third
439+ -fourth
440+ -fifth
441+ +vierte
442+ +fünfte
443+ sixth
444+ seventh
445+
446+ ` ;
447+ expect ( parsePatch ( patchStr ) ) . to . eql ( [ {
448+ oldFileName : 'foo' ,
449+ oldHeader : '2024-06-14 22:16:31.444276792 +0100' ,
450+ newFileName : 'bar' ,
451+ newHeader : '2024-06-14 22:17:14.910611219 +0100' ,
452+ hunks : [
453+ {
454+ oldStart : 1 ,
455+ oldLines : 7 ,
456+ newStart : 1 ,
457+ newLines : 7 ,
458+ lines : [
459+ ' first' ,
460+ ' second' ,
461+ ' third' ,
462+ '-fourth' ,
463+ '-fifth' ,
464+ '+vierte' ,
465+ '+fünfte' ,
466+ ' sixth' ,
467+ ' seventh'
468+ ]
469+ }
470+ ]
471+ } ] ) ;
472+ } ) ;
473+
474+ it ( "shouldn't be caught out by removal/addition of lines starting with -- or ++" , ( ) => {
475+ // The patch below is a valid patch generated by diffing this file, foo:
476+
477+ // first
478+ // second
479+ // third
480+ // -- bla
481+ // fifth
482+ // sixth
483+
484+ // against this file, bar:
485+
486+ // first
487+ // second
488+ // third
489+ // ++ bla
490+ // fifth
491+ // sixth
492+ // seventh
493+
494+ // with the command `diff -u0 foo bar`. (All lines in `foo` and `bar` have no leading
495+ // whitespace and a trailing LF.)
496+
497+ // This is effectively an adversarial example meant to catch out a parser that tries to
498+ // detect the end of a file in a multi-file diff by looking for lines starting with '---',
499+ // '+++', and then '@@'. jsdiff used to do this. However, as this example illustrates, it is
500+ // unsound, since the '---' and '+++' lines might actually just represent the deletion and
501+ // insertion of lines starting with '--' and '++'. The only way to disambiguate these
502+ // interpretations is to heed the line counts in the @@ hunk headers; you *cannot* reliably
503+ // determine where a hunk or file ends in a unified diff patch without heeding those line
504+ // counts.
505+
506+ const patchStr = `--- foo 2024-06-14 21:57:04.341065736 +0100
507+ +++ bar 2024-06-14 22:00:57.988080321 +0100
508+ @@ -4 +4 @@
509+ --- bla
510+ +++ bla
511+ @@ -6,0 +7 @@
512+ +seventh
513+ ` ;
514+
515+ expect ( parsePatch ( patchStr ) ) . to . eql ( [ {
516+ oldFileName : 'foo 2024-06-14 21:57:04.341065736 +0100' ,
517+ oldHeader : '' ,
518+ newFileName : 'bar 2024-06-14 22:00:57.988080321 +0100' ,
519+ newHeader : '' ,
520+ hunks : [
521+ { oldStart : 4 , oldLines : 1 , newStart : 4 , newLines : 1 , lines : [ '--- bla' , '+++ bla' ] } ,
522+ { oldStart : 7 , oldLines : 0 , newStart : 7 , newLines : 1 , lines : [ '+seventh' ] }
523+ ]
524+ } ] ) ;
525+ } ) ;
428526 } ) ;
429527} ) ;
0 commit comments