mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Code cleanup and fix test running
This commit is contained in:
@ -1,40 +1,39 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Wabbajack.DTOs.ConverterGenerators
|
||||
namespace Wabbajack.DTOs.ConverterGenerators;
|
||||
|
||||
public class CFile
|
||||
{
|
||||
public class CFile
|
||||
private readonly StringBuilder _sb;
|
||||
private int _indent;
|
||||
|
||||
public CFile()
|
||||
{
|
||||
private readonly StringBuilder _sb;
|
||||
private int _indent;
|
||||
_sb = new StringBuilder();
|
||||
Code("// THIS FILE IS AUTOGENERATED DO NOT EDIT BY HAND");
|
||||
Code("using System;");
|
||||
Code("using System.Text.Json;");
|
||||
Code("using System.Text.Json.Serialization;");
|
||||
Code("using Wabbajack.Hashing.xxHash64;");
|
||||
Code("using Microsoft.Extensions.DependencyInjection;");
|
||||
Code("");
|
||||
}
|
||||
|
||||
public CFile()
|
||||
{
|
||||
_sb = new StringBuilder();
|
||||
Code("// THIS FILE IS AUTOGENERATED DO NOT EDIT BY HAND");
|
||||
Code("using System;");
|
||||
Code("using System.Text.Json;");
|
||||
Code("using System.Text.Json.Serialization;");
|
||||
Code("using Wabbajack.Hashing.xxHash64;");
|
||||
Code("using Microsoft.Extensions.DependencyInjection;");
|
||||
Code("");
|
||||
}
|
||||
public void Write(string path)
|
||||
{
|
||||
File.WriteAllText(path, _sb.ToString());
|
||||
}
|
||||
|
||||
public void Write(string path)
|
||||
{
|
||||
File.WriteAllText(path, _sb.ToString());
|
||||
}
|
||||
public void Code(string c)
|
||||
{
|
||||
if (c.EndsWith("}"))
|
||||
_indent--;
|
||||
|
||||
public void Code(string c)
|
||||
{
|
||||
if (c.EndsWith("}"))
|
||||
_indent--;
|
||||
for (var i = 0; i < _indent; i++) _sb.Append(" ");
|
||||
_sb.AppendLine(c);
|
||||
|
||||
for (var i = 0; i < _indent; i++) _sb.Append(" ");
|
||||
_sb.AppendLine(c);
|
||||
|
||||
if (c.EndsWith("{"))
|
||||
_indent++;
|
||||
}
|
||||
if (c.EndsWith("{"))
|
||||
_indent++;
|
||||
}
|
||||
}
|
@ -6,203 +6,202 @@ using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Wabbajack.DTOs.JsonConverters;
|
||||
|
||||
namespace Wabbajack.DTOs.ConverterGenerators
|
||||
namespace Wabbajack.DTOs.ConverterGenerators;
|
||||
|
||||
public class PolymorphicGenerator<T>
|
||||
{
|
||||
public class PolymorphicGenerator<T>
|
||||
public PolymorphicGenerator()
|
||||
{
|
||||
public PolymorphicGenerator()
|
||||
var types = typeof(T).Assembly.GetTypes()
|
||||
.Where(t => !t.IsAbstract && !t.IsInterface)
|
||||
.Where(t => t.IsAssignableTo(typeof(T)));
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
var types = typeof(T).Assembly.GetTypes()
|
||||
.Where(t => !t.IsAbstract && !t.IsInterface)
|
||||
.Where(t => t.IsAssignableTo(typeof(T)));
|
||||
var nameAttr = type.CustomAttributes.Where(t => t.AttributeType == typeof(JsonNameAttribute))
|
||||
.Select(t => (string) t.ConstructorArguments.First().Value!)
|
||||
.FirstOrDefault();
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
var nameAttr = type.CustomAttributes.Where(t => t.AttributeType == typeof(JsonNameAttribute))
|
||||
.Select(t => (string)t.ConstructorArguments.First().Value!)
|
||||
.FirstOrDefault();
|
||||
if (nameAttr == default)
|
||||
throw new JsonException($"Type {type} of interface {typeof(T)} does not have a JsonNameAttribute");
|
||||
Registry[nameAttr] = type;
|
||||
ReverseRegistry[type] = nameAttr;
|
||||
|
||||
if (nameAttr == default)
|
||||
throw new JsonException($"Type {type} of interface {typeof(T)} does not have a JsonNameAttribute");
|
||||
Registry[nameAttr] = type;
|
||||
ReverseRegistry[type] = nameAttr;
|
||||
var aliases = type.CustomAttributes.Where(t => t.AttributeType == typeof(JsonAliasAttribute))
|
||||
.Select(t => t.ConstructorArguments.First());
|
||||
|
||||
var aliases = type.CustomAttributes.Where(t => t.AttributeType == typeof(JsonAliasAttribute))
|
||||
.Select(t => t.ConstructorArguments.First());
|
||||
|
||||
foreach (var alias in aliases) Registry[(string)alias.Value!] = type;
|
||||
}
|
||||
foreach (var alias in aliases) Registry[(string) alias.Value!] = type;
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, Type> Registry { get; } = new();
|
||||
public Dictionary<Type, string> ReverseRegistry { get; } = new();
|
||||
public Dictionary<string, Type> Registry { get; } = new();
|
||||
public Dictionary<Type, string> ReverseRegistry { get; } = new();
|
||||
|
||||
public void GenerateSpecific(CFile c)
|
||||
public void GenerateSpecific(CFile c)
|
||||
{
|
||||
foreach (var type in ReverseRegistry.Keys.OrderBy(k => k.FullName))
|
||||
{
|
||||
foreach (var type in ReverseRegistry.Keys.OrderBy(k => k.FullName))
|
||||
{
|
||||
var members = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(p => p.CanRead)
|
||||
.Where(p => p.CanWrite)
|
||||
.Where(p => !p.CustomAttributes.Any(c => c.AttributeType == typeof(JsonIgnoreAttribute)))
|
||||
.Select(p =>
|
||||
var members = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(p => p.CanRead)
|
||||
.Where(p => p.CanWrite)
|
||||
.Where(p => !p.CustomAttributes.Any(c => c.AttributeType == typeof(JsonIgnoreAttribute)))
|
||||
.Select(p =>
|
||||
{
|
||||
var name = p.CustomAttributes.Where(c => c.AttributeType == typeof(JsonPropertyNameAttribute))
|
||||
.Select(a => (string) a.ConstructorArguments.FirstOrDefault().Value)
|
||||
.FirstOrDefault() ?? p.Name;
|
||||
|
||||
return new
|
||||
{
|
||||
var name = p.CustomAttributes.Where(c => c.AttributeType == typeof(JsonPropertyNameAttribute))
|
||||
.Select(a => (string)a.ConstructorArguments.FirstOrDefault().Value)
|
||||
.FirstOrDefault() ?? p.Name;
|
||||
|
||||
return new
|
||||
{
|
||||
Name = name, PropName = name.ToLower() + "Prop", Property = p, Type = p.PropertyType,
|
||||
RealName = p.Name
|
||||
};
|
||||
})
|
||||
.OrderBy(p => p.Name)
|
||||
.ToArray();
|
||||
|
||||
var mungedName = type.FullName!.Replace(".", "_");
|
||||
c.Code($"public class {mungedName}Converter : JsonConverter<{type.FullName}> {{");
|
||||
c.Code(
|
||||
$"public override {type.FullName} Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {{");
|
||||
c.Code("if (reader.TokenType != JsonTokenType.StartObject)");
|
||||
c.Code(" throw new JsonException();");
|
||||
foreach (var member in members) c.Code($"{member.Type.FullName} {member.PropName} = default;");
|
||||
|
||||
c.Code("while (true) {");
|
||||
|
||||
c.Code("reader.Read();");
|
||||
c.Code("if (reader.TokenType == JsonTokenType.EndObject) {");
|
||||
c.Code("reader.Read();");
|
||||
c.Code("break;");
|
||||
c.Code("}");
|
||||
c.Code("var prop = reader.GetString();");
|
||||
c.Code("reader.Read();");
|
||||
c.Code("switch (prop) {");
|
||||
|
||||
foreach (var member in members)
|
||||
{
|
||||
c.Code($"case \"{member.Name}\":");
|
||||
c.Code(
|
||||
$" {member.PropName} = JsonSerializer.Deserialize<{member.Type.FullName}>(ref reader, options);");
|
||||
c.Code(" break;");
|
||||
}
|
||||
|
||||
c.Code("default:");
|
||||
c.Code(" reader.Skip();");
|
||||
c.Code(" break;");
|
||||
|
||||
c.Code("}");
|
||||
|
||||
c.Code("}");
|
||||
|
||||
c.Code($"return new {type.FullName} {{");
|
||||
|
||||
foreach (var member in members) c.Code($"{member.RealName} = {member.PropName},");
|
||||
|
||||
|
||||
c.Code("};");
|
||||
|
||||
c.Code("}");
|
||||
|
||||
c.Code(
|
||||
$"public override void Write(Utf8JsonWriter writer, {type.FullName} value, JsonSerializerOptions options) {{");
|
||||
|
||||
c.Code("writer.WriteStartObject();");
|
||||
c.Code($"writer.WriteString(\"$type\", \"{ReverseRegistry[type]}\");");
|
||||
|
||||
foreach (var member in members)
|
||||
{
|
||||
c.Code($"writer.WritePropertyName(\"{member.Name}\");");
|
||||
c.Code(
|
||||
$"JsonSerializer.Serialize<{member.Type.FullName}>(writer, value.{member.RealName}, options);");
|
||||
}
|
||||
|
||||
c.Code("writer.WriteEndObject();");
|
||||
|
||||
c.Code("}");
|
||||
|
||||
c.Code("}");
|
||||
}
|
||||
}
|
||||
|
||||
public void GenerateGeneric(CFile c)
|
||||
{
|
||||
var type = typeof(T);
|
||||
var mungedName = typeof(T).FullName!.Replace(".", "_");
|
||||
Name = name, PropName = name.ToLower() + "Prop", Property = p, Type = p.PropertyType,
|
||||
RealName = p.Name
|
||||
};
|
||||
})
|
||||
.OrderBy(p => p.Name)
|
||||
.ToArray();
|
||||
|
||||
var mungedName = type.FullName!.Replace(".", "_");
|
||||
c.Code($"public class {mungedName}Converter : JsonConverter<{type.FullName}> {{");
|
||||
|
||||
c.Code("public static void ConfigureServices(IServiceCollection services) {");
|
||||
|
||||
foreach (var tp in ReverseRegistry.Keys)
|
||||
c.Code($"services.AddSingleton<JsonConverter, {tp.FullName!.Replace(".", "_")}Converter>();");
|
||||
c.Code($"services.AddSingleton<JsonConverter, {mungedName}Converter>();");
|
||||
|
||||
c.Code("}");
|
||||
|
||||
c.Code(
|
||||
$"public override {type.FullName} Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {{");
|
||||
|
||||
c.Code("var cReader = reader;");
|
||||
c.Code("if (reader.TokenType != JsonTokenType.StartObject)");
|
||||
c.Code(" throw new JsonException();");
|
||||
c.Code("cReader.Read();");
|
||||
foreach (var member in members) c.Code($"{member.Type.FullName} {member.PropName} = default;");
|
||||
|
||||
c.Code("if (cReader.GetString() != \"$type\")");
|
||||
c.Code(" throw new JsonException();");
|
||||
c.Code("cReader.Read();");
|
||||
c.Code("var type = cReader.GetString();");
|
||||
c.Code("switch(type) {");
|
||||
foreach (var (alias, tp) in Registry)
|
||||
c.Code("while (true) {");
|
||||
|
||||
c.Code("reader.Read();");
|
||||
c.Code("if (reader.TokenType == JsonTokenType.EndObject) {");
|
||||
c.Code("reader.Read();");
|
||||
c.Code("break;");
|
||||
c.Code("}");
|
||||
c.Code("var prop = reader.GetString();");
|
||||
c.Code("reader.Read();");
|
||||
c.Code("switch (prop) {");
|
||||
|
||||
foreach (var member in members)
|
||||
{
|
||||
c.Code($"case \"{alias}\":");
|
||||
c.Code($" return JsonSerializer.Deserialize<{tp.FullName}>(ref reader, options)!;");
|
||||
c.Code($"case \"{member.Name}\":");
|
||||
c.Code(
|
||||
$" {member.PropName} = JsonSerializer.Deserialize<{member.Type.FullName}>(ref reader, options);");
|
||||
c.Code(" break;");
|
||||
}
|
||||
|
||||
c.Code("default:");
|
||||
c.Code(" throw new JsonException($\"No Type dispatch for {type}\");");
|
||||
c.Code(" reader.Skip();");
|
||||
c.Code(" break;");
|
||||
|
||||
c.Code("}");
|
||||
|
||||
c.Code("}");
|
||||
|
||||
c.Code($"return new {type.FullName} {{");
|
||||
|
||||
foreach (var member in members) c.Code($"{member.RealName} = {member.PropName},");
|
||||
|
||||
|
||||
c.Code("};");
|
||||
|
||||
c.Code("}");
|
||||
|
||||
c.Code(
|
||||
$"public override void Write(Utf8JsonWriter writer, {type.FullName} value, JsonSerializerOptions options) {{");
|
||||
|
||||
c.Code("switch (value) {");
|
||||
var idx = 0;
|
||||
c.Code("writer.WriteStartObject();");
|
||||
c.Code($"writer.WriteString(\"$type\", \"{ReverseRegistry[type]}\");");
|
||||
|
||||
int Distance(Type t)
|
||||
foreach (var member in members)
|
||||
{
|
||||
var depth = 0;
|
||||
var b = t;
|
||||
while (b != null)
|
||||
{
|
||||
b = b.BaseType;
|
||||
depth += 1;
|
||||
}
|
||||
|
||||
return depth;
|
||||
c.Code($"writer.WritePropertyName(\"{member.Name}\");");
|
||||
c.Code(
|
||||
$"JsonSerializer.Serialize<{member.Type.FullName}>(writer, value.{member.RealName}, options);");
|
||||
}
|
||||
|
||||
foreach (var t in ReverseRegistry.Keys.OrderByDescending(t => Distance(t)))
|
||||
{
|
||||
c.Code($"case {t.FullName} v{idx}:");
|
||||
c.Code($" JsonSerializer.Serialize(writer, v{idx}, options);");
|
||||
c.Code(" return;");
|
||||
idx += 1;
|
||||
}
|
||||
c.Code("writer.WriteEndObject();");
|
||||
|
||||
c.Code("}");
|
||||
|
||||
c.Code("}");
|
||||
|
||||
c.Code("}");
|
||||
}
|
||||
|
||||
public void GenerateAll(CFile cfile)
|
||||
{
|
||||
GenerateGeneric(cfile);
|
||||
GenerateSpecific(cfile);
|
||||
}
|
||||
}
|
||||
|
||||
public void GenerateGeneric(CFile c)
|
||||
{
|
||||
var type = typeof(T);
|
||||
var mungedName = typeof(T).FullName!.Replace(".", "_");
|
||||
|
||||
c.Code($"public class {mungedName}Converter : JsonConverter<{type.FullName}> {{");
|
||||
|
||||
c.Code("public static void ConfigureServices(IServiceCollection services) {");
|
||||
|
||||
foreach (var tp in ReverseRegistry.Keys)
|
||||
c.Code($"services.AddSingleton<JsonConverter, {tp.FullName!.Replace(".", "_")}Converter>();");
|
||||
c.Code($"services.AddSingleton<JsonConverter, {mungedName}Converter>();");
|
||||
|
||||
c.Code("}");
|
||||
|
||||
c.Code(
|
||||
$"public override {type.FullName} Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {{");
|
||||
|
||||
c.Code("var cReader = reader;");
|
||||
c.Code("if (reader.TokenType != JsonTokenType.StartObject)");
|
||||
c.Code(" throw new JsonException();");
|
||||
c.Code("cReader.Read();");
|
||||
|
||||
c.Code("if (cReader.GetString() != \"$type\")");
|
||||
c.Code(" throw new JsonException();");
|
||||
c.Code("cReader.Read();");
|
||||
c.Code("var type = cReader.GetString();");
|
||||
c.Code("switch(type) {");
|
||||
foreach (var (alias, tp) in Registry)
|
||||
{
|
||||
c.Code($"case \"{alias}\":");
|
||||
c.Code($" return JsonSerializer.Deserialize<{tp.FullName}>(ref reader, options)!;");
|
||||
}
|
||||
|
||||
c.Code("default:");
|
||||
c.Code(" throw new JsonException($\"No Type dispatch for {type}\");");
|
||||
|
||||
c.Code("}");
|
||||
c.Code("}");
|
||||
|
||||
c.Code(
|
||||
$"public override void Write(Utf8JsonWriter writer, {type.FullName} value, JsonSerializerOptions options) {{");
|
||||
|
||||
c.Code("switch (value) {");
|
||||
var idx = 0;
|
||||
|
||||
int Distance(Type t)
|
||||
{
|
||||
var depth = 0;
|
||||
var b = t;
|
||||
while (b != null)
|
||||
{
|
||||
b = b.BaseType;
|
||||
depth += 1;
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
foreach (var t in ReverseRegistry.Keys.OrderByDescending(t => Distance(t)))
|
||||
{
|
||||
c.Code($"case {t.FullName} v{idx}:");
|
||||
c.Code($" JsonSerializer.Serialize(writer, v{idx}, options);");
|
||||
c.Code(" return;");
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
c.Code("}");
|
||||
|
||||
c.Code("}");
|
||||
|
||||
c.Code("}");
|
||||
}
|
||||
|
||||
public void GenerateAll(CFile cfile)
|
||||
{
|
||||
GenerateGeneric(cfile);
|
||||
GenerateSpecific(cfile);
|
||||
}
|
||||
}
|
@ -2,20 +2,19 @@
|
||||
using Wabbajack.DTOs.BSA.FileStates;
|
||||
using Wabbajack.DTOs.DownloadStates;
|
||||
|
||||
namespace Wabbajack.DTOs.ConverterGenerators
|
||||
namespace Wabbajack.DTOs.ConverterGenerators;
|
||||
|
||||
internal class Program
|
||||
{
|
||||
internal class Program
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
var cfile = new CFile();
|
||||
new PolymorphicGenerator<IDownloadState>().GenerateAll(cfile);
|
||||
new PolymorphicGenerator<IArchive>().GenerateAll(cfile);
|
||||
new PolymorphicGenerator<Directive>().GenerateAll(cfile);
|
||||
new PolymorphicGenerator<AFile>().GenerateAll(cfile);
|
||||
var cfile = new CFile();
|
||||
new PolymorphicGenerator<IDownloadState>().GenerateAll(cfile);
|
||||
new PolymorphicGenerator<IArchive>().GenerateAll(cfile);
|
||||
new PolymorphicGenerator<Directive>().GenerateAll(cfile);
|
||||
new PolymorphicGenerator<AFile>().GenerateAll(cfile);
|
||||
|
||||
|
||||
cfile.Write(@"..\Wabbajack.DTOs\JsonConverters\Generated.cs");
|
||||
}
|
||||
cfile.Write(@"..\Wabbajack.DTOs\JsonConverters\Generated.cs");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user