@@ -15,6 +15,19 @@ public static class JsonMerger
1515 /// <param name="patch">The patch JObject to merge.</param>
1616 /// <returns>The merged JObject.</returns>
1717 public static JObject Merge ( JObject original , JObject patch )
18+ {
19+ patch = MergeRecursive ( original , patch ) ;
20+ original . Merge ( patch , new ( ) { MergeArrayHandling = MergeArrayHandling . Replace , MergeNullValueHandling = MergeNullValueHandling . Merge } ) ;
21+ return original ;
22+ }
23+
24+ /// <summary>
25+ /// Recursively applies custom merging logic to arrays.
26+ /// </summary>
27+ /// <param name="original"></param>
28+ /// <param name="patch"></param>
29+ /// <returns></returns>
30+ private static JObject MergeRecursive ( JObject original , JObject patch )
1831 {
1932 foreach ( var property in patch . Properties ( ) . ToArray ( ) . ToList ( ) )
2033 {
@@ -25,43 +38,26 @@ public static JObject Merge(JObject original, JObject patch)
2538 JToken ? originalValue = original [ propName ] ;
2639 JToken patchValue = property . Value ;
2740
28- if ( originalValue == null )
29- {
30- JArray ? patchArray = patchValue . TryCast < JArray > ( ) ;
31- if ( patchArray != null )
32- {
33- bool isSkins = propName . Equals ( "skins" , StringComparison . OrdinalIgnoreCase ) ;
34- JArray merged = MergeArrays ( new JArray ( ) , patchArray , isSkins ) ;
35- original [ propName ] = merged ;
36- }
37- else
38- {
39- original [ propName ] = patchValue ;
40- }
41- continue ;
42- }
43-
44- JObject ? originalObj = originalValue . TryCast < JObject > ( ) ;
45- JObject ? patchObj = patchValue . TryCast < JObject > ( ) ;
46- if ( originalObj != null && patchObj != null )
41+ if ( patchValue . Type == JTokenType . Array )
4742 {
48- Merge ( originalObj , patchObj ) ;
49- continue ;
50- }
43+ if ( originalValue == null )
44+ originalValue = new JArray ( ) ;
5145
52- JArray ? originalArr = originalValue . TryCast < JArray > ( ) ;
53- JArray ? patchArr = patchValue . TryCast < JArray > ( ) ;
54- if ( originalArr != null && patchArr != null )
55- {
46+ JArray originalArr = originalValue . Cast < JArray > ( ) ;
47+ JArray patchArr = patchValue . Cast < JArray > ( ) ;
5648 bool isSkins = propName . Equals ( "skins" , StringComparison . OrdinalIgnoreCase ) ;
5749 JArray merged = MergeArrays ( originalArr , patchArr , isSkins ) ;
58- original [ propName ] = merged ;
59- continue ;
50+ patch [ propName ] = merged ;
6051 }
61- original [ propName ] = patchValue ;
62- }
52+ else if ( patchValue . Type == JTokenType . Object )
53+ {
54+ if ( originalValue == null || originalValue . Type != JTokenType . Object )
55+ originalValue = new JObject ( ) ;
6356
64- return original ;
57+ MergeRecursive ( originalValue . Cast < JObject > ( ) , patchValue . Cast < JObject > ( ) ) ;
58+ }
59+ }
60+ return patch ;
6561 }
6662
6763 /// <summary>
@@ -73,22 +69,10 @@ public static JObject Merge(JObject original, JObject patch)
7369 /// <returns>The merged JArray.</returns>
7470 private static JArray MergeArrays ( JArray original , JArray patch , bool isSkins )
7571 {
76- if ( patch . Count == 0 )
77- return new JArray ( ) ;
78-
7972 var result = new JArray ( original ) ;
8073 var patchList = patch . _values . ToArray ( ) . ToList ( ) ;
8174
82- bool hasDirectValues = patchList . Any ( v =>
83- v . Type == JTokenType . String &&
84- ! v . ToString ( ) . StartsWith ( "+" ) &&
85- ! v . ToString ( ) . StartsWith ( "-" ) ) ;
86-
87- if ( ! isSkins && hasDirectValues )
88- {
89- result = new JArray ( ) ;
90- }
91-
75+ bool hasCustomValues = false ;
9276 foreach ( var token in patchList )
9377 {
9478 if ( token . Type != JTokenType . String )
@@ -102,10 +86,8 @@ private static JArray MergeArrays(JArray original, JArray patch, bool isSkins)
10286 if ( str . StartsWith ( "+" ) )
10387 {
10488 string value = str . Substring ( 1 ) ;
105- if ( ! result . _values . ToArray ( ) . Any ( t => t . Type == JTokenType . String && t . ToString ( ) == value ) )
106- {
107- result . Add ( value ) ;
108- }
89+ result . Add ( value ) ;
90+ hasCustomValues = true ;
10991 }
11092 else if ( str . StartsWith ( "-" ) )
11193 {
@@ -115,23 +97,18 @@ private static JArray MergeArrays(JArray original, JArray patch, bool isSkins)
11597 . ToList ( ) ;
11698 foreach ( var rem in toRemove )
11799 result . Remove ( rem ) ;
100+ hasCustomValues = true ;
118101 }
119- else
102+ else if ( isSkins )
120103 {
121- if ( isSkins )
122- {
123- if ( ! result . _values . ToArray ( ) . Any ( t => t . Type == JTokenType . String && t . ToString ( ) == str ) )
124- {
125- result . Add ( str ) ;
126- }
127- }
128- else
129- {
130- result . Add ( str ) ;
131- }
104+ result . Add ( str ) ;
105+ hasCustomValues = true ;
132106 }
133107 }
134-
108+ if ( ! hasCustomValues )
109+ {
110+ result = new JArray ( patch ) ;
111+ }
135112 return result ;
136113 }
137114}
0 commit comments