stabilizaiton work - projects rework for maintenanceability and ui livening

This commit is contained in:
master
2026-02-03 23:40:04 +02:00
parent 074ce117ba
commit 557feefdc3
3305 changed files with 186813 additions and 107843 deletions

View File

@@ -1,4 +1,3 @@
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Text.Encodings.Web;
@@ -13,7 +12,7 @@ namespace StellaOps.Canonicalization.Json;
/// </summary>
public static class CanonicalJsonSerializer
{
private static readonly JsonSerializerOptions Options = new()
private static readonly JsonSerializerOptions _options = new()
{
WriteIndented = false,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
@@ -29,7 +28,7 @@ public static class CanonicalJsonSerializer
};
public static string Serialize<T>(T value)
=> JsonSerializer.Serialize(value, Options);
=> JsonSerializer.Serialize(value, _options);
public static (string Json, string Digest) SerializeWithDigest<T>(T value)
{
@@ -41,102 +40,7 @@ public static class CanonicalJsonSerializer
public static T Deserialize<T>(string json)
{
return JsonSerializer.Deserialize<T>(json, Options)
return JsonSerializer.Deserialize<T>(json, _options)
?? throw new InvalidOperationException($"Failed to deserialize {typeof(T).Name}");
}
}
/// <summary>
/// Converter factory that orders dictionary keys alphabetically.
/// </summary>
public sealed class StableDictionaryConverterFactory : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert)
{
if (!typeToConvert.IsGenericType) return false;
var generic = typeToConvert.GetGenericTypeDefinition();
return generic == typeof(Dictionary<,>) || generic == typeof(IDictionary<,>) || generic == typeof(IReadOnlyDictionary<,>);
}
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
var args = typeToConvert.GetGenericArguments();
var converterType = typeof(StableDictionaryConverter<,>).MakeGenericType(args[0], args[1]);
return (JsonConverter)Activator.CreateInstance(converterType)!;
}
}
public sealed class StableDictionaryConverter<TKey, TValue> : JsonConverter<IDictionary<TKey, TValue>>
where TKey : notnull
{
public override IDictionary<TKey, TValue>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> JsonSerializer.Deserialize<Dictionary<TKey, TValue>>(ref reader, options);
public override void Write(Utf8JsonWriter writer, IDictionary<TKey, TValue> value, JsonSerializerOptions options)
{
writer.WriteStartObject();
var ordered = value
.Select(kvp => new
{
Key = kvp.Key,
Value = kvp.Value,
RawKeyString = ConvertKeyToString(kvp.Key)
})
.Select(kvp => new
{
kvp.Key,
kvp.Value,
kvp.RawKeyString,
KeyString = ApplyKeyPolicy(kvp.RawKeyString, options)
})
.OrderBy(kvp => kvp.KeyString, StringComparer.Ordinal)
.ThenBy(kvp => kvp.RawKeyString, StringComparer.Ordinal);
foreach (var kvp in ordered)
{
writer.WritePropertyName(kvp.KeyString);
JsonSerializer.Serialize(writer, kvp.Value, options);
}
writer.WriteEndObject();
}
private static string ConvertKeyToString(TKey key)
{
if (key is null)
{
throw new ArgumentException("Dictionary key cannot be null.", nameof(key));
}
return key switch
{
string s => s,
IFormattable formattable => formattable.ToString(null, CultureInfo.InvariantCulture),
_ => Convert.ToString(key, CultureInfo.InvariantCulture)
} ?? string.Empty;
}
private static string ApplyKeyPolicy(string keyString, JsonSerializerOptions options)
{
if (options.DictionaryKeyPolicy is not null)
{
keyString = options.DictionaryKeyPolicy.ConvertName(keyString);
}
return keyString;
}
}
/// <summary>
/// Converter for ISO 8601 date/time with UTC normalization.
/// </summary>
public sealed class Iso8601DateTimeConverter : JsonConverter<DateTimeOffset>
{
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> DateTimeOffset.Parse(
reader.GetString() ?? throw new JsonException("DateTimeOffset value is null."),
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options)
=> writer.WriteStringValue(value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture));
}