/**
 * 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 } from './types' ; const concatenateRelevantDiffs = ( op , diffs , changeColor ) : string => diffs . reduce ( ( reduced , diff ) : string => reduced + ( diff [ 0 ] === DIFF_EQUAL ? diff [ 1 ] : diff [ 0 ] === op && diff [ 1 ] . length !== 0 ? changeColor ( diff [ 1 ] ) : '' ) , '' ) ; class ChangeBuffer { private op : number ; private line : Array < Diff > ; private lines : Array < Diff > ; private changeColor : DiffOptionsColor ; constructor ( op , changeColor ) { this . op = op ; this . line = [ ] ; this . lines = [ ] ; this . changeColor = changeColor ; } private pushSubstring ( substring ) { this . pushDiff ( new Diff ( this . op , substring ) ) ; } private pushLine ( ) { this . lines . push ( this . line . length !== 1 ? new Diff ( this . op , concatenateRelevantDiffs ( this . op , this . line , this . changeColor ) ) : this . line [ 0 ] [ 0 ] === this . op ? this . line [ 0 ] : new Diff ( this . op , this . line [ 0 ] [ 1 ] ) ) ; this . line . length = 0 ; } isLineEmpty ( ) { return this . line . length === 0 ; } pushDiff ( diff ) { this . line . push ( diff ) ; } align ( diff ) { const string = diff [ 1 ] ; if ( string . includes ( '\n' ) ) { const substrings = string . split ( '\n' ) ; const iLast = substrings . length - 1 ; substrings . forEach ( ( substring , i ) => { if ( i < iLast ) { this . pushSubstring ( substring ) ; this . pushLine ( ) ; } else if ( substring . length !== 0 ) { this . pushSubstring ( substring ) ; } } ) ; } else { this . pushDiff ( diff ) ; } } moveLinesTo ( lines ) { if ( ! this . isLineEmpty ( ) ) { this . pushLine ( ) ; } lines . push ( ... this . lines ) ; this . lines . length = 0 ; } } class CommonBuffer { private deleteBuffer : ChangeBuffer ; private insertBuffer : ChangeBuffer ; private lines : Array < Diff > ; constructor ( deleteBuffer , insertBuffer ) { this . deleteBuffer = deleteBuffer ; this . insertBuffer = insertBuffer ; this . lines = [ ] ; } private pushDiffCommonLine ( diff ) { this . lines . push ( diff ) ; } private pushDiffChangeLines ( diff ) { const isDiffEmpty = diff [ 1 ] . length === 0 ; if ( ! isDiffEmpty || this . deleteBuffer . isLineEmpty ( ) ) { this . deleteBuffer . pushDiff ( diff ) ; } if ( ! isDiffEmpty || this . insertBuffer . isLineEmpty ( ) ) { this . insertBuffer . pushDiff ( diff ) ; } } private flushChangeLines ( ) { this . deleteBuffer . moveLinesTo ( this . lines ) ; this . insertBuffer . moveLinesTo ( this . lines ) ; } align ( diff ) { const op = diff [ 0 ] ; const string = diff [ 1 ] ; if ( string . includes ( '\n' ) ) { const substrings = string . split ( '\n' ) ; const iLast = substrings . length - 1 ; substrings . forEach ( ( substring , i ) => { if ( i === 0 ) { const subdiff = new Diff ( op , substring ) ; if ( this . deleteBuffer . isLineEmpty ( ) && this . insertBuffer . isLineEmpty ( ) ) { this . flushChangeLines ( ) ; this . pushDiffCommonLine ( subdiff ) ; } else { this . pushDiffChangeLines ( subdiff ) ; this . flushChangeLines ( ) ; } } else if ( i < iLast ) { this . pushDiffCommonLine ( new Diff ( op , substring ) ) ; } else if ( substring . length !== 0 ) { this . pushDiffChangeLines ( new Diff ( op , substring ) ) ; } } ) ; } else { this . pushDiffChangeLines ( diff ) ; } } getLines ( ) { this . flushChangeLines ( ) ; return this . lines ; } } const getAlignedDiffs = ( diffs , changeColor ) : Array < Diff > => { const deleteBuffer = new ChangeBuffer ( DIFF_DELETE , changeColor ) ; const insertBuffer = new ChangeBuffer ( DIFF_INSERT , changeColor ) ; const commonBuffer = new CommonBuffer ( deleteBuffer , insertBuffer ) ; diffs . forEach ( ( diff ) => { switch ( diff [ 0 ] ) { case DIFF_DELETE : deleteBuffer . align ( diff ) ; break ; case DIFF_INSERT : insertBuffer . align ( diff ) ; break ; default : commonBuffer . align ( diff ) ; } } ) ; return commonBuffer . getLines ( ) ; } ; export default getAlignedDiffs ;