1- const TYPE = { UNCHANGED : 'unchanged' , ADDED : 'added' , REMOVED : 'removed' , MODIFIED : 'modified' }
1+ const TYPE = { UNCHANGED : 'unchanged' , ADDED : 'added' , REMOVED : 'removed' , MODIFIED : 'modified' } ;
22
33const typeOf = ( v ) => {
44 if ( v === null ) return 'null' ;
@@ -8,9 +8,9 @@ const typeOf = (v) => {
88
99const isObj = ( v ) => v !== null && typeof v === 'object' ;
1010
11- const keys = ( a , b ) => [ ...new Set ( [ ...Object . keys ( a || { } ) , ...Object . keys ( b || { } ) ] ) ] ;
11+ const allKeys = ( a , b ) => [ ...new Set ( [ ...Object . keys ( a || { } ) , ...Object . keys ( b || { } ) ] ) ] ;
1212
13- const node = ( key , type , left , right , extra = { } ) => ( {
13+ const createNode = ( key , type , left , right , extra = { } ) => ( {
1414 key,
1515 type,
1616 left,
@@ -19,50 +19,68 @@ const node = (key, type, left, right, extra = {}) => ({
1919 ...extra
2020} ) ;
2121
22- const container = ( val , isArr ) => {
23- if ( isArr ) return { isArray : true } ;
22+ const getContainerProps = ( val ) => {
23+ if ( Array . isArray ( val ) ) return { isArray : true } ;
2424 if ( isObj ( val ) ) return { isObject : true } ;
2525 return { } ;
2626} ;
2727
28- const childMap = ( val , side ) => ( v , k ) => node (
29- k , TYPE . UNCHANGED ,
30- side === 'added' ? undefined : v ,
31- side === 'added' ? v : undefined ,
32- isObj ( v ) && { children : mapChildren ( v , side ) , ...container ( v , Array . isArray ( v ) ) }
33- )
28+ const mapChildrenForSide = ( val , side ) => {
29+ const createChildNode = ( value , key ) => {
30+ const leftValue = side === 'added' ? undefined : value ;
31+ const rightValue = side === 'added' ? value : undefined ;
32+ const childExtra = isObj ( value ) ? {
33+ children : mapChildrenForSide ( value , side ) ,
34+ ...getContainerProps ( value )
35+ } : { } ;
36+ return createNode ( key , TYPE . UNCHANGED , leftValue , rightValue , childExtra ) ;
37+ } ;
3438
35- const mapChildren = ( val , side ) => {
36- if ( Array . isArray ( val ) ) return val . map ( childMap ( val , side ) ) ;
37- if ( isObj ( val ) ) return Object . entries ( val ) . map ( ( [ k , v ] ) => childMap ( val , side ) ( v , k ) ) ;
39+ if ( Array . isArray ( val ) ) {
40+ return val . map ( ( item , index ) => createChildNode ( item , index ) ) ;
41+ }
42+ if ( isObj ( val ) ) {
43+ return Object . entries ( val ) . map ( ( [ k , v ] ) => createChildNode ( v , k ) ) ;
44+ }
3845 return [ ] ;
3946} ;
4047
4148const diffContainer = ( left , right , key , isArr ) => {
4249 const items = isArr
4350 ? Array . from ( { length : Math . max ( left ?. length || 0 , right ?. length || 0 ) } , ( _ , i ) => diff ( left ?. [ i ] , right ?. [ i ] , i ) )
44- : keys ( left , right ) . map ( k => diff ( left ?. [ k ] , right ?. [ k ] , k ) )
45- const hasDiff = items . some ( c => c . hasDiff )
46- return node ( key , hasDiff ? TYPE . MODIFIED : TYPE . UNCHANGED , left , right , { children : items , ...container ( left , isArr ) } )
47- }
51+ : allKeys ( left , right ) . map ( k => diff ( left ?. [ k ] , right ?. [ k ] , k ) ) ;
52+ const hasDiff = items . some ( c => c . hasDiff ) ;
53+ return createNode ( key , hasDiff ? TYPE . MODIFIED : TYPE . UNCHANGED , left , right , {
54+ children : items ,
55+ ...getContainerProps ( left )
56+ } ) ;
57+ } ;
4858
4959const diff = ( left , right , key = 'root' ) => {
5060 if ( left === undefined ) {
51- const extra = isObj ( right ) ? { children : mapChildren ( right , 'added' ) , ...container ( right , Array . isArray ( right ) ) } : { } ;
52- return node ( key , TYPE . ADDED , left , right , extra ) ;
61+ const extra = isObj ( right ) ? {
62+ children : mapChildrenForSide ( right , 'added' ) ,
63+ ...getContainerProps ( right )
64+ } : { } ;
65+ return createNode ( key , TYPE . ADDED , left , right , extra ) ;
5366 }
5467 if ( right === undefined ) {
55- const extra = isObj ( left ) ? { children : mapChildren ( left , 'removed' ) , ...container ( left , Array . isArray ( left ) ) } : { } ;
56- return node ( key , TYPE . REMOVED , left , right , extra ) ;
68+ const extra = isObj ( left ) ? {
69+ children : mapChildrenForSide ( left , 'removed' ) ,
70+ ...getContainerProps ( left )
71+ } : { } ;
72+ return createNode ( key , TYPE . REMOVED , left , right , extra ) ;
5773 }
5874 if ( ! isObj ( left ) && ! isObj ( right ) ) {
59- if ( left === right ) return node ( key , TYPE . UNCHANGED , left , right ) ;
60- return node ( key , TYPE . MODIFIED , left , right ) ;
75+ return createNode ( key , left === right ? TYPE . UNCHANGED : TYPE . MODIFIED , left , right ) ;
6176 }
6277 if ( typeOf ( left ) !== typeOf ( right ) ) {
63- return node ( key , TYPE . MODIFIED , left , right , { children : [ ] , ...container ( left , Array . isArray ( left ) ) } ) ;
78+ return createNode ( key , TYPE . MODIFIED , left , right , {
79+ children : [ ] ,
80+ ...getContainerProps ( left )
81+ } ) ;
6482 }
6583 return diffContainer ( left , right , key , Array . isArray ( left ) ) ;
6684} ;
6785
68- export { diff , TYPE }
86+ export { diff , TYPE } ;
0 commit comments