Implement diff-reporter PoC (#5)
This commit is contained in:
77
src/Recordingtest.DiffReporter/JsonDiffer.cs
Normal file
77
src/Recordingtest.DiffReporter/JsonDiffer.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user