/**
 * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */ import { DIFF_DELETE , DIFF_EQUAL , DIFF_INSERT , Diff } from './cleanupSemantic' ; import type { DiffOptionsColor , DiffOptionsNormalized } from './types' ; const formatTrailingSpaces = ( line , trailingSpaceFormatter ) : string => line . replace ( /\s+$/ , ( match ) => trailingSpaceFormatter ( match ) ) ; const printDiffLine = ( line , isFirstOrLast , color , indicator , trailingSpaceFormatter , emptyFirstOrLastLinePlaceholder ) : string => line . length !== 0 ? color ( indicator + ' ' + formatTrailingSpaces ( line , trailingSpaceFormatter ) ) : indicator !== ' ' ? color ( indicator ) : isFirstOrLast && emptyFirstOrLastLinePlaceholder . length !== 0 ? color ( indicator + ' ' + emptyFirstOrLastLinePlaceholder ) : '' ; const printDeleteLine = ( line , isFirstOrLast , { aColor , aIndicator , changeLineTrailingSpaceColor , emptyFirstOrLastLinePlaceholder , } ) : string => printDiffLine ( line , isFirstOrLast , aColor , aIndicator , changeLineTrailingSpaceColor , emptyFirstOrLastLinePlaceholder ) ; const printInsertLine = ( line , isFirstOrLast , { bColor , bIndicator , changeLineTrailingSpaceColor , emptyFirstOrLastLinePlaceholder , } ) : string => printDiffLine ( line , isFirstOrLast , bColor , bIndicator , changeLineTrailingSpaceColor , emptyFirstOrLastLinePlaceholder ) ; const printCommonLine = ( line , isFirstOrLast , { commonColor , commonIndicator , commonLineTrailingSpaceColor , emptyFirstOrLastLinePlaceholder , } ) : string => printDiffLine ( line , isFirstOrLast , commonColor , commonIndicator , commonLineTrailingSpaceColor , emptyFirstOrLastLinePlaceholder ) ; const createPatchMark = ( aStart , aEnd , bStart , bEnd , { patchColor } ) : string => patchColor ( `@@ -${ aStart + 1 },${ aEnd - aStart } +${ bStart + 1 },${ bEnd - bStart } @@` ) ; export const joinAlignedDiffsNoExpand = ( diffs , options ) : string => { const iLength = diffs . length ; const nContextLines = options . contextLines ; const nContextLines2 = nContextLines + nContextLines ; let jLength = iLength ; let hasExcessAtStartOrEnd = false ; let nExcessesBetweenChanges = 0 ; let i = 0 ; while ( i !== iLength ) { const iStart = i ; while ( i !== iLength && diffs [ i ] [ 0 ] === DIFF_EQUAL ) { i += 1 ; } if ( iStart !== i ) { if ( iStart === 0 ) { if ( i > nContextLines ) { jLength -= i - nContextLines ; hasExcessAtStartOrEnd = true ; } } else if ( i === iLength ) { const n = i - iStart ; if ( n > nContextLines ) { jLength -= n - nContextLines ; hasExcessAtStartOrEnd = true ; } } else { const n = i - iStart ; if ( n > nContextLines2 ) { jLength -= n - nContextLines2 ; nExcessesBetweenChanges += 1 ; } } } while ( i !== iLength && diffs [ i ] [ 0 ] !== DIFF_EQUAL ) { i += 1 ; } } const hasPatch = nExcessesBetweenChanges !== 0 || hasExcessAtStartOrEnd ; if ( nExcessesBetweenChanges !== 0 ) { jLength += nExcessesBetweenChanges + 1 ; } else if ( hasExcessAtStartOrEnd ) { jLength += 1 ; } const jLast = jLength - 1 ; const lines = [ ] ; let jPatchMark = 0 ; if ( hasPatch ) { lines . push ( '' ) ; } let aStart = 0 ; let bStart = 0 ; let aEnd = 0 ; let bEnd = 0 ; const pushCommonLine = ( line ) : void => { const j = lines . length ; lines . push ( printCommonLine ( line , j === 0 || j === jLast , options ) ) ; aEnd += 1 ; bEnd += 1 ; } ; const pushDeleteLine = ( line ) : void => { const j = lines . length ; lines . push ( printDeleteLine ( line , j === 0 || j === jLast , options ) ) ; aEnd += 1 ; } ; const pushInsertLine = ( line ) : void => { const j = lines . length ; lines . push ( printInsertLine ( line , j === 0 || j === jLast , options ) ) ; bEnd += 1 ; } ; i = 0 ; while ( i !== iLength ) { let iStart = i ; while ( i !== iLength && diffs [ i ] [ 0 ] === DIFF_EQUAL ) { i += 1 ; } if ( iStart !== i ) { if ( iStart === 0 ) { if ( i > nContextLines ) { iStart = i - nContextLines ; aStart = iStart ; bStart = iStart ; aEnd = aStart ; bEnd = bStart ; } for ( let iCommon = iStart ; iCommon !== i ; iCommon += 1 ) { pushCommonLine ( diffs [ iCommon ] [ 1 ] ) ; } } else if ( i === iLength ) { const iEnd = i - iStart > nContextLines ? iStart + nContextLines : i ; for ( let iCommon = iStart ; iCommon !== iEnd ; iCommon += 1 ) { pushCommonLine ( diffs [ iCommon ] [ 1 ] ) ; } } else { const nCommon = i - iStart ; if ( nCommon > nContextLines2 ) { const iEnd = iStart + nContextLines ; for ( let iCommon = iStart ; iCommon !== iEnd ; iCommon += 1 ) { pushCommonLine ( diffs [ iCommon ] [ 1 ] ) ; } lines [ jPatchMark ] = createPatchMark ( aStart , aEnd , bStart , bEnd , options ) ; jPatchMark = lines . length ; lines . push ( '' ) ; const nOmit = nCommon - nContextLines2 ; aStart = aEnd + nOmit ; bStart = bEnd + nOmit ; aEnd = aStart ; bEnd = bStart ; for ( let iCommon = i - nContextLines ; iCommon !== i ; iCommon += 1 ) { pushCommonLine ( diffs [ iCommon ] [ 1 ] ) ; } } else { for ( let iCommon = iStart ; iCommon !== i ; iCommon += 1 ) { pushCommonLine ( diffs [ iCommon ] [ 1 ] ) ; } } } } while ( i !== iLength && diffs [ i ] [ 0 ] === DIFF_DELETE ) { pushDeleteLine ( diffs [ i ] [ 1 ] ) ; i += 1 ; } while ( i !== iLength && diffs [ i ] [ 0 ] === DIFF_INSERT ) { pushInsertLine ( diffs [ i ] [ 1 ] ) ; i += 1 ; } } if ( hasPatch ) { lines [ jPatchMark ] = createPatchMark ( aStart , aEnd , bStart , bEnd , options ) ; } return lines . join ( '\n' ) ; } ; export const joinAlignedDiffsExpand = ( diffs , options ) : string => diffs . map ( ( diff , i , diffs ) : string => { const line = diff [ 1 ] ; const isFirstOrLast = i === 0 || i === diffs . length - 1 ; switch ( diff [ 0 ] ) { case DIFF_DELETE : return printDeleteLine ( line , isFirstOrLast , options ) ; case DIFF_INSERT : return printInsertLine ( line , isFirstOrLast , options ) ; default : return printCommonLine ( line , isFirstOrLast , options ) ; } } ) . join ( '\n' ) ;