diff --git a/Samples/Dgmjr.Enumerations.CodeGenerator.Samples.csproj b/Samples/Dgmjr.Enumerations.CodeGenerator.Samples.csproj index 3f5cfb6..ce4bbf8 100644 --- a/Samples/Dgmjr.Enumerations.CodeGenerator.Samples.csproj +++ b/Samples/Dgmjr.Enumerations.CodeGenerator.Samples.csproj @@ -22,7 +22,7 @@ Samples for the DGMJR Enumeration data structure generator - + diff --git a/Samples/Dgmjr.Enumerations.CodeGenerator.Samples.sln b/Samples/Dgmjr.Enumerations.CodeGenerator.Samples.sln index b71bb08..de1b012 100644 --- a/Samples/Dgmjr.Enumerations.CodeGenerator.Samples.sln +++ b/Samples/Dgmjr.Enumerations.CodeGenerator.Samples.sln @@ -8,7 +8,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\..\..\..\..\Packages\Versions.Local.props = ..\..\..\..\..\Packages\Versions.Local.props EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Enumerations.CodeGenerator.Samples", "Dgmjr.Enumerations.CodeGenerator.Samples.csproj", "{166E5F60-3449-4A11-AA22-092E10E19564}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Enumerations.CodeGenerator.Samples", "Dgmjr.Enumerations.CodeGenerator.Samples.csproj", "{72AF42ED-1B8A-46BA-BDB6-E666F7019AF7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -20,18 +20,18 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {166E5F60-3449-4A11-AA22-092E10E19564}.Local|Any CPU.ActiveCfg = Local|Any CPU - {166E5F60-3449-4A11-AA22-092E10E19564}.Local|Any CPU.Build.0 = Local|Any CPU - {166E5F60-3449-4A11-AA22-092E10E19564}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {166E5F60-3449-4A11-AA22-092E10E19564}.Debug|Any CPU.Build.0 = Debug|Any CPU - {166E5F60-3449-4A11-AA22-092E10E19564}.Testing|Any CPU.ActiveCfg = Testing|Any CPU - {166E5F60-3449-4A11-AA22-092E10E19564}.Testing|Any CPU.Build.0 = Testing|Any CPU - {166E5F60-3449-4A11-AA22-092E10E19564}.Staging|Any CPU.ActiveCfg = Staging|Any CPU - {166E5F60-3449-4A11-AA22-092E10E19564}.Staging|Any CPU.Build.0 = Staging|Any CPU - {166E5F60-3449-4A11-AA22-092E10E19564}.Production|Any CPU.ActiveCfg = Local|Any CPU - {166E5F60-3449-4A11-AA22-092E10E19564}.Production|Any CPU.Build.0 = Local|Any CPU - {166E5F60-3449-4A11-AA22-092E10E19564}.Release|Any CPU.ActiveCfg = Release|Any CPU - {166E5F60-3449-4A11-AA22-092E10E19564}.Release|Any CPU.Build.0 = Release|Any CPU + {72AF42ED-1B8A-46BA-BDB6-E666F7019AF7}.Local|Any CPU.ActiveCfg = Local|Any CPU + {72AF42ED-1B8A-46BA-BDB6-E666F7019AF7}.Local|Any CPU.Build.0 = Local|Any CPU + {72AF42ED-1B8A-46BA-BDB6-E666F7019AF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {72AF42ED-1B8A-46BA-BDB6-E666F7019AF7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {72AF42ED-1B8A-46BA-BDB6-E666F7019AF7}.Testing|Any CPU.ActiveCfg = Testing|Any CPU + {72AF42ED-1B8A-46BA-BDB6-E666F7019AF7}.Testing|Any CPU.Build.0 = Testing|Any CPU + {72AF42ED-1B8A-46BA-BDB6-E666F7019AF7}.Staging|Any CPU.ActiveCfg = Staging|Any CPU + {72AF42ED-1B8A-46BA-BDB6-E666F7019AF7}.Staging|Any CPU.Build.0 = Staging|Any CPU + {72AF42ED-1B8A-46BA-BDB6-E666F7019AF7}.Production|Any CPU.ActiveCfg = Local|Any CPU + {72AF42ED-1B8A-46BA-BDB6-E666F7019AF7}.Production|Any CPU.Build.0 = Local|Any CPU + {72AF42ED-1B8A-46BA-BDB6-E666F7019AF7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {72AF42ED-1B8A-46BA-BDB6-E666F7019AF7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Tests/Dgmjr.Enumerations.CodeGenerator.Tests.csproj b/Tests/Dgmjr.Enumerations.CodeGenerator.Tests.csproj index d2c402a..f1ee1a5 100644 --- a/Tests/Dgmjr.Enumerations.CodeGenerator.Tests.csproj +++ b/Tests/Dgmjr.Enumerations.CodeGenerator.Tests.csproj @@ -19,6 +19,7 @@ false true true + 8037C3AA-FC4B-4379-8C4E-0517FC90E94E @@ -40,7 +41,7 @@ - + diff --git a/Tests/Dgmjr.Enumerations.CodeGenerator.Tests.sln b/Tests/Dgmjr.Enumerations.CodeGenerator.Tests.sln index a9ed9ac..a5e21d2 100644 --- a/Tests/Dgmjr.Enumerations.CodeGenerator.Tests.sln +++ b/Tests/Dgmjr.Enumerations.CodeGenerator.Tests.sln @@ -1,4 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 12.00 +# Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B283EBC2-E01F-412D-9339-FD56EF114549}" ProjectSection(SolutionItems) = preProject ..\..\..\..\..\Directory.Build.props = ..\..\..\..\..\Directory.Build.props diff --git a/src/Constants.cs b/src/Constants.cs index 3aa2988..f8a4cc2 100644 --- a/src/Constants.cs +++ b/src/Constants.cs @@ -1,3 +1,4 @@ +using System.Reflection.PortableExecutable; /* * Constants.cs * @@ -51,6 +52,7 @@ internal static class Constants public const string DisplayAttribute = nameof(DisplayAttribute); public const string DisplayName = nameof(DisplayName); public const string Enumeration = nameof(Enumeration); + public const string EnumerationJsonConverter = nameof(EnumerationJsonConverter); public const string GenerateEnumerationClassAttribute = nameof( GenerateEnumerationClassAttribute ); @@ -144,6 +146,10 @@ internal static class Constants private static readonly string IEnumerationDeclaration = typeof(Constants).Assembly.ReadAssemblyResourceAllText($"I{Enumeration}.{scriban}"); + private static readonly string EnumerationJsonConverterDeclaration = + typeof(Constants).Assembly.ReadAssemblyResourceAllText( + $"{EnumerationJsonConverter}.{scriban}" + ); // """ // namespace {{ dto_namespace }}.Abstractions; @@ -194,6 +200,10 @@ internal static class Constants nameof(NestedEnumerationTypeDeclaration) ); + private static readonly Template EnumerationJsonConverterDeclarationTemplate = Template.Parse( + EnumerationJsonConverterDeclaration + ); + public static string RenderHeader(string filename) => //Comment; HeaderTemplate.Render(new FilenameAndTimestampTuple(filename)); @@ -204,6 +214,10 @@ internal static class Constants // DateTimeOffset.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.ffffzzzZ") // ); + public static string RenderJsonConverterDeclaration(EnumerationFieldDto e) => //Comment; + // IEnumerationDeclarationTemplate.Render(e); + EnumerationJsonConverterDeclarationTemplate.Render(e); + public static string RenderIEnumerationDeclaration(EnumerationDto e) => //Comment; // IEnumerationDeclarationTemplate.Render(e); IEnumerationDeclaration diff --git a/src/Dgmjr.Enumerations.CodeGenerator.csproj b/src/Dgmjr.Enumerations.CodeGenerator.csproj index a06821a..ec53a96 100644 --- a/src/Dgmjr.Enumerations.CodeGenerator.csproj +++ b/src/Dgmjr.Enumerations.CodeGenerator.csproj @@ -18,6 +18,7 @@ This package contains a source generator, which generates enumeration data structures from enum types. true $(NoWarn);S3903;RCS1110;S3604 + C4622771-2A7B-42E6-9B3C-8F71CDD7E65B @@ -34,7 +35,7 @@ - + diff --git a/src/Dgmjr.Enumerations.CodeGenerator.sln b/src/Dgmjr.Enumerations.CodeGenerator.sln index 533f957..132e9e5 100644 --- a/src/Dgmjr.Enumerations.CodeGenerator.sln +++ b/src/Dgmjr.Enumerations.CodeGenerator.sln @@ -1,5 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# +# Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B283EBC2-E01F-412D-9339-FD56EF114549}" ProjectSection(SolutionItems) = preProject ..\..\..\..\..\Directory.Build.props = ..\..\..\..\..\Directory.Build.props @@ -8,30 +8,30 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\..\..\..\..\Packages\Versions.Local.props = ..\..\..\..\..\Packages\Versions.Local.props EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Enumerations.CodeGenerator", "Dgmjr.Enumerations.CodeGenerator.csproj", "{AC845DE2-CF87-49D2-A8A3-2019389FF879}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Enumerations.CodeGenerator", "Dgmjr.Enumerations.CodeGenerator.csproj", "{C4622771-2A7B-42E6-9B3C-8F71CDD7E65B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Local|Any CPU = Local|Any CPU Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 + Testing|Any CPU = Testing|Any CPU + Staging|Any CPU = Staging|Any CPU + Production|Any CPU = Production|Any CPU Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {AC845DE2-CF87-49D2-A8A3-2019389FF879}.Local|Any CPU.ActiveCfg = Local|Any CPU - {AC845DE2-CF87-49D2-A8A3-2019389FF879}.Local|Any CPU.Build.0 = Local|Any CPU - {AC845DE2-CF87-49D2-A8A3-2019389FF879}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AC845DE2-CF87-49D2-A8A3-2019389FF879}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AC845DE2-CF87-49D2-A8A3-2019389FF879}.Testing|Any CPU.ActiveCfg = Testing|Any CPU - {AC845DE2-CF87-49D2-A8A3-2019389FF879}.Testing|Any CPU.Build.0 = Testing|Any CPU - {AC845DE2-CF87-49D2-A8A3-2019389FF879}.Staging|Any CPU.ActiveCfg = Staging|Any CPU - {AC845DE2-CF87-49D2-A8A3-2019389FF879}.Staging|Any CPU.Build.0 = Staging|Any CPU - {AC845DE2-CF87-49D2-A8A3-2019389FF879}.Production|Any CPU.ActiveCfg = Local|Any CPU - {AC845DE2-CF87-49D2-A8A3-2019389FF879}.Production|Any CPU.Build.0 = Local|Any CPU - {AC845DE2-CF87-49D2-A8A3-2019389FF879}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AC845DE2-CF87-49D2-A8A3-2019389FF879}.Release|Any CPU.Build.0 = Release|Any CPU + {C4622771-2A7B-42E6-9B3C-8F71CDD7E65B}.Local|Any CPU.ActiveCfg = Local|Any CPU + {C4622771-2A7B-42E6-9B3C-8F71CDD7E65B}.Local|Any CPU.Build.0 = Local|Any CPU + {C4622771-2A7B-42E6-9B3C-8F71CDD7E65B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C4622771-2A7B-42E6-9B3C-8F71CDD7E65B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C4622771-2A7B-42E6-9B3C-8F71CDD7E65B}.Testing|Any CPU.ActiveCfg = Testing|Any CPU + {C4622771-2A7B-42E6-9B3C-8F71CDD7E65B}.Testing|Any CPU.Build.0 = Testing|Any CPU + {C4622771-2A7B-42E6-9B3C-8F71CDD7E65B}.Staging|Any CPU.ActiveCfg = Staging|Any CPU + {C4622771-2A7B-42E6-9B3C-8F71CDD7E65B}.Staging|Any CPU.Build.0 = Staging|Any CPU + {C4622771-2A7B-42E6-9B3C-8F71CDD7E65B}.Production|Any CPU.ActiveCfg = Local|Any CPU + {C4622771-2A7B-42E6-9B3C-8F71CDD7E65B}.Production|Any CPU.Build.0 = Local|Any CPU + {C4622771-2A7B-42E6-9B3C-8F71CDD7E65B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C4622771-2A7B-42E6-9B3C-8F71CDD7E65B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/EnumerationGenerator.cs b/src/EnumerationGenerator.cs index 6e7c9a1..d2f5654 100644 --- a/src/EnumerationGenerator.cs +++ b/src/EnumerationGenerator.cs @@ -246,6 +246,27 @@ var enumSymbol in values {nestedClassDeclaration.NormalizeWhitespace().GetText()} """ ); + // Generate the nested class declaration + var jsonConverterDeclaration = RenderJsonConverterDeclaration( + new EnumerationFieldDto( + enumSymbol.GetMembers(fieldName).OfType().FirstOrDefault(), + dataStructureType, + dtoTypeName, + dtoNamespace, + enumSymbol.EnumUnderlyingType.ToDisplayString(), + enumSymbol.MetadataName, + baseType + ) + ); + + fileName = $"{dtoTypeName}.{fieldName}JsonConverter.g.cs"; + context.AddSource( + fileName, + $""" + {RenderHeader(fileName)} + {ParseCompilationUnit(jsonConverterDeclaration).NormalizeWhitespace().GetText()} + """ + ); } } } diff --git a/src/Resources/EnumerationJsonConverter.scriban b/src/Resources/EnumerationJsonConverter.scriban new file mode 100644 index 0000000..d0108d7 --- /dev/null +++ b/src/Resources/EnumerationJsonConverter.scriban @@ -0,0 +1,31 @@ +namespace {{ dto_namespace }}; +using {{ dto_namespace }}.Abstractions; + +public partial {{ data_structure_type }} @{{ dto_type_name }} +{ + {{ compiler_generated_attributes }} + public class {{ field_name }}JsonConverter : System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(type typeToConvert) => + typeof(I{{ dto_type_name }}).IsAssignableFrom(typeToConvert); + + public override I{{ dto_type_name }} Read( + ref Utf8JsonReader reader, + type typeToConvert, + JsonSerializerOptions options + ) => + @{{ dto_type_name }}.Parse( + reader.TokenType == JsonTokenType.String + ? reader.GetString() + : reader.GetInt32().ToString() + ); + + public override void Write(Utf8JsonWriter writer, I{{ dto_type_name }} value, Jso options) => + writer.WriteStringValue(value.ShortName); + } + + public class {{ field_name }}JsonConverterAttribute : System.Text.Json.Serialization.JsonConverterAttribute + { + public {{ field_name }}JsonConverterAttribute() : base(typeof({{ field_name }}JsonConverter)) { } + } +} diff --git a/src/Resources/Header.scriban b/src/Resources/Header.scriban index 810362a..aa2d412 100644 --- a/src/Resources/Header.scriban +++ b/src/Resources/Header.scriban @@ -19,6 +19,9 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Text.RegularExpressions; +using System.Text.Json.Serialization; +using System.Text.Json; +using System.Xml.Serialization; #if NET7_0_OR_GREATER using StringSyntax = System.Diagnostics.CodeAnalysis.StringSyntaxAttribute; #endif diff --git a/src/Resources/IEnumeration.scriban b/src/Resources/IEnumeration.scriban index 5c27843..30d57f0 100644 --- a/src/Resources/IEnumeration.scriban +++ b/src/Resources/IEnumeration.scriban @@ -9,6 +9,7 @@ IHaveAName, IHaveAValue<{{ enum_namespace }}.{{ enum_type_name }}>, IHaveADescription, IHaveAUri, + IHaveAuri, IHaveAUriString, IHaveSynonyms, IHaveAShortName, diff --git a/src/Resources/NestedEnumerationType.scriban b/src/Resources/NestedEnumerationType.scriban index db61473..fe31513 100644 --- a/src/Resources/NestedEnumerationType.scriban +++ b/src/Resources/NestedEnumerationType.scriban @@ -6,27 +6,10 @@ public partial {{ data_structure_type }} @{{ dto_type_name }} {{ if base_type != /// {{ description }} /// {{ compiler_generated_attributes }} + [{{ field_name }}JsonConverterAttribute] public partial {{ data_structure_type }} @{{ field_name }} : {{ if base_type != "" && base_type != null }}{{ dto_type_name }}, {{ end }} - I{{ enumeration_name }}, - IHaveAName, - IHaveAValue, - IHaveAValue<{{ enum_underlying_type }}>, - IHaveAValue<{{ enum_namespace }}.{{ enum_type }}>, - IHaveADescription, - IHaveAUri, - IHaveAuri, - IHaveAUriString, - IHaveSynonyms, - IHaveAShortName, - IHaveAGuid, - IHaveAGuidString, - IHaveADisplayName, - IIdentifiable, - IIdentifiable<{{ enum_underlying_type }}>, - IConvertible, - IEquatable<{{ enum_underlying_type }}>, - IEquatable + I{{ enumeration_name }} { /// The {{ enumeration_name }}'s value /// @@ -79,80 +62,98 @@ public partial {{ data_structure_type }} @{{ dto_type_name }} {{ if base_type != /// The {{ enumeration_name }}'s synonyms /// {{ synonyms }} + [JsonIgnore, XmlIgnore] public static readonly string[] Synonyms = new string[] { {{ synonyms }} }; /// The {{ enumeration_name }}'s value /// + [JsonIgnore, XmlIgnore] {{ enum_namespace }}.{{ enum_type }} IHaveAValue<{{ enum_namespace }}.{{ enum_type }}>.Value => Value; /// The {{ enumeration_name }}'s value as a(n) /// {{ id }} + [JsonIgnore, XmlIgnore] {{ enum_underlying_type }} IHaveAValue<{{ enum_underlying_type }}>.Value => Id; /// The {{ enumeration_name }}'s GUID /// {{ guid_string }} + [JsonIgnore, XmlIgnore] guid IHaveAGuid.Guid => Guid; /// The {{ enumeration_name }}'s GUID /// {{ guid_string }} + [JsonIgnore, XmlIgnore] string IHaveAGuidString.GuidString => GuidString; /// The {{ enumeration_name }}'s display name /// {{ display_name }} + [JsonIgnore, XmlIgnore] string IHaveADisplayName.DisplayName => DisplayName; /// The {{ enumeration_name }}'s value /// + [JsonIgnore, XmlIgnore] object IHaveAValue.Value => Value; /// A short description of the {{ enumeration_name }} /// {{ description }} + [JsonIgnore, XmlIgnore] string IHaveADescription.Description => Description; /// The {{ enumeration_name }}'s name /// {{ field_name }} + [JsonIgnore, XmlIgnore] string IHaveAName.Name => Name; /// The {{ enumeration_name }}'s short name /// {{ short_name }} + [JsonIgnore, XmlIgnore] string IHaveAShortName.ShortName => ShortName; /// The {{ enumeration_name }}'s URI /// {{ uri_string }} + [JsonIgnore, XmlIgnore] Uri IHaveAUri.Uri => Uri; /// The {{ enumeration_name }}'s URI /// {{ uri_string }} + [JsonIgnore, XmlIgnore] string IHaveAUriString.UriString => UriString; /// The {{ enumeration_name }}'s URI /// {{ uri_string }} + [JsonIgnore, XmlIgnore] System.uri IHaveAuri.Uri => System.uri.From(Uri.ToString()); /// The order in which the {{ enumeration_name }} should appear /// {{ order }} /// 0 + [JsonIgnore, XmlIgnore] int I{{ enumeration_name }}.Order => Order; /// The {{ enumeration_name }}'s URI /// {{ uri_string }} + [JsonIgnore, XmlIgnore] uri I{{ dto_type_name }}.Uri => uri.From(Uri.ToString()); /// The {{ enumeration_name }}'s Id as an /// {{ id }} + [JsonIgnore, XmlIgnore] object IIdentifiable.Id => Id; /// The {{ enumeration_name }}'s Id as a(n) /// {{ id }} + [JsonIgnore, XmlIgnore] {{ enum_underlying_type }} IIdentifiable<{{ enum_underlying_type }}>.Id => Id; /// The {{ enumeration_name }}'s synonyms /// {{ synonyms }} + [JsonIgnore, XmlIgnore] string[] IHaveSynonyms.Synonyms { get => Synonyms; init { } } - bool IEquatable.Equals(I{{ enumeration_name }} value) + bool IEquatable.Equals(I{{ enumeration_name }}? value) => this == value; bool IEquatable<{{ enum_underlying_type }}>.Equals({{ enum_underlying_type }} value)