1+ import { useMemo } from 'react' ;
12import styled from '@emotion/styled' ;
23import type { Change } from 'diff' ;
34import { diffChars , diffLines , diffWords } from 'diff' ;
@@ -23,31 +24,76 @@ type Props = {
2324 type ?: keyof typeof diffFnMap ;
2425} ;
2526
27+ // this function splits the lines from diffLines into words that are diffed
28+ function getDisplayData (
29+ line : Change [ ] ,
30+ highlightAdded : Change | undefined ,
31+ highlightRemoved : Change | undefined
32+ ) : Change [ ] {
33+ if ( ! highlightAdded && ! highlightRemoved ) {
34+ return line ;
35+ }
36+
37+ const leftText = line . reduce (
38+ ( acc , result ) => ( result . added ? acc : acc + result . value ) ,
39+ ''
40+ ) ;
41+ const rightText = line . reduce (
42+ ( acc , result ) => ( result . removed ? acc : acc + result . value ) ,
43+ ''
44+ ) ;
45+
46+ if ( ! leftText && ! rightText ) {
47+ return line ;
48+ }
49+
50+ return diffWords ( leftText , rightText ) ;
51+ }
52+
2653function SplitDiff ( { className, type = 'lines' , base, target} : Props ) {
2754 const diffFn = diffFnMap [ type ] ;
2855
29- const baseLines = base . split ( '\n' ) ;
30- const targetLines = target . split ( '\n' ) ;
31- const [ largerArray ] =
32- baseLines . length > targetLines . length
33- ? [ baseLines , targetLines ]
34- : [ targetLines , baseLines ] ;
35- const results = largerArray . map ( ( _line , index ) =>
36- diffFn ( baseLines [ index ] || '' , targetLines [ index ] || '' , { newlineIsToken : true } )
37- ) ;
56+ const results = diffFn ( base , target , { newlineIsToken : true } ) ;
57+
58+ // split one change that includes multiple lines into one change per line (for formatting)
59+ const groupedChanges = useMemo ( ( ) : Change [ ] [ ] => {
60+ let currentLine : Change [ ] = [ ] ;
61+ const processedLines : Change [ ] [ ] = [ ] ;
62+ for ( const change of results ) {
63+ const lines = change . value . split ( '\n' ) ;
64+ for ( let i = 0 ; i < lines . length ; i ++ ) {
65+ const lineValue = lines [ i ] ;
66+ if ( lineValue !== undefined && lineValue !== '' ) {
67+ currentLine . push ( {
68+ value : lineValue ,
69+ added : change . added ,
70+ removed : change . removed ,
71+ } ) ;
72+ }
73+ if ( i < lines . length - 1 ) {
74+ processedLines . push ( currentLine ) ;
75+ currentLine = [ ] ;
76+ }
77+ }
78+ }
79+ if ( currentLine . length > 0 ) {
80+ processedLines . push ( currentLine ) ;
81+ }
82+ return processedLines ;
83+ } , [ results ] ) ;
3884
3985 return (
4086 < SplitTable className = { className } data-test-id = "split-diff" >
4187 < SplitBody >
42- { results . map ( ( line , j ) => {
88+ { groupedChanges . map ( ( line , j ) => {
4389 const highlightAdded = line . find ( result => result . added ) ;
4490 const highlightRemoved = line . find ( result => result . removed ) ;
4591
4692 return (
4793 < tr key = { j } >
4894 < Cell isRemoved = { highlightRemoved } >
4995 < Line >
50- { line
96+ { getDisplayData ( line , highlightAdded , highlightRemoved )
5197 . filter ( result => ! result . added )
5298 . map ( ( result , i ) => (
5399 < Word key = { i } isRemoved = { result . removed } >
@@ -61,7 +107,7 @@ function SplitDiff({className, type = 'lines', base, target}: Props) {
61107
62108 < Cell isAdded = { highlightAdded } >
63109 < Line >
64- { line
110+ { getDisplayData ( line , highlightAdded , highlightRemoved )
65111 . filter ( result => ! result . removed )
66112 . map ( ( result , i ) => (
67113 < Word key = { i } isAdded = { result . added } >
0 commit comments