@@ -14,21 +14,19 @@ function getLeanDiff(
1414 showOnly : ObjectDiffOptions [ "showOnly" ] = DEFAULT_OBJECT_DIFF_OPTIONS . showOnly ,
1515) : ObjectDiff [ "diff" ] {
1616 const { statuses, granularity } = showOnly ;
17- return diff . reduce (
18- ( acc , value ) => {
19- if ( granularity === GRANULARITY . DEEP && value . diff ) {
20- const leanDiff = getLeanDiff ( value . diff , showOnly ) ;
21- if ( leanDiff . length > 0 ) {
22- return [ ... acc , { ... value , diff : leanDiff } ] ;
23- }
17+ const res : ObjectDiff [ " diff" ] = [ ] ;
18+ 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 } ) ;
2424 }
25- if ( statuses . includes ( value . status ) ) {
26- return [ ...acc , value ] ;
27- }
28- return acc ;
29- } ,
30- [ ] as ObjectDiff [ "diff" ] ,
31- ) ;
25+ } else if ( statuses . includes ( value . status ) ) {
26+ res . push ( value ) ;
27+ }
28+ }
29+ return res ;
3230}
3331
3432function getObjectStatus ( diff : ObjectDiff [ "diff" ] ) : OBJECT_STATUS {
@@ -50,34 +48,37 @@ function formatSingleObjectDiff(
5048 } ;
5149 }
5250 const diff : ObjectDiff [ "diff" ] = [ ] ;
53- Object . entries ( data ) . forEach ( ( [ property , value ] ) => {
51+
52+ for ( const [ property , value ] of Object . entries ( data ) ) {
5453 if ( isObject ( value ) ) {
5554 const subPropertiesDiff : Diff [ ] = [ ] ;
56- Object . entries ( value ) . forEach ( ( [ subProperty , subValue ] ) => {
55+ for ( const [ subProperty , subValue ] of Object . entries ( value ) ) {
5756 subPropertiesDiff . push ( {
5857 property : subProperty ,
5958 previousValue : status === OBJECT_STATUS . ADDED ? undefined : subValue ,
6059 currentValue : status === OBJECT_STATUS . ADDED ? subValue : undefined ,
6160 status,
6261 } ) ;
63- } ) ;
64- return diff . push ( {
62+ }
63+ diff . push ( {
6564 property,
6665 previousValue :
6766 status === OBJECT_STATUS . ADDED ? undefined : data [ property ] ,
6867 currentValue : status === OBJECT_STATUS . ADDED ? value : undefined ,
6968 status,
7069 diff : subPropertiesDiff ,
7170 } ) ;
71+ } else {
72+ diff . push ( {
73+ property,
74+ previousValue :
75+ status === OBJECT_STATUS . ADDED ? undefined : data [ property ] ,
76+ currentValue : status === OBJECT_STATUS . ADDED ? value : undefined ,
77+ status,
78+ } ) ;
7279 }
73- return diff . push ( {
74- property,
75- previousValue :
76- status === OBJECT_STATUS . ADDED ? undefined : data [ property ] ,
77- currentValue : status === OBJECT_STATUS . ADDED ? value : undefined ,
78- status,
79- } ) ;
80- } ) ;
80+ }
81+
8182 if ( options . showOnly && options . showOnly . statuses . length > 0 ) {
8283 return {
8384 type : "object" ,
@@ -92,20 +93,6 @@ function formatSingleObjectDiff(
9293 } ;
9394}
9495
95- function getPreviousMatch (
96- previousValue : unknown | undefined ,
97- nextSubProperty : unknown ,
98- options ?: ObjectDiffOptions ,
99- ) : unknown | undefined {
100- if ( ! previousValue ) {
101- return undefined ;
102- }
103- const previousMatch = Object . entries ( previousValue ) . find ( ( [ subPreviousKey ] ) =>
104- isEqual ( subPreviousKey , nextSubProperty , options ) ,
105- ) ;
106- return previousMatch ? previousMatch [ 1 ] : undefined ;
107- }
108-
10996function getValueStatus (
11097 previousValue : unknown ,
11198 nextValue : unknown ,
@@ -117,91 +104,60 @@ function getValueStatus(
117104 return OBJECT_STATUS . UPDATED ;
118105}
119106
120- function getPropertyStatus ( subPropertiesDiff : Diff [ ] ) : OBJECT_STATUS {
121- return subPropertiesDiff . some (
122- ( property ) => property . status !== OBJECT_STATUS . EQUAL ,
123- )
124- ? OBJECT_STATUS . UPDATED
125- : OBJECT_STATUS . EQUAL ;
126- }
127-
128- function getDeletedProperties (
129- previousValue : Record < string , unknown > | undefined ,
130- nextValue : Record < string , unknown > ,
131- ) : { property : string ; value : unknown } [ ] | undefined {
132- if ( ! previousValue ) return undefined ;
133- const prevKeys = Object . keys ( previousValue ) ;
134- const nextKeys = Object . keys ( nextValue ) ;
135- const deletedKeys = prevKeys . filter ( ( prevKey ) => ! nextKeys . includes ( prevKey ) ) ;
136- if ( deletedKeys . length > 0 ) {
137- return deletedKeys . map ( ( deletedKey ) => ( {
138- property : deletedKey ,
139- value : previousValue [ deletedKey ] ,
140- } ) ) ;
141- }
142- return undefined ;
143- }
144-
145107function getSubPropertiesDiff (
146- previousValue : Record < string , unknown > | undefined ,
108+ previousValue : Record < string , unknown > | undefined = { } ,
147109 nextValue : Record < string , unknown > ,
148110 options ?: ObjectDiffOptions ,
149111) : Diff [ ] {
150112 const subPropertiesDiff : Diff [ ] = [ ] ;
151- let subDiff : Diff [ ] ;
152- const deletedMainSubProperties = getDeletedProperties (
153- previousValue ,
154- nextValue ,
155- ) ;
156- if ( deletedMainSubProperties ) {
157- deletedMainSubProperties . forEach ( ( deletedProperty ) => {
113+ const allKeys = new Set ( [
114+ ...Object . keys ( previousValue ) ,
115+ ...Object . keys ( nextValue ) ,
116+ ] ) ;
117+
118+ for ( const property of allKeys ) {
119+ const prevSubValue = previousValue [ property ] ;
120+ const nextSubValue = nextValue [ property ] ;
121+ if ( ! ( property in nextValue ) ) {
158122 subPropertiesDiff . push ( {
159- property : deletedProperty . property ,
160- previousValue : deletedProperty . value ,
123+ property,
124+ previousValue : prevSubValue ,
161125 currentValue : undefined ,
162126 status : OBJECT_STATUS . DELETED ,
163127 } ) ;
164- } ) ;
165- }
166- Object . entries ( nextValue ) . forEach ( ( [ nextSubProperty , nextSubValue ] ) => {
167- const previousMatch = getPreviousMatch (
168- previousValue ,
169- nextSubProperty ,
170- options ,
171- ) ;
172- if ( ! previousMatch ) {
173- return subPropertiesDiff . push ( {
174- property : nextSubProperty ,
175- previousValue : previousMatch ,
128+ continue ;
129+ }
130+ if ( ! ( property in previousValue ) ) {
131+ subPropertiesDiff . push ( {
132+ property,
133+ previousValue : undefined ,
176134 currentValue : nextSubValue ,
177- status :
178- ! previousValue || ! ( nextSubProperty in previousValue )
179- ? OBJECT_STATUS . ADDED
180- : previousMatch === nextSubValue
181- ? OBJECT_STATUS . EQUAL
182- : OBJECT_STATUS . UPDATED ,
135+ status : OBJECT_STATUS . ADDED ,
183136 } ) ;
137+ continue ;
184138 }
185- if ( isObject ( nextSubValue ) ) {
186- const data : Diff [ ] = getSubPropertiesDiff (
187- previousMatch as Record < string , unknown > ,
188- nextSubValue ,
189- options ,
139+ if ( isObject ( nextSubValue ) && isObject ( prevSubValue ) ) {
140+ const subDiff = getSubPropertiesDiff ( prevSubValue , nextSubValue , options ) ;
141+ const isUpdated = subDiff . some (
142+ ( entry ) => entry . status !== OBJECT_STATUS . EQUAL ,
190143 ) ;
191- if ( data && data . length > 0 ) {
192- subDiff = data ;
193- }
194- }
195- if ( previousMatch ) {
196144 subPropertiesDiff . push ( {
197- property : nextSubProperty ,
198- previousValue : previousMatch ,
145+ property,
146+ previousValue : prevSubValue ,
147+ currentValue : nextSubValue ,
148+ status : isUpdated ? OBJECT_STATUS . UPDATED : OBJECT_STATUS . EQUAL ,
149+ ...( isUpdated && { diff : subDiff } ) ,
150+ } ) ;
151+ } else {
152+ const status = getValueStatus ( prevSubValue , nextSubValue , options ) ;
153+ subPropertiesDiff . push ( {
154+ property,
155+ previousValue : prevSubValue ,
199156 currentValue : nextSubValue ,
200- status : getValueStatus ( previousMatch , nextSubValue , options ) ,
201- ...( ! ! subDiff && { diff : subDiff } ) ,
157+ status,
202158 } ) ;
203159 }
204- } ) ;
160+ }
205161 return subPropertiesDiff ;
206162}
207163
@@ -235,54 +191,53 @@ export function getObjectDiff(
235191 return formatSingleObjectDiff ( prevData , OBJECT_STATUS . DELETED , options ) ;
236192 }
237193 const diff : ObjectDiff [ "diff" ] = [ ] ;
238- Object . entries ( nextData ) . forEach ( ( [ nextProperty , nextValue ] ) => {
239- const previousValue = prevData [ nextProperty ] ;
240- if ( ! previousValue ) {
241- return diff . push ( {
242- property : nextProperty ,
194+ const allKeys = new Set ( [ ...Object . keys ( prevData ) , ...Object . keys ( nextData ) ] ) ;
195+ for ( const property of allKeys ) {
196+ const previousValue = prevData [ property ] ;
197+ const currentValue = nextData [ property ] ;
198+ if ( ! ( property in nextData ) ) {
199+ diff . push ( {
200+ property,
243201 previousValue,
244- currentValue : nextValue ,
245- status : ! ( nextProperty in prevData )
246- ? OBJECT_STATUS . ADDED
247- : previousValue === nextValue
248- ? OBJECT_STATUS . EQUAL
249- : OBJECT_STATUS . UPDATED ,
202+ currentValue : undefined ,
203+ status : OBJECT_STATUS . DELETED ,
204+ } ) ;
205+ continue ;
206+ }
207+ if ( ! ( property in prevData ) ) {
208+ diff . push ( {
209+ property,
210+ previousValue : undefined ,
211+ currentValue,
212+ status : OBJECT_STATUS . ADDED ,
250213 } ) ;
214+ continue ;
251215 }
252- if ( isObject ( nextValue ) ) {
253- const subPropertiesDiff : Diff [ ] = getSubPropertiesDiff (
254- previousValue as Record < string , unknown > ,
255- nextValue ,
216+ if ( isObject ( currentValue ) && isObject ( previousValue ) ) {
217+ const subDiff = getSubPropertiesDiff (
218+ previousValue ,
219+ currentValue ,
256220 options ,
257221 ) ;
258- const subPropertyStatus = getPropertyStatus ( subPropertiesDiff ) ;
259- return diff . push ( {
260- property : nextProperty ,
222+ const isUpdated = subDiff . some (
223+ ( entry ) => entry . status !== OBJECT_STATUS . EQUAL ,
224+ ) ;
225+ diff . push ( {
226+ property,
261227 previousValue,
262- currentValue : nextValue ,
263- status : subPropertyStatus ,
264- ...( subPropertyStatus !== OBJECT_STATUS . EQUAL && {
265- diff : subPropertiesDiff ,
266- } ) ,
228+ currentValue,
229+ status : isUpdated ? OBJECT_STATUS . UPDATED : OBJECT_STATUS . EQUAL ,
230+ ...( isUpdated && { diff : subDiff } ) ,
267231 } ) ;
268- }
269- return diff . push ( {
270- property : nextProperty ,
271- previousValue,
272- currentValue : nextValue ,
273- status : getValueStatus ( previousValue , nextValue , options ) ,
274- } ) ;
275- } ) ;
276- const deletedProperties = getDeletedProperties ( prevData , nextData ) ;
277- if ( deletedProperties ) {
278- deletedProperties . forEach ( ( deletedProperty ) => {
232+ } else {
233+ const status = getValueStatus ( previousValue , currentValue , options ) ;
279234 diff . push ( {
280- property : deletedProperty . property ,
281- previousValue : deletedProperty . value ,
282- currentValue : undefined ,
283- status : OBJECT_STATUS . DELETED ,
235+ property,
236+ previousValue,
237+ currentValue,
238+ status,
284239 } ) ;
285- } ) ;
240+ }
286241 }
287242 if ( options . showOnly && options . showOnly . statuses . length > 0 ) {
288243 return {
0 commit comments