@@ -29,6 +29,8 @@ import { DiffOp } from './diff-op.enum';
2929import { Diff } from './diff.type' ;
3030import { PatchOperation } from './patch-operation.class' ;
3131
32+ type HalfMatchResult = [ string , string , string , string , string ] ;
33+
3234/**
3335 * Class containing the diff, match and patch methods.
3436 * @constructor
@@ -64,10 +66,10 @@ export class DiffMatchPatch {
6466 */
6567
6668 // Define some regex patterns for matching boundaries.
67- private whitespaceRegex = new RegExp ( '/\\s/' ) ;
68- private linebreakRegex = new RegExp ( '/[\\r\\n]/' ) ;
69- private blanklineEndRegex = new RegExp ( '/\\n\\ r?\\ n$/' ) ;
70- private blanklineStartRegex = new RegExp ( ' /^\\ r?\\n\\ r?\\n/' ) ;
69+ private readonly whitespaceRegex = / \s / ;
70+ private readonly linebreakRegex = / \r \n / ;
71+ private readonly blanklineEndRegex = / \n \ r? \n $ / ;
72+ private readonly blanklineStartRegex = / ^ \r ? \n \ r? \n / ;
7173
7274 /**
7375 * Find the differences between two texts. Simplifies the problem by stripping
@@ -512,7 +514,7 @@ export class DiffMatchPatch {
512514 return [ ] ; // Get rid of the null case.
513515 }
514516 const patches = [ ] ;
515- let patch = new PatchOperation ( ) ;
517+ let patch = new PatchOperation ( 0 , 0 ) ;
516518 let patchDiffLength = 0 ; // Keeping our own length const is faster in JS.
517519 let char_count1 = 0 ; // Number of characters into the text1 string.
518520 let char_count2 = 0 ; // Number of characters into the text2 string.
@@ -562,7 +564,7 @@ export class DiffMatchPatch {
562564 if ( patchDiffLength ) {
563565 this . patch_addContext_ ( patch , prepatch_text ) ;
564566 patches . push ( patch ) ;
565- patch = new PatchOperation ( ) ;
567+ patch = new PatchOperation ( 0 , 0 ) ;
566568 patchDiffLength = 0 ;
567569 // Unlike Unidiff, our patch lists have a rolling context.
568570 // http://code.google.com/p/google-diff-match-patch/wiki/Unidiff
@@ -687,21 +689,22 @@ export class DiffMatchPatch {
687689 for ( const diff of patches [ x ] . diffs ) {
688690 if ( diff [ 0 ] !== DiffOp . Equal ) {
689691 index2 = this . diff_xIndex ( diffs , index1 ) ;
690- }
691- if ( diff [ 0 ] === DiffOp . Insert ) {
692- // Insertion
693- text =
694- text . substring ( 0 , start_loc + index2 ) +
695- diff [ 1 ] +
696- text . substring ( start_loc + index2 ) ;
697- } else if ( diff [ 0 ] === DiffOp . Delete ) {
698- // Deletion
699- text =
700- text . substring ( 0 , start_loc + index2 ) +
701- text . substring (
702- start_loc +
703- this . diff_xIndex ( diffs , index1 + diff [ 1 ] . length ) ,
704- ) ;
692+
693+ if ( diff [ 0 ] === DiffOp . Insert ) {
694+ // Insertion
695+ text =
696+ text . substring ( 0 , start_loc + index2 ) +
697+ diff [ 1 ] +
698+ text . substring ( start_loc + index2 ) ;
699+ } else if ( diff [ 0 ] === DiffOp . Delete ) {
700+ // Deletion
701+ text =
702+ text . substring ( 0 , start_loc + index2 ) +
703+ text . substring (
704+ start_loc +
705+ this . diff_xIndex ( diffs , index1 + diff [ 1 ] . length ) ,
706+ ) ;
707+ }
705708 }
706709 if ( diff [ 0 ] !== DiffOp . Delete ) {
707710 index1 += diff [ 1 ] . length ;
@@ -748,9 +751,8 @@ export class DiffMatchPatch {
748751 if ( ! m ) {
749752 throw new Error ( 'Invalid patch string: ' + text [ textPointer ] ) ;
750753 }
751- const patch = new PatchOperation ( ) ;
754+ const patch = new PatchOperation ( parseInt ( m [ 1 ] , 10 ) , parseInt ( m [ 3 ] , 10 ) ) ;
752755 patches . push ( patch ) ;
753- patch . start1 = parseInt ( m [ 1 ] , 10 ) ;
754756 if ( m [ 2 ] === '' ) {
755757 patch . start1 -- ;
756758 patch . length1 = 1 ;
@@ -761,7 +763,6 @@ export class DiffMatchPatch {
761763 patch . length1 = parseInt ( m [ 2 ] , 10 ) ;
762764 }
763765
764- patch . start2 = parseInt ( m [ 3 ] , 10 ) ;
765766 if ( m [ 4 ] === '' ) {
766767 patch . start2 -- ;
767768 patch . length2 = 1 ;
@@ -775,7 +776,7 @@ export class DiffMatchPatch {
775776
776777 while ( textPointer < text . length ) {
777778 const sign = text [ textPointer ] . charAt ( 0 ) ;
778- let line : string ;
779+ let line : string | undefined ;
779780 try {
780781 line = decodeURI ( text [ textPointer ] . substring ( 1 ) ) ;
781782 } catch ( _ex ) {
@@ -1546,7 +1547,10 @@ export class DiffMatchPatch {
15461547 * text2 and the common middle. Or null if there was no match.
15471548 * @private
15481549 */
1549- private diff_halfMatch_ ( text1 : string , text2 : string ) : string [ ] {
1550+ private diff_halfMatch_ (
1551+ text1 : string ,
1552+ text2 : string ,
1553+ ) : HalfMatchResult | null {
15501554 if ( this . Diff_Timeout <= 0 ) {
15511555 // Don't risk returning a non-optimal diff if we have unlimited time.
15521556 return null ;
@@ -1571,16 +1575,20 @@ export class DiffMatchPatch {
15711575 Math . ceil ( longtext . length / 2 ) ,
15721576 this ,
15731577 ) ;
1574- let hm ;
1575- if ( ! hm1 && ! hm2 ) {
1578+ let hm : HalfMatchResult | undefined ;
1579+ if ( hm1 === null && hm2 === null ) {
15761580 return null ;
1577- } else if ( ! hm2 ) {
1578- hm = hm1 ;
1579- } else if ( ! hm1 ) {
1580- hm = hm2 ;
1581- } else {
1581+ } else if ( hm1 !== null && hm2 !== null ) {
15821582 // Both matched. Select the longest.
15831583 hm = hm1 [ 4 ] . length > hm2 [ 4 ] . length ? hm1 : hm2 ;
1584+ } else if ( hm1 !== null ) {
1585+ hm = hm1 ;
1586+ } else if ( hm2 !== null ) {
1587+ hm = hm2 ;
1588+ }
1589+
1590+ if ( hm === undefined ) {
1591+ throw new Error ( 'hm expected to be defined but was undefined' ) ;
15841592 }
15851593
15861594 // A half-match was found, sort out the return data.
@@ -1620,15 +1628,15 @@ export class DiffMatchPatch {
16201628 shorttext : string ,
16211629 i : number ,
16221630 dmp : DiffMatchPatch ,
1623- ) : string [ ] {
1631+ ) : HalfMatchResult | null {
16241632 // Start with a 1/4 length substring at position i as a seed.
16251633 const seed = longtext . substring ( i , i + Math . floor ( longtext . length / 4 ) ) ;
16261634 let j = - 1 ;
16271635 let best_common = '' ;
1628- let best_longtext_a ;
1629- let best_longtext_b ;
1630- let best_shorttext_a ;
1631- let best_shorttext_b ;
1636+ let best_longtext_a = '' ;
1637+ let best_longtext_b = '' ;
1638+ let best_shorttext_a = '' ;
1639+ let best_shorttext_b = '' ;
16321640 // tslint:disable-next-line:no-conditional-assignment
16331641 while ( ( j = shorttext . indexOf ( seed , j + 1 ) ) !== - 1 ) {
16341642 const prefixLength = dmp . diff_commonPrefix (
@@ -1657,9 +1665,9 @@ export class DiffMatchPatch {
16571665 best_shorttext_b ,
16581666 best_common ,
16591667 ] ;
1660- } else {
1661- return null ;
16621668 }
1669+
1670+ return null ;
16631671 }
16641672
16651673 /**
@@ -1679,13 +1687,13 @@ export class DiffMatchPatch {
16791687 * @return {number } The score.
16801688 * @private
16811689 */
1682- function diff_cleanupSemanticScore_ ( one : string , two : string ) : number {
1690+ const diff_cleanupSemanticScore_ = ( one : string , two : string ) : number => {
16831691 if ( ! one || ! two ) {
16841692 // Edges are the best.
16851693 return 6 ;
16861694 }
16871695
1688- const nonAlphaNumericRegex_ = new RegExp ( ' /[^a-zA-Z0-9]/' ) ;
1696+ const nonAlphaNumericRegex_ = / [ ^ a - z A - Z 0 - 9 ] / ;
16891697
16901698 // Each port of this function behaves slightly differently due to
16911699 // subtle differences in each language's definition of things like
@@ -1696,14 +1704,12 @@ export class DiffMatchPatch {
16961704 const char2 = two . charAt ( 0 ) ;
16971705 const nonAlphaNumeric1 = char1 . match ( nonAlphaNumericRegex_ ) ;
16981706 const nonAlphaNumeric2 = char2 . match ( nonAlphaNumericRegex_ ) ;
1699- const whitespace1 =
1700- nonAlphaNumeric1 && char1 . match ( this . whitespaceRegex_ ) ;
1701- const whitespace2 =
1702- nonAlphaNumeric2 && char2 . match ( this . whitespaceRegex_ ) ;
1703- const lineBreak1 = whitespace1 && char1 . match ( this . linebreakRegex_ ) ;
1704- const lineBreak2 = whitespace2 && char2 . match ( this . linebreakRegex_ ) ;
1705- const blankLine1 = lineBreak1 && one . match ( this . blanklineEndRegex_ ) ;
1706- const blankLine2 = lineBreak2 && two . match ( this . blanklineStartRegex_ ) ;
1707+ const whitespace1 = nonAlphaNumeric1 && char1 . match ( this . whitespaceRegex ) ;
1708+ const whitespace2 = nonAlphaNumeric2 && char2 . match ( this . whitespaceRegex ) ;
1709+ const lineBreak1 = whitespace1 && char1 . match ( this . linebreakRegex ) ;
1710+ const lineBreak2 = whitespace2 && char2 . match ( this . linebreakRegex ) ;
1711+ const blankLine1 = lineBreak1 && one . match ( this . blanklineEndRegex ) ;
1712+ const blankLine2 = lineBreak2 && two . match ( this . blanklineStartRegex ) ;
17071713
17081714 if ( blankLine1 || blankLine2 ) {
17091715 // Five points for blank lines.
@@ -1722,7 +1728,7 @@ export class DiffMatchPatch {
17221728 return 1 ;
17231729 }
17241730 return 0 ;
1725- }
1731+ } ;
17261732
17271733 let pointer = 1 ;
17281734 // Intentionally ignore the first and last element (don't need checking).
@@ -2038,6 +2044,12 @@ export class DiffMatchPatch {
20382044 // First pass: exact match.
20392045 rd [ j ] = ( ( rd [ j + 1 ] << 1 ) | 1 ) & charMatch ;
20402046 } else {
2047+ if ( last_rd === undefined ) {
2048+ throw new Error (
2049+ 'last_rd should have been set by the previous loop but is undefined' ,
2050+ ) ;
2051+ }
2052+
20412053 // Subsequent passes: fuzzy match.
20422054 rd [ j ] =
20432055 ( ( ( rd [ j + 1 ] << 1 ) | 1 ) & charMatch ) |
@@ -2146,22 +2158,7 @@ export class DiffMatchPatch {
21462158 * @return {!Array.<!diff_match_patch.PatchOperation> } Array of Patch objects.
21472159 */
21482160 private patch_deepCopy ( patches : PatchOperation [ ] ) : PatchOperation [ ] {
2149- // Making deep copies is hard in JavaScript.
2150- const patchesCopy = [ ] ;
2151- for ( let x = 0 ; x < patches . length ; x ++ ) {
2152- const patch = patches [ x ] ;
2153- const patchCopy = new PatchOperation ( ) ;
2154- patchCopy . diffs = [ ] ;
2155- for ( let y = 0 ; y < patch . diffs . length ; y ++ ) {
2156- patchCopy . diffs [ y ] = [ patch . diffs [ y ] [ 0 ] , patch . diffs [ y ] [ 1 ] ] ;
2157- }
2158- patchCopy . start1 = patch . start1 ;
2159- patchCopy . start2 = patch . start2 ;
2160- patchCopy . length1 = patch . length1 ;
2161- patchCopy . length2 = patch . length2 ;
2162- patchesCopy [ x ] = patchCopy ;
2163- }
2164- return patchesCopy ;
2161+ return patches . map ( ( x ) => x . clone ( ) ) ;
21652162 }
21662163
21672164 /**
@@ -2237,15 +2234,15 @@ export class DiffMatchPatch {
22372234 const bigpatch = patches [ x ] ;
22382235 // Remove the big old patch.
22392236 patches . splice ( x -- , 1 ) ;
2240- let start1 = bigpatch . start1 ;
2241- let start2 = bigpatch . start2 ;
2237+ let { start1, start2 } = bigpatch ;
22422238 let precontext = '' ;
22432239 while ( bigpatch . diffs . length !== 0 ) {
22442240 // Create one of several smaller patches.
2245- const patch = new PatchOperation ( ) ;
2241+ const patch = new PatchOperation (
2242+ start1 - precontext . length ,
2243+ start2 - precontext . length ,
2244+ ) ;
22462245 let empty = true ;
2247- patch . start1 = start1 - precontext . length ;
2248- patch . start2 = start2 - precontext . length ;
22492246 if ( precontext !== '' ) {
22502247 patch . length1 = patch . length2 = precontext . length ;
22512248 patch . diffs . push ( [ DiffOp . Equal , precontext ] ) ;
@@ -2260,7 +2257,7 @@ export class DiffMatchPatch {
22602257 // Insertions are harmless.
22612258 patch . length2 += diff_text . length ;
22622259 start2 += diff_text . length ;
2263- patch . diffs . push ( bigpatch . diffs . shift ( ) ) ;
2260+ patch . diffs . push ( bigpatch . diffs . shift ( ) ! ) ;
22642261 empty = false ;
22652262 } else if (
22662263 diff_type === DiffOp . Delete &&
0 commit comments