@@ -14,25 +14,38 @@ function getLeanDiff(
1414 showOnly : ObjectDiffOptions [ "showOnly" ] = DEFAULT_OBJECT_DIFF_OPTIONS . showOnly ,
1515) : ObjectDiff [ "diff" ] {
1616 const { statuses, granularity } = showOnly ;
17+ const statusesSet = new Set ( statuses ) ;
1718 const res : ObjectDiff [ "diff" ] = [ ] ;
19+ const deep = granularity === Granularity . DEEP ;
1820 for ( let i = 0 ; i < diff . length ; i ++ ) {
19- const value = diff [ i ] ;
20- if ( granularity === Granularity . DEEP && value . diff ) {
21- const leanDiff = getLeanDiff ( value . diff , showOnly ) ;
22- if ( leanDiff . length > 0 ) {
23- res . push ( { ...value , diff : leanDiff } ) ;
21+ const entry = diff [ i ] ;
22+ if ( deep && entry . diff ) {
23+ const sub = getLeanDiff ( entry . diff , showOnly ) ;
24+ if ( sub . length > 0 ) {
25+ res . push ( {
26+ property : entry . property ,
27+ previousValue : entry . previousValue ,
28+ currentValue : entry . currentValue ,
29+ status : entry . status ,
30+ diff : sub ,
31+ } ) ;
2432 }
25- } else if ( statuses . includes ( value . status ) ) {
26- res . push ( value ) ;
33+ continue ;
34+ }
35+ if ( statusesSet . has ( entry . status ) ) {
36+ res . push ( entry ) ;
2737 }
2838 }
2939 return res ;
3040}
3141
3242function getObjectStatus ( diff : ObjectDiff [ "diff" ] ) : ObjectStatus {
33- return diff . some ( ( property ) => property . status !== ObjectStatus . EQUAL )
34- ? ObjectStatus . UPDATED
35- : ObjectStatus . EQUAL ;
43+ for ( let i = 0 ; i < diff . length ; i ++ ) {
44+ if ( diff [ i ] . status !== ObjectStatus . EQUAL ) {
45+ return ObjectStatus . UPDATED ;
46+ }
47+ }
48+ return ObjectStatus . EQUAL ;
3649}
3750
3851function formatSingleObjectDiff (
@@ -41,123 +54,117 @@ function formatSingleObjectDiff(
4154 options : ObjectDiffOptions = DEFAULT_OBJECT_DIFF_OPTIONS ,
4255) : ObjectDiff {
4356 if ( ! data ) {
44- return {
45- type : "object" ,
46- status : ObjectStatus . EQUAL ,
47- diff : [ ] ,
48- } ;
57+ return { type : "object" , status : ObjectStatus . EQUAL , diff : [ ] } ;
4958 }
5059 const diff : ObjectDiff [ "diff" ] = [ ] ;
51-
52- for ( const [ property , value ] of Object . entries ( data ) ) {
60+ const added = status === ObjectStatus . ADDED ;
61+ for ( const key in data ) {
62+ const value = data [ key ] ;
5363 if ( isObject ( value ) ) {
54- const subPropertiesDiff : Diff [ ] = [ ] ;
55- for ( const [ subProperty , subValue ] of Object . entries ( value ) ) {
56- subPropertiesDiff . push ( {
57- property : subProperty ,
58- previousValue : status === ObjectStatus . ADDED ? undefined : subValue ,
59- currentValue : status === ObjectStatus . ADDED ? subValue : undefined ,
64+ const sub : Diff [ ] = [ ] ;
65+ for ( const subKey in value ) {
66+ sub . push ( {
67+ property : subKey ,
68+ previousValue : added ? undefined : value [ subKey ] ,
69+ currentValue : added ? value [ subKey ] : undefined ,
6070 status,
6171 } ) ;
6272 }
6373 diff . push ( {
64- property,
65- previousValue :
66- status === ObjectStatus . ADDED ? undefined : data [ property ] ,
67- currentValue : status === ObjectStatus . ADDED ? value : undefined ,
74+ property : key ,
75+ previousValue : added ? undefined : data [ key ] ,
76+ currentValue : added ? value : undefined ,
6877 status,
69- diff : subPropertiesDiff ,
78+ diff : sub ,
7079 } ) ;
7180 } else {
7281 diff . push ( {
73- property,
74- previousValue :
75- status === ObjectStatus . ADDED ? undefined : data [ property ] ,
76- currentValue : status === ObjectStatus . ADDED ? value : undefined ,
82+ property : key ,
83+ previousValue : added ? undefined : data [ key ] ,
84+ currentValue : added ? value : undefined ,
7785 status,
7886 } ) ;
7987 }
8088 }
81-
82- if ( options . showOnly && options . showOnly . statuses . length > 0 ) {
83- return {
84- type : "object" ,
85- status,
86- diff : getLeanDiff ( diff , options . showOnly ) ,
87- } ;
89+ const showOnly = options . showOnly ;
90+ if ( showOnly && showOnly . statuses . length > 0 ) {
91+ return { type : "object" , status, diff : getLeanDiff ( diff , showOnly ) } ;
8892 }
89- return {
90- type : "object" ,
91- status,
92- diff,
93- } ;
94- }
95-
96- function getValueStatus (
97- previousValue : unknown ,
98- nextValue : unknown ,
99- options ?: ObjectDiffOptions ,
100- ) : ObjectStatus {
101- if ( isEqual ( previousValue , nextValue , options ) ) {
102- return ObjectStatus . EQUAL ;
103- }
104- return ObjectStatus . UPDATED ;
93+ return { type : "object" , status, diff } ;
10594}
10695
10796function getDiff (
108- previousValue : Record < string , unknown > | undefined = { } ,
109- nextValue : Record < string , unknown > ,
97+ prev : Record < string , unknown > = { } ,
98+ next : Record < string , unknown > ,
11099 options ?: ObjectDiffOptions ,
111100) : Diff [ ] {
112101 const diff : Diff [ ] = [ ] ;
113- const allKeys = new Set ( [
114- ...Object . keys ( previousValue ) ,
115- ...Object . keys ( nextValue ) ,
116- ] ) ;
117102
118- for ( const property of allKeys ) {
119- const prevSubValue = previousValue [ property ] ;
120- const nextSubValue = nextValue [ property ] ;
121- if ( ! ( property in nextValue ) ) {
103+ for ( const key in prev ) {
104+ const prevVal = prev [ key ] ;
105+
106+ if ( ! Object . prototype . hasOwnProperty . call ( next , key ) ) {
122107 diff . push ( {
123- property,
124- previousValue : prevSubValue ,
108+ property : key ,
109+ previousValue : prevVal ,
125110 currentValue : undefined ,
126111 status : ObjectStatus . DELETED ,
127112 } ) ;
128113 continue ;
129114 }
130- if ( ! ( property in previousValue ) ) {
131- diff . push ( {
132- property,
133- previousValue : undefined ,
134- currentValue : nextSubValue ,
135- status : ObjectStatus . ADDED ,
136- } ) ;
137- continue ;
138- }
139- if ( isObject ( nextSubValue ) && isObject ( prevSubValue ) ) {
140- const subDiff = getDiff ( prevSubValue , nextSubValue , options ) ;
141- const isUpdated = subDiff . some (
142- ( entry ) => entry . status !== ObjectStatus . EQUAL ,
115+
116+ const nextVal = next [ key ] ;
117+
118+ if ( isObject ( prevVal ) && isObject ( nextVal ) ) {
119+ const sub = getDiff ( prevVal , nextVal , options ) ;
120+ let updated = false ;
121+
122+ for ( let i = 0 ; i < sub . length ; i ++ ) {
123+ if ( sub [ i ] . status !== ObjectStatus . EQUAL ) {
124+ updated = true ;
125+ break ;
126+ }
127+ }
128+
129+ diff . push (
130+ updated
131+ ? {
132+ property : key ,
133+ previousValue : prevVal ,
134+ currentValue : nextVal ,
135+ status : ObjectStatus . UPDATED ,
136+ diff : sub ,
137+ }
138+ : {
139+ property : key ,
140+ previousValue : prevVal ,
141+ currentValue : nextVal ,
142+ status : ObjectStatus . EQUAL ,
143+ } ,
143144 ) ;
144- diff . push ( {
145- property,
146- previousValue : prevSubValue ,
147- currentValue : nextSubValue ,
148- status : isUpdated ? ObjectStatus . UPDATED : ObjectStatus . EQUAL ,
149- ...( isUpdated && { diff : subDiff } ) ,
150- } ) ;
151145 } else {
152- const status = getValueStatus ( prevSubValue , nextSubValue , options ) ;
146+ const status = isEqual ( prevVal , nextVal , options )
147+ ? ObjectStatus . EQUAL
148+ : ObjectStatus . UPDATED ;
149+
153150 diff . push ( {
154- property,
155- previousValue : prevSubValue ,
156- currentValue : nextSubValue ,
151+ property : key ,
152+ previousValue : prevVal ,
153+ currentValue : nextVal ,
157154 status,
158155 } ) ;
159156 }
160157 }
158+
159+ for ( const key in next ) {
160+ if ( Object . prototype . hasOwnProperty . call ( prev , key ) ) continue ;
161+ diff . push ( {
162+ property : key ,
163+ previousValue : undefined ,
164+ currentValue : next [ key ] ,
165+ status : ObjectStatus . ADDED ,
166+ } ) ;
167+ }
161168 return diff ;
162169}
163170
0 commit comments