78 lines
2.5 KiB
C#
78 lines
2.5 KiB
C#
using System.Text.Json;
|
|
|
|
namespace Recordingtest.DiffReporter;
|
|
|
|
internal static class JsonDiffer
|
|
{
|
|
public static IReadOnlyList<Hunk> Diff(JsonElement a, JsonElement b)
|
|
{
|
|
var aMap = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
|
var bMap = new SortedDictionary<string, string>(StringComparer.Ordinal);
|
|
Flatten("$", a, aMap);
|
|
Flatten("$", b, bMap);
|
|
|
|
var hunks = new List<Hunk>();
|
|
var allKeys = new SortedSet<string>(aMap.Keys, StringComparer.Ordinal);
|
|
foreach (var k in bMap.Keys) allKeys.Add(k);
|
|
|
|
int idx = 0;
|
|
foreach (var key in allKeys)
|
|
{
|
|
var hasA = aMap.TryGetValue(key, out var av);
|
|
var hasB = bMap.TryGetValue(key, out var bv);
|
|
if (hasA && hasB)
|
|
{
|
|
if (!string.Equals(av, bv, StringComparison.Ordinal))
|
|
hunks.Add(new Hunk(idx, "changed", $"{key}={av}", $"{key}={bv}"));
|
|
}
|
|
else if (hasA)
|
|
{
|
|
hunks.Add(new Hunk(idx, "removed", $"{key}={av}", string.Empty));
|
|
}
|
|
else if (hasB)
|
|
{
|
|
hunks.Add(new Hunk(idx, "added", string.Empty, $"{key}={bv}"));
|
|
}
|
|
idx++;
|
|
}
|
|
return hunks;
|
|
}
|
|
|
|
private static void Flatten(string path, JsonElement el, IDictionary<string, string> map)
|
|
{
|
|
switch (el.ValueKind)
|
|
{
|
|
case JsonValueKind.Object:
|
|
foreach (var p in el.EnumerateObject())
|
|
Flatten(path + "." + p.Name, p.Value, map);
|
|
break;
|
|
case JsonValueKind.Array:
|
|
int i = 0;
|
|
foreach (var item in el.EnumerateArray())
|
|
{
|
|
Flatten(path + "[" + i + "]", item, map);
|
|
i++;
|
|
}
|
|
break;
|
|
case JsonValueKind.String:
|
|
map[path] = "\"" + el.GetString() + "\"";
|
|
break;
|
|
case JsonValueKind.Number:
|
|
map[path] = el.GetRawText();
|
|
break;
|
|
case JsonValueKind.True:
|
|
map[path] = "true";
|
|
break;
|
|
case JsonValueKind.False:
|
|
map[path] = "false";
|
|
break;
|
|
case JsonValueKind.Null:
|
|
map[path] = "null";
|
|
break;
|
|
default:
|
|
map[path] = el.GetRawText();
|
|
break;
|
|
}
|
|
}
|
|
}
|