1- import * as Diff from 'diff'
1+ import { diff_match_patch as DiffMatchPatch } from 'diff-match-patch '
22import hljs from './highlight'
33
44import type { Ref } from 'vue'
5- import type { Change } from 'diff'
5+ import type { Diff } from 'diff-match-patch '
66
77type Mode = 'split' | 'unified'
88type Theme = 'dark' | 'light' | 'custom'
99type Role = 'prev' | 'current' | 'unified'
1010
11+ enum Type {
12+ removed = - 1 ,
13+ equal = 0 ,
14+ added = 1 ,
15+ disabled = 2
16+ }
17+
1118interface Line {
12- type : 'added' | 'removed' | 'equal' | 'disabled' ;
19+ type : string ;
1320 lineNum ?: number ;
1421 value ?: string ;
1522 chkWords ?: boolean ;
1623}
1724
1825type Lines = Array < Line >
19- type Diffs = Array < Change >
26+ type Diffs = Array < Diff >
2027
2128const MODIFIED_START_TAG = '<vue-diff-modified>'
2229const MODIFIED_CLOSE_TAG = '</vue-diff-modified>'
@@ -25,9 +32,9 @@ const MODIFIED_CLOSE_TAG = '</vue-diff-modified>'
2532 * Get diff type
2633 * @param diff
2734 */
28- const getDiffType = ( diff : Change ) => {
29- if ( ! diff . count ) return 'disabled'
30- return diff . added ? 'added' : diff . removed ? 'removed' : 'equal'
35+ const getDiffType = ( type : Type ) => {
36+ if ( ! Type [ type ] ) return 'disabled'
37+ return Type [ type ]
3138}
3239
3340/**
@@ -42,28 +49,28 @@ const getSplitLines = (diffsMap: Array<Diffs>): Array<Lines> => {
4249 }
4350
4451 diffsMap . map ( ( diffs ) => {
45- const prevLines = diffs [ 0 ] . value . replace ( / \n $ / , '' ) . split ( '\n' )
46- const currentLines = diffs [ 1 ] . value . replace ( / \n $ / , '' ) . split ( '\n' )
52+ const prevLines = diffs [ 0 ] [ 1 ] . replace ( / \n $ / , '' ) . split ( '\n' )
53+ const currentLines = diffs [ 1 ] [ 1 ] . replace ( / \n $ / , '' ) . split ( '\n' )
4754 const loopCount = Math . max ( prevLines . length , currentLines . length )
4855
4956 for ( let i = 0 ; i < loopCount ; i ++ ) {
50- const hasPrevLine = getDiffType ( diffs [ 0 ] ) !== 'disabled'
51- const hasCurrentLine = getDiffType ( diffs [ 1 ] ) !== 'disabled'
57+ const hasPrevLine = getDiffType ( diffs [ 0 ] [ 0 ] ) !== 'disabled' && typeof prevLines [ i ] !== 'undefined '
58+ const hasCurrentLine = getDiffType ( diffs [ 1 ] [ 0 ] ) !== 'disabled' && typeof currentLines [ i ] !== 'undefined '
5259
5360 if ( hasPrevLine ) lineNum . prev = lineNum . prev + 1
5461 if ( hasCurrentLine ) lineNum . current = lineNum . current + 1
5562
56- const chkWords = Boolean ( diffs [ 0 ] . count === diffs [ 1 ] . count && getDiffType ( diffs [ 0 ] ) . match ( / a d d e d | r e m o v e d / ) && getDiffType ( diffs [ 1 ] ) . match ( / a d d e d | r e m o v e d / ) )
63+ const chkWords = Boolean ( getDiffType ( diffs [ 0 ] [ 0 ] ) . match ( / a d d e d | r e m o v e d / ) && getDiffType ( diffs [ 1 ] [ 0 ] ) . match ( / a d d e d | r e m o v e d / ) )
5764
5865 result . push ( [
5966 {
60- type : getDiffType ( diffs [ 0 ] ) ,
67+ type : hasPrevLine ? getDiffType ( diffs [ 0 ] [ 0 ] ) : 'disabled' ,
6168 lineNum : hasPrevLine ? lineNum . prev : undefined ,
6269 value : hasPrevLine ? prevLines [ i ] : undefined ,
6370 chkWords
6471 } ,
6572 {
66- type : getDiffType ( diffs [ 1 ] ) ,
73+ type : hasCurrentLine ? getDiffType ( diffs [ 1 ] [ 0 ] ) : 'disabled' ,
6774 lineNum : hasCurrentLine ? lineNum . current : undefined ,
6875 value : hasCurrentLine ? currentLines [ i ] : undefined ,
6976 chkWords
@@ -84,33 +91,33 @@ const getUnifiedLines = (diffsMap: Array<Diffs>): Array<Lines> => {
8491 let lineNum = 0
8592
8693 diffsMap . map ( ( diffs ) => {
87- const prevLines = diffs [ 0 ] . value . replace ( / \n $ / , '' ) . split ( '\n' )
88- const currentLines = diffs [ 1 ] . value . replace ( / \n $ / , '' ) . split ( '\n' )
94+ const prevLines = diffs [ 0 ] [ 1 ] . replace ( / \n $ / , '' ) . split ( '\n' )
95+ const currentLines = diffs [ 1 ] [ 1 ] . replace ( / \n $ / , '' ) . split ( '\n' )
8996
9097 prevLines . map ( value => {
91- const type = getDiffType ( diffs [ 0 ] )
98+ const type = getDiffType ( diffs [ 0 ] [ 0 ] )
9299
93100 if ( type !== 'removed' ) return
94101
95102 result . push ( [
96103 {
97- type : getDiffType ( diffs [ 0 ] ) ,
104+ type : getDiffType ( diffs [ 0 ] [ 0 ] ) ,
98105 lineNum : undefined ,
99106 value : value
100107 }
101108 ] )
102109 } )
103110
104111 currentLines . map ( value => {
105- const type = getDiffType ( diffs [ 1 ] )
112+ const type = getDiffType ( diffs [ 1 ] [ 0 ] )
106113
107114 if ( type === 'disabled' ) return
108115
109116 lineNum = lineNum + 1
110117
111118 result . push ( [
112119 {
113- type : getDiffType ( diffs [ 1 ] ) ,
120+ type : getDiffType ( diffs [ 1 ] [ 0 ] ) ,
114121 lineNum,
115122 value : value
116123 }
@@ -128,11 +135,22 @@ const getUnifiedLines = (diffsMap: Array<Diffs>): Array<Lines> => {
128135 * @param current
129136 */
130137const renderLines = ( mode : Mode , prev : string , current : string ) : Array < Lines > => {
138+ function diffLines ( prev : string , current : string ) {
139+ const dmp = new DiffMatchPatch ( )
140+ const a = dmp . diff_linesToChars_ ( prev , current )
141+ const linePrev = a . chars1
142+ const lineCurrent = a . chars2
143+ const lineArray = a . lineArray
144+ const diffs = dmp . diff_main ( linePrev , lineCurrent , false )
145+ dmp . diff_charsToLines_ ( diffs , lineArray )
146+ return diffs
147+ }
148+
131149 /**
132150 * stacked prev, current data
133151 */
134- const diffsMap = Diff . diffLines ( prev , current ) . reduce ( ( acc : Array < Diffs > , curr ) => {
135- const type = getDiffType ( curr )
152+ const diffsMap = diffLines ( prev , current ) . reduce ( ( acc : Array < Diffs > , curr ) => {
153+ const type = getDiffType ( curr [ 0 ] )
136154
137155 if ( type === 'equal' ) {
138156 acc . push ( [ curr ] ) // Push index 0
@@ -143,7 +161,8 @@ const renderLines = (mode: Mode, prev: string, current: string): Array<Lines> =>
143161 }
144162
145163 if ( type === 'added' ) {
146- if ( acc . length && acc [ acc . length - 1 ] [ 0 ] && acc [ acc . length - 1 ] [ 0 ] . removed ) {
164+ const prev = acc . length && acc [ acc . length - 1 ] [ 0 ] ? acc [ acc . length - 1 ] [ 0 ] : null
165+ if ( prev && getDiffType ( prev [ 0 ] ) === 'removed' ) {
147166 acc [ acc . length - 1 ] . push ( curr ) // Push index 1 if index 0 has removed data in last array
148167 } else {
149168 acc . push ( [ curr ] ) // Push index 0
@@ -159,14 +178,14 @@ const renderLines = (mode: Mode, prev: string, current: string): Array<Lines> =>
159178 diffsMap . map ( ( diffs ) => {
160179 if ( diffs . length > 1 ) return // Return if has index 0, 1
161180
162- const type = getDiffType ( diffs [ 0 ] )
181+ const type = getDiffType ( diffs [ 0 ] [ 0 ] )
163182
164183 if ( type === 'added' ) {
165- diffs . unshift ( { value : '' } ) // Set empty data
184+ diffs . unshift ( [ 2 , '' ] ) // Set empty data
166185 } else if ( type === 'removed' ) {
167- diffs . push ( { value : '' } ) // Set empty data
186+ diffs . push ( [ 2 , '' ] ) // Set empty data
168187 } else if ( type === 'equal' ) {
169- diffs . push ( { ...diffs [ 0 ] } ) // Set same data
188+ diffs . push ( [ ...diffs [ 0 ] ] ) // Set same data
170189 }
171190 } )
172191
@@ -191,8 +210,11 @@ const renderWords = (prev: string, current: string) => {
191210 /**
192211 * Set modified tags in changed words (removed -> added)
193212 */
194- return Diff . diffWords ( prev , current ) . filter ( word => getDiffType ( word ) !== 'removed' ) . map ( word => {
195- return getDiffType ( word ) === 'added' ? `${ MODIFIED_START_TAG } ${ word . value } ${ MODIFIED_CLOSE_TAG } ` : word . value
213+ const dmp = new DiffMatchPatch ( )
214+ const diff = dmp . diff_main ( prev , current )
215+ dmp . diff_cleanupSemantic ( diff )
216+ return diff . filter ( result => getDiffType ( result [ 0 ] ) !== 'removed' ) . map ( result => {
217+ return getDiffType ( result [ 0 ] ) === 'added' ? `${ MODIFIED_START_TAG } ${ result [ 1 ] } ${ MODIFIED_CLOSE_TAG } ` : result [ 1 ]
196218 } ) . join ( '' )
197219}
198220
@@ -269,4 +291,4 @@ const setHighlightCode = ({ highlightCode, language, code }: { highlightCode: Re
269291}
270292
271293export { MODIFIED_START_TAG , MODIFIED_CLOSE_TAG , getDiffType , getSplitLines , getUnifiedLines , renderLines , renderWords , setHighlightCode }
272- export type { Mode , Theme , Role , Change , Lines , Line }
294+ export type { Mode , Theme , Role , Lines , Line }
0 commit comments