Skip to content

Commit c215f1e

Browse files
committed
Refactor JSON handling and add utility methods for deep copy and equivalence comparison
1 parent 2bcafdf commit c215f1e

File tree

14 files changed

+185
-14
lines changed

14 files changed

+185
-14
lines changed

src/Confix.Tool/src/Confix.Library/Entities/Component/Configuration/ComponentReferenceConfiguration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public static ComponentReferenceConfiguration Parse(string key, JsonNode node)
5959
null);
6060
}
6161

62-
if (node.GetValueKind() is JsonValueKind.True)
62+
if (node.GetValueKind() is JsonValueKind.True || node.GetValueKind() is JsonValueKind.False)
6363
{
6464
return new ComponentReferenceConfiguration(
6565
provider,

src/Confix.Tool/src/Confix.Library/Entities/Project/DefaultValueVisitor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
using System.Collections.ObjectModel;
33
using System.Text.Json.Nodes;
44
using Confix.Tool.Schema;
5-
using Json.More;
5+
using Confix.Utilities.Json;
66
using Json.Schema;
77

88
namespace Confix.Tool.Entities.Components.DotNet;

src/Confix.Tool/src/Confix.Library/Entities/Schema/MetadataKeyword.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System.Text.Json;
22
using System.Text.Json.Nodes;
33
using System.Text.Json.Serialization;
4-
using Json.More;
4+
using Confix.Utilities.Json;
55
using Json.Schema;
66

77
namespace Confix.Entities.Schema;

src/Confix.Tool/src/Confix.Library/Utilities/Json/JsonNodeExtensions.cs

Lines changed: 174 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System.Text.Json.Nodes;
55
using System.Text.RegularExpressions;
66
using Confix.Tool;
7-
using Json.More;
87
using Json.Schema;
98
using Spectre.Console;
109

@@ -210,4 +209,178 @@ public static async Task SerializeToStreamAsync(
210209

211210
[GeneratedRegex(@"^(?<name>.+?)\[(?<index>\d+)]$")]
212211
private static partial Regex ParseSegmentRegex();
212+
213+
/// <summary>
214+
/// Creates a deep copy of the JSON node.
215+
/// </summary>
216+
/// <param name="node">The JSON node to copy.</param>
217+
/// <returns>A deep copy of the JSON node.</returns>
218+
public static JsonNode? Copy(this JsonNode? node)
219+
{
220+
if (node is null)
221+
{
222+
return null;
223+
}
224+
225+
return node.GetValueKind() switch
226+
{
227+
JsonValueKind.Object => CopyObject((JsonObject)node),
228+
JsonValueKind.Array => CopyArray((JsonArray)node),
229+
_ => JsonValue.Create(JsonSerializer.Deserialize<JsonElement>(node.ToJsonString()))
230+
};
231+
}
232+
233+
private static JsonObject CopyObject(JsonObject source)
234+
{
235+
var copy = new JsonObject();
236+
foreach (var (key, value) in source)
237+
{
238+
copy[key] = Copy(value);
239+
}
240+
return copy;
241+
}
242+
243+
private static JsonArray CopyArray(JsonArray source)
244+
{
245+
var copy = new JsonArray();
246+
foreach (var item in source)
247+
{
248+
copy.Add(Copy(item));
249+
}
250+
return copy;
251+
}
252+
253+
/// <summary>
254+
/// Determines if two JSON nodes are equivalent.
255+
/// </summary>
256+
/// <param name="a">The first JSON node.</param>
257+
/// <param name="b">The second JSON node.</param>
258+
/// <returns>True if the nodes are equivalent; otherwise, false.</returns>
259+
public static bool IsEquivalentTo(this JsonNode? a, JsonNode? b)
260+
{
261+
if (ReferenceEquals(a, b))
262+
{
263+
return true;
264+
}
265+
266+
if (a is null || b is null)
267+
{
268+
return false;
269+
}
270+
271+
var aKind = a.GetValueKind();
272+
var bKind = b.GetValueKind();
273+
274+
if (aKind != bKind)
275+
{
276+
return false;
277+
}
278+
279+
return aKind switch
280+
{
281+
JsonValueKind.Object => AreObjectsEquivalent((JsonObject)a, (JsonObject)b),
282+
JsonValueKind.Array => AreArraysEquivalent((JsonArray)a, (JsonArray)b),
283+
JsonValueKind.String => AreValuesEquivalent(a, b),
284+
JsonValueKind.Number => AreValuesEquivalent(a, b),
285+
JsonValueKind.True => true,
286+
JsonValueKind.False => true,
287+
JsonValueKind.Null => true,
288+
_ => false
289+
};
290+
}
291+
292+
private static bool AreObjectsEquivalent(JsonObject a, JsonObject b)
293+
{
294+
if (a.Count != b.Count)
295+
{
296+
return false;
297+
}
298+
299+
foreach (var (key, aValue) in a)
300+
{
301+
if (!b.TryGetPropertyValue(key, out var bValue))
302+
{
303+
return false;
304+
}
305+
306+
if (!IsEquivalentTo(aValue, bValue))
307+
{
308+
return false;
309+
}
310+
}
311+
312+
return true;
313+
}
314+
315+
private static bool AreArraysEquivalent(JsonArray a, JsonArray b)
316+
{
317+
if (a.Count != b.Count)
318+
{
319+
return false;
320+
}
321+
322+
for (var i = 0; i < a.Count; i++)
323+
{
324+
if (!IsEquivalentTo(a[i], b[i]))
325+
{
326+
return false;
327+
}
328+
}
329+
330+
return true;
331+
}
332+
333+
private static bool AreValuesEquivalent(JsonNode a, JsonNode b)
334+
{
335+
var aString = a.ToJsonString();
336+
var bString = b.ToJsonString();
337+
return aString == bString;
338+
}
339+
340+
/// <summary>
341+
/// Gets a hash code for the JSON node that is consistent with equivalence comparison.
342+
/// </summary>
343+
/// <param name="node">The JSON node.</param>
344+
/// <returns>A hash code value.</returns>
345+
public static int GetEquivalenceHashCode(this JsonNode? node)
346+
{
347+
if (node is null)
348+
{
349+
return 0;
350+
}
351+
352+
var kind = node.GetValueKind();
353+
354+
return kind switch
355+
{
356+
JsonValueKind.Object => GetObjectHashCode((JsonObject)node),
357+
JsonValueKind.Array => GetArrayHashCode((JsonArray)node),
358+
JsonValueKind.String or JsonValueKind.Number => node.ToJsonString().GetHashCode(),
359+
JsonValueKind.True => true.GetHashCode(),
360+
JsonValueKind.False => false.GetHashCode(),
361+
JsonValueKind.Null => 0,
362+
_ => 0
363+
};
364+
}
365+
366+
private static int GetObjectHashCode(JsonObject obj)
367+
{
368+
var hash = new HashCode();
369+
foreach (var (key, value) in obj.OrderBy(x => x.Key))
370+
{
371+
hash.Add(key);
372+
hash.Add(GetEquivalenceHashCode(value));
373+
}
374+
return hash.ToHashCode();
375+
}
376+
377+
private static int GetArrayHashCode(JsonArray array)
378+
{
379+
var hash = new HashCode();
380+
foreach (var item in array)
381+
{
382+
hash.Add(GetEquivalenceHashCode(item));
383+
}
384+
return hash.ToHashCode();
385+
}
213386
}

src/Confix.Tool/src/Confix.Library/Utilities/Json/JsonSchemaBuilderExtensions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System.Text.Json.Nodes;
22
using Confix.Entities.Schema;
33
using Confix.Utilities.Json;
4-
using Json.More;
54
using Json.Schema;
65

76
namespace Confix.Tool.Schema;

src/Confix.Tool/src/Confix.Library/Utilities/Json/VariableIntellisenseRewriter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System.Text.Json;
22
using System.Text.Json.Nodes;
3-
using Json.More;
3+
using Confix.Utilities.Json;
44
using Json.Schema;
55

66
namespace Confix.Tool.Schema;

src/Confix.Tool/src/Confix.Library/Variables/JsonVariableRewriter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
using System.Text.Json.Nodes;
33
using Confix.Tool;
44
using Confix.Tool.Schema;
5-
using Json.More;
5+
using Confix.Utilities.Json;
66
using Json.Schema;
77

88
namespace Confix.Variables;

src/Confix.Tool/src/Confix.Library/Variables/Providers/Local/LocalVariableProvider.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using Confix.Tool.Schema;
77
using Confix.Utilities.Json;
88
using HotChocolate.Types;
9-
using Json.More;
109

1110
namespace Confix.Variables;
1211

src/Confix.Tool/test/Confix.Tool.Tests/Entities/Variables/VariableProviderDefinitionTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
using System.Text.Json.Nodes;
22
using Confix.Tool;
33
using Confix.Tool.Abstractions;
4+
using Confix.Utilities.Json;
45
using FluentAssertions;
5-
using Json.More;
66

77
namespace Confix.Entities.Component.Configuration;
88

src/Confix.Tool/test/Confix.Tool.Tests/Middlewares/MagicPathRewriterTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System.Text.Json.Nodes;
22
using Confix.Tool.Middlewares;
3-
using Json.More;
3+
using Confix.Utilities.Json;
44
using Snapshooter.Xunit;
55

66
namespace Confix.Entities.Component.Configuration.Middlewares;

0 commit comments

Comments
 (0)