diff --git a/src/NetEscapades.EnumGenerators/SourceGenerationHelper.cs b/src/NetEscapades.EnumGenerators/SourceGenerationHelper.cs index d3e4e3b..ea7f0ca 100644 --- a/src/NetEscapades.EnumGenerators/SourceGenerationHelper.cs +++ b/src/NetEscapades.EnumGenerators/SourceGenerationHelper.cs @@ -4,842 +4,1218 @@ namespace NetEscapades.EnumGenerators; public static class SourceGenerationHelper { - private const string Header = @"//------------------------------------------------------------------------------ -// -// This code was generated by the NetEscapades.EnumGenerators source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ + private const string Header = """ + //------------------------------------------------------------------------------ + // + // This code was generated by the NetEscapades.EnumGenerators source generator + // + // Changes to this file may cause incorrect behavior and will be lost if + // the code is regenerated. + // + //------------------------------------------------------------------------------ -#nullable enable"; + #nullable enable + """; - public const string Attribute = Header + @" + public const string Attribute = Header + """ -#if NETESCAPADES_ENUMGENERATORS_EMBED_ATTRIBUTES -namespace NetEscapades.EnumGenerators -{ - /// - /// Add to enums to indicate that extension methods should be generated for the type - /// - [global::System.AttributeUsage(global::System.AttributeTargets.Enum)] - [global::System.Diagnostics.Conditional(""NETESCAPADES_ENUMGENERATORS_USAGES"")] -#if NET5_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = ""Generated by the NetEscapades.EnumGenerators source generator."")] -#else - [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -#endif - public class EnumExtensionsAttribute : global::System.Attribute - { - /// - /// The namespace to generate the extension class. - /// If not provided, the namespace of the enum will be used - /// - public string? ExtensionClassNamespace { get; set; } - - /// - /// The name to use for the extension class. - /// If not provided, the enum name with ""Extensions"" will be used. - /// For example for an Enum called StatusCodes, the default name - /// will be StatusCodesExtensions - /// - public string? ExtensionClassName { get; set; } - } + + #if NETESCAPADES_ENUMGENERATORS_EMBED_ATTRIBUTES + namespace NetEscapades.EnumGenerators + { + /// + /// Add to enums to indicate that extension methods should be generated for the type + /// + [global::System.AttributeUsage(global::System.AttributeTargets.Enum)] + [global::System.Diagnostics.Conditional("NETESCAPADES_ENUMGENERATORS_USAGES")] + #if NET5_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = "Generated by the NetEscapades.EnumGenerators source generator.")] + #else + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + #endif + public class EnumExtensionsAttribute : global::System.Attribute + { + /// + /// The namespace to generate the extension class. + /// If not provided, the namespace of the enum will be used + /// + public string? ExtensionClassNamespace { get; set; } + + /// + /// The name to use for the extension class. + /// If not provided, the enum name with "Extensions" will be used. + /// For example for an Enum called StatusCodes, the default name + /// will be StatusCodesExtensions + /// + public string? ExtensionClassName { get; set; } + } - /// - /// Add to enums to indicate that extension methods should be generated for the type - /// - [System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple = true)] - [System.Diagnostics.Conditional(""NETESCAPADES_ENUMGENERATORS_USAGES"")] -#if NET5_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = ""Generated by the NetEscapades.EnumGenerators source generator."")] -#else - [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] -#endif - public class EnumExtensionsAttribute : System.Attribute - where T: System.Enum - { - /// - /// The namespace to generate the extension class. - /// If not provided, the namespace of the enum will be used - /// - public string? ExtensionClassNamespace { get; set; } - - /// - /// The name to use for the extension class. - /// If not provided, the enum name with """"Extensions"""" will be used. - /// For example for an Enum called StatusCodes, the default name - /// will be StatusCodesExtensions - /// - public string? ExtensionClassName { get; set; } - } -} -#endif -"; + /// + /// Add to enums to indicate that extension methods should be generated for the type + /// + [System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple = true)] + [System.Diagnostics.Conditional("NETESCAPADES_ENUMGENERATORS_USAGES")] + #if NET5_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = "Generated by the NetEscapades.EnumGenerators source generator.")] + #else + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + #endif + public class EnumExtensionsAttribute : System.Attribute + where T: System.Enum + { + /// + /// The namespace to generate the extension class. + /// If not provided, the namespace of the enum will be used + /// + public string? ExtensionClassNamespace { get; set; } + + /// + /// The name to use for the extension class. + /// If not provided, the enum name with ""Extensions"" will be used. + /// For example for an Enum called StatusCodes, the default name + /// will be StatusCodesExtensions + /// + public string? ExtensionClassName { get; set; } + } + } + #endif + + """; public static string GenerateExtensionClass(StringBuilder sb, in EnumToGenerate enumToGenerate) { sb .Append(Header) - .Append(@" -#if NETCOREAPP && !NETCOREAPP2_0 && !NETCOREAPP1_1 && !NETCOREAPP1_0 -using System; -#endif -"); + .Append(""" + + #if NETCOREAPP && !NETCOREAPP2_0 && !NETCOREAPP1_1 && !NETCOREAPP1_0 + using System; + #endif + + """); if (!string.IsNullOrEmpty(enumToGenerate.Namespace)) { - sb.Append(@" -namespace ").Append(enumToGenerate.Namespace).Append(@" -{"); + sb.Append(""" + + namespace + """).Append(enumToGenerate.Namespace).Append(""" + + { + """); } var fullyQualifiedName = $"global::{enumToGenerate.FullyQualifiedName}"; - sb.Append(@" - /// - /// Extension methods for - /// - [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""NetEscapades.EnumGenerators"", """).Append(Constants.Version).Append(@""")] - ").Append(enumToGenerate.IsPublic ? "public" : "internal").Append(@" static partial class ").Append(enumToGenerate.Name).Append(@" - { - /// - /// The number of members in the enum. - /// This is a non-distinct count of defined names. - /// - public const int Length = ").Append(enumToGenerate.Names.Count).Append(";").Append(@" - - /// - /// Returns the string representation of the value. - /// If the attribute is decorated with a [Display] attribute, then - /// uses the provided value. Otherwise uses the name of the member, equivalent to - /// calling ToString() on . - /// - /// The value to retrieve the string value for - /// The string representation of the value - public static string ToStringFast(this ").Append(fullyQualifiedName).Append(@" value) - => value switch - {"); - foreach (var member in enumToGenerate.Names) + sb.Append(""" + + /// + /// Extension methods for + /// + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("NetEscapades.EnumGenerators", " + """ + ).Append(Constants.Version).Append(""" + ")] + + """ + ).Append(enumToGenerate.IsPublic ? "public" : "internal").Append(" static partial class ").Append(enumToGenerate.Name).Append(""" + + { + /// + /// The number of members in the enum. + /// This is a non-distinct count of defined names. + /// + public const int Length = + """ + ).Append(enumToGenerate.Names.Count).Append(";").Append(""" + + + /// + /// Returns the string representation of the value. + /// If the attribute is decorated with a [Display] attribute, then + /// uses the provided value. Otherwise uses the name of the member, equivalent to + /// calling ToString() on . + /// + /// The value to retrieve the string value for + /// The string representation of the value + public static string ToStringFast(this + """ + ).Append(fullyQualifiedName).Append(""" + value) + => value switch + { + """); + foreach (var (Key, Value) in enumToGenerate.Names) { - sb.Append(@" - ").Append(fullyQualifiedName).Append('.').Append(member.Key) + sb.Append(""" + + + """).Append(fullyQualifiedName).Append('.').Append(Key) .Append(" => "); - if (member.Value.DisplayName is null) + if (Value.DisplayName is null) { - sb.Append("nameof(").Append(fullyQualifiedName).Append('.').Append(member.Key).Append("),"); + sb.Append("nameof(").Append(fullyQualifiedName).Append('.').Append(Key).Append("),"); } else { - sb.Append('"').Append(member.Value.DisplayName).Append(@""","); + sb.Append('"').Append(Value.DisplayName).Append(""" + ", + """); } } - sb.Append(@" - _ => value.ToString(), - };"); + sb.Append(""" + + _ => value.ToString(), + }; + """); if (enumToGenerate.HasFlags) { - sb.Append(@" - - /// - /// Determines whether one or more bit fields are set in the current instance. - /// Equivalent to calling on . - /// - /// The value of the instance to investigate - /// The flag to check for - /// true if the fields set in the flag are also set in the current instance; otherwise false. - /// If the underlying value of is zero, the method returns true. - /// This is consistent with the behaviour of - public static bool HasFlagFast(this ").Append(fullyQualifiedName).Append(@" value, ").Append(fullyQualifiedName).Append(@" flag) - => flag == 0 ? true : (value & flag) == flag;"); + sb.Append(""" + + + /// + /// Determines whether one or more bit fields are set in the current instance. + /// Equivalent to calling on . + /// + /// The value of the instance to investigate + /// The flag to check for + /// true if the fields set in the flag are also set in the current instance; otherwise false. + /// If the underlying value of is zero, the method returns true. + /// This is consistent with the behaviour of + public static bool HasFlagFast(this + """ + ).Append(fullyQualifiedName).Append(" value, ").Append(fullyQualifiedName).Append(""" + flag) + => flag == 0 ? true : (value & flag) == flag; + """); } - sb.Append(@" - - /// - /// Returns a boolean telling whether the given enum value exists in the enumeration. - /// - /// The value to check if it's defined - /// true if the value exists in the enumeration, false otherwise - public static bool IsDefined(").Append(fullyQualifiedName).Append(@" value) - => value switch - {"); - foreach (var member in enumToGenerate.Names) + sb.Append(""" + + + /// + /// Returns a boolean telling whether the given enum value exists in the enumeration. + /// + /// The value to check if it's defined + /// true if the value exists in the enumeration, false otherwise + public static bool IsDefined( + """ + ).Append(fullyQualifiedName).Append(""" + value) + => value switch + { + """); + foreach (var (Key, _) in enumToGenerate.Names) { - sb.Append(@" - ").Append(fullyQualifiedName).Append('.').Append(member.Key) + sb.Append(""" + + + """).Append(fullyQualifiedName).Append('.').Append(Key) .Append(" => true,"); } - sb.Append(@" - _ => false, - };"); - - sb.Append(@" - - /// - /// Returns a boolean telling whether an enum with the given name exists in the enumeration. - /// - /// The name to check if it's defined - /// true if a member with the name exists in the enumeration, false otherwise - public static bool IsDefined(string name) => IsDefined(name, allowMatchingMetadataAttribute: false); - - /// - /// Returns a boolean telling whether an enum with the given name exists in the enumeration, - /// or if a member decorated with a [Display] attribute - /// with the required name exists. - /// - /// The name to check if it's defined - /// If true, considers the value of metadata attributes,otherwise ignores them - /// true if a member with the name exists in the enumeration, or a member is decorated - /// with a [Display] attribute with the name, false otherwise - public static bool IsDefined(string name, bool allowMatchingMetadataAttribute) - {"); + sb.Append(""" + + _ => false, + }; + """); + + sb.Append(""" + + + /// + /// Returns a boolean telling whether an enum with the given name exists in the enumeration. + /// + /// The name to check if it's defined + /// true if a member with the name exists in the enumeration, false otherwise + public static bool IsDefined(string name) => IsDefined(name, allowMatchingMetadataAttribute: false); + + /// + /// Returns a boolean telling whether an enum with the given name exists in the enumeration, + /// or if a member decorated with a [Display] attribute + /// with the required name exists. + /// + /// The name to check if it's defined + /// If true, considers the value of metadata attributes,otherwise ignores them + /// true if a member with the name exists in the enumeration, or a member is decorated + /// with a [Display] attribute with the name, false otherwise + public static bool IsDefined(string name, bool allowMatchingMetadataAttribute) + { + """); if (enumToGenerate.IsDisplayAttributeUsed) { - sb.Append(@" - var isDefinedInDisplayAttribute = false; - if (allowMatchingMetadataAttribute) - { - isDefinedInDisplayAttribute = name switch - {"); - foreach (var member in enumToGenerate.Names) + sb.Append(""" + + var isDefinedInDisplayAttribute = false; + if (allowMatchingMetadataAttribute) + { + isDefinedInDisplayAttribute = name switch + { + """); + foreach (var (_, Value) in enumToGenerate.Names) { - if (member.Value.DisplayName is not null && member.Value.IsDisplayNameTheFirstPresence) + if (Value.DisplayName is not null && Value.IsDisplayNameTheFirstPresence) { - sb.Append(@" - """).Append(member.Value.DisplayName).Append(@""" => true,"); + sb.Append(""" + + " + """ + ).Append(Value.DisplayName).Append(""" + " => true, + """); } } - sb.Append(@" - _ => false, - }; - } + sb.Append(""" - if (isDefinedInDisplayAttribute) - { - return true; - } + _ => false, + }; + } - "); + if (isDefinedInDisplayAttribute) + { + return true; + } + + + """); } - sb.Append(@" - return name switch - {"); - foreach (var member in enumToGenerate.Names) + sb.Append(""" + + return name switch + { + """); + foreach (var (Key, _) in enumToGenerate.Names) { - sb.Append(@" - nameof(").Append(fullyQualifiedName).Append('.').Append(member.Key).Append(@") => true,"); + sb.Append(""" + + nameof( + """).Append(fullyQualifiedName).Append('.').Append(Key).Append(") => true,"); } - sb.Append(@" - _ => false, - }; - }"); - - sb.Append(@" - -#if NETCOREAPP && !NETCOREAPP2_0 && !NETCOREAPP1_1 && !NETCOREAPP1_0 - /// - /// Returns a boolean telling whether an enum with the given name exists in the enumeration - /// - /// The name to check if it's defined - /// true if a member with the name exists in the enumeration, false otherwise - public static bool IsDefined(in ReadOnlySpan name) => IsDefined(name, allowMatchingMetadataAttribute: false); - - /// - /// Returns a boolean telling whether an enum with the given name exists in the enumeration, - /// or optionally if a member decorated with a [Display] attribute - /// with the required name exists. - /// Slower then the overload, but doesn't allocate memory./> - /// - /// The name to check if it's defined - /// If true, considers the value of metadata attributes,otherwise ignores them - /// true if a member with the name exists in the enumeration, or a member is decorated - /// with a [Display] attribute with the name, false otherwise - public static bool IsDefined(in ReadOnlySpan name, bool allowMatchingMetadataAttribute) - {"); + sb.Append(""" + + _ => false, + }; + } + """); + + sb.Append(""" + + + #if NETCOREAPP && !NETCOREAPP2_0 && !NETCOREAPP1_1 && !NETCOREAPP1_0 + /// + /// Returns a boolean telling whether an enum with the given name exists in the enumeration + /// + /// The name to check if it's defined + /// true if a member with the name exists in the enumeration, false otherwise + public static bool IsDefined(in ReadOnlySpan name) => IsDefined(name, allowMatchingMetadataAttribute: false); + + /// + /// Returns a boolean telling whether an enum with the given name exists in the enumeration, + /// or optionally if a member decorated with a [Display] attribute + /// with the required name exists. + /// Slower then the overload, but doesn't allocate memory./> + /// + /// The name to check if it's defined + /// If true, considers the value of metadata attributes,otherwise ignores them + /// true if a member with the name exists in the enumeration, or a member is decorated + /// with a [Display] attribute with the name, false otherwise + public static bool IsDefined(in ReadOnlySpan name, bool allowMatchingMetadataAttribute) + { + """); if (enumToGenerate.IsDisplayAttributeUsed) { - sb.Append(@" - var isDefinedInDisplayAttribute = false; - if (allowMatchingMetadataAttribute) - { - isDefinedInDisplayAttribute = name switch - {"); - foreach (var member in enumToGenerate.Names) + sb.Append(""" + + var isDefinedInDisplayAttribute = false; + if (allowMatchingMetadataAttribute) + { + isDefinedInDisplayAttribute = name switch + { + """); + foreach (var (_, Value) in enumToGenerate.Names) { - if (member.Value.DisplayName is not null && member.Value.IsDisplayNameTheFirstPresence) + if (Value.DisplayName is not null && Value.IsDisplayNameTheFirstPresence) { - sb.Append(@" - ReadOnlySpan current when current.Equals(""").Append(member.Value.DisplayName).Append(@""".AsSpan(), global::System.StringComparison.Ordinal) => true,"); + sb.Append(""" + + ReadOnlySpan current when current.Equals(" + """ + ).Append(Value.DisplayName).Append(""" + ".AsSpan(), global::System.StringComparison.Ordinal) => true, + """); } } - sb.Append(@" - _ => false, - }; - } + sb.Append(""" - if (isDefinedInDisplayAttribute) - { - return true; - } -"); + _ => false, + }; + } + + if (isDefinedInDisplayAttribute) + { + return true; + } + + """); } - sb.Append(@" - return name switch - {"); - foreach (var member in enumToGenerate.Names) + sb.Append(""" + + return name switch + { + """); + foreach (var (Key, _) in enumToGenerate.Names) { - sb.Append(@" - ReadOnlySpan current when current.Equals(nameof(").Append(fullyQualifiedName).Append('.').Append(member.Key) - .Append(@").AsSpan(), global::System.StringComparison.Ordinal) => true,"); - } + sb.Append(""" - sb.Append(@" - _ => false, - }; + ReadOnlySpan current when current.Equals(nameof( + """).Append(fullyQualifiedName).Append('.').Append(Key) + .Append(").AsSpan(), global::System.StringComparison.Ordinal) => true,"); } -#endif"); - - sb.Append(@" - - /// - /// Converts the string representation of the name or numeric value of - /// an to the equivalent instance. - /// - /// The case-sensitive string representation of the enumeration name or underlying value to convert - /// An object of type whose - /// value is represented by - public static ").Append(fullyQualifiedName).Append(@" Parse( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - string? name) - => TryParse(name, out var value, false, false) ? value : ThrowValueNotFound(name); - - /// - /// Converts the string representation of the name or numeric value of - /// an to the equivalent instance. - /// - /// The case-sensitive string representation of the enumeration name or underlying value to convert - /// true to read value in case insensitive mode; false to read value in case sensitive mode. - /// An object of type whose - /// value is represented by - public static ").Append(fullyQualifiedName).Append(@" Parse( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - string? name, - bool ignoreCase) - => TryParse(name, out var value, ignoreCase, false) ? value : ThrowValueNotFound(name); - - /// - /// Converts the string representation of the name or numeric value of - /// an to the equivalent instance. - /// - /// The case-sensitive string representation of the enumeration name or underlying value to convert - /// true to read value in case insensitive mode; false to read value in case sensitive mode. - /// If true, considers the value included in metadata attributes such as - /// [Display] attribute when parsing, otherwise only considers the member names. - /// An object of type whose - /// value is represented by - public static ").Append(fullyQualifiedName).Append(@" Parse( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - string? name, - bool ignoreCase, - bool allowMatchingMetadataAttribute) - => TryParse(name, out var value, ignoreCase, allowMatchingMetadataAttribute) ? value : ThrowValueNotFound(name); - -#if NETCOREAPP3_0_OR_GREATER - [System.Diagnostics.CodeAnalysis.DoesNotReturn] -#endif - private static ").Append(fullyQualifiedName).Append(@" ThrowValueNotFound(string? name) - => throw new System.ArgumentException($""Requested value '{name}' was not found.""); - - /// - /// Converts the string representation of the name or numeric value of - /// an to the equivalent instance. - /// The return value indicates whether the conversion succeeded. - /// - /// The case-sensitive string representation of the enumeration name or underlying value to convert - /// When this method returns, contains an object of type - /// whose - /// value is represented by if the parse operation succeeds. - /// If the parse operation fails, contains the default value of the underlying type - /// of . This parameter is passed uninitialized. - /// true if the value parameter was converted successfully; otherwise, false. - public static bool TryParse( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - string? name, - out ").Append(fullyQualifiedName).Append(@" value) - => TryParse(name, out value, false, false);"); - sb.Append(@" - - /// - /// Converts the string representation of the name or numeric value of - /// an to the equivalent instance. - /// The return value indicates whether the conversion succeeded. - /// - /// The string representation of the enumeration name or underlying value to convert - /// When this method returns, contains an object of type - /// whose - /// value is represented by if the parse operation succeeds. - /// If the parse operation fails, contains the default value of the underlying type - /// of . This parameter is passed uninitialized. - /// true to read value in case insensitive mode; false to read value in case sensitive mode. - /// true if the value parameter was converted successfully; otherwise, false. - public static bool TryParse( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - string? name, - out ").Append(fullyQualifiedName).Append(@" value, - bool ignoreCase) - => TryParse(name, out value, ignoreCase, false);"); - sb.Append(@" - - /// - /// Converts the string representation of the name or numeric value of - /// an to the equivalent instance. - /// The return value indicates whether the conversion succeeded. - /// - /// The string representation of the enumeration name or underlying value to convert - /// When this method returns, contains an object of type - /// whose - /// value is represented by if the parse operation succeeds. - /// If the parse operation fails, contains the default value of the underlying type - /// of . This parameter is passed uninitialized. - /// true to read value in case insensitive mode; false to read value in case sensitive mode. - /// If true, considers the value included in metadata attributes such as - /// [Display] attribute when parsing, otherwise only considers the member names. - /// true if the value parameter was converted successfully; otherwise, false. - public static bool TryParse( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - string? name, - out ").Append(fullyQualifiedName).Append(@" value, - bool ignoreCase, - bool allowMatchingMetadataAttribute) - => ignoreCase - ? TryParseIgnoreCase(name, out value, allowMatchingMetadataAttribute) - : TryParseWithCase(name, out value, allowMatchingMetadataAttribute); - - private static bool TryParseIgnoreCase( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - string? name, - out ").Append(fullyQualifiedName).Append(@" value, - bool allowMatchingMetadataAttribute) - {"); + + sb.Append(""" + + _ => false, + }; + } + #endif + """); + + sb.Append(""" + + + /// + /// Converts the string representation of the name or numeric value of + /// an to the equivalent instance. + /// + /// The case-sensitive string representation of the enumeration name or underlying value to convert + /// An object of type whose + /// value is represented by + public static + """ + ).Append(fullyQualifiedName).Append(""" + Parse( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + string? name) + => TryParse(name, out var value, false, false) ? value : ThrowValueNotFound(name); + + /// + /// Converts the string representation of the name or numeric value of + /// an to the equivalent instance. + /// + /// The case-sensitive string representation of the enumeration name or underlying value to convert + /// true to read value in case insensitive mode; false to read value in case sensitive mode. + /// An object of type whose + /// value is represented by + public static + """ + ).Append(fullyQualifiedName).Append(""" + Parse( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + string? name, + bool ignoreCase) + => TryParse(name, out var value, ignoreCase, false) ? value : ThrowValueNotFound(name); + + /// + /// Converts the string representation of the name or numeric value of + /// an to the equivalent instance. + /// + /// The case-sensitive string representation of the enumeration name or underlying value to convert + /// true to read value in case insensitive mode; false to read value in case sensitive mode. + /// If true, considers the value included in metadata attributes such as + /// [Display] attribute when parsing, otherwise only considers the member names. + /// An object of type whose + /// value is represented by + public static + """ + ).Append(fullyQualifiedName).Append(""" + Parse( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + string? name, + bool ignoreCase, + bool allowMatchingMetadataAttribute) + => TryParse(name, out var value, ignoreCase, allowMatchingMetadataAttribute) ? value : ThrowValueNotFound(name); + + #if NETCOREAPP3_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.DoesNotReturn] + #endif + private static + """ + ).Append(fullyQualifiedName).Append(""" + ThrowValueNotFound(string? name) + => throw new System.ArgumentException($"Requested value '{name}' was not found."); + + /// + /// Converts the string representation of the name or numeric value of + /// an to the equivalent instance. + /// The return value indicates whether the conversion succeeded. + /// + /// The case-sensitive string representation of the enumeration name or underlying value to convert + /// When this method returns, contains an object of type + /// whose + /// value is represented by if the parse operation succeeds. + /// If the parse operation fails, contains the default value of the underlying type + /// of . This parameter is passed uninitialized. + /// true if the value parameter was converted successfully; otherwise, false. + public static bool TryParse( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + string? name, + out + """ + ).Append(fullyQualifiedName).Append(""" + value) + => TryParse(name, out value, false, false); + """); + sb.Append(""" + + + /// + /// Converts the string representation of the name or numeric value of + /// an to the equivalent instance. + /// The return value indicates whether the conversion succeeded. + /// + /// The string representation of the enumeration name or underlying value to convert + /// When this method returns, contains an object of type + /// whose + /// value is represented by if the parse operation succeeds. + /// If the parse operation fails, contains the default value of the underlying type + /// of . This parameter is passed uninitialized. + /// true to read value in case insensitive mode; false to read value in case sensitive mode. + /// true if the value parameter was converted successfully; otherwise, false. + public static bool TryParse( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + string? name, + out + """ + ).Append(fullyQualifiedName).Append(""" + value, + bool ignoreCase) + => TryParse(name, out value, ignoreCase, false); + """); + sb.Append(""" + + + /// + /// Converts the string representation of the name or numeric value of + /// an to the equivalent instance. + /// The return value indicates whether the conversion succeeded. + /// + /// The string representation of the enumeration name or underlying value to convert + /// When this method returns, contains an object of type + /// whose + /// value is represented by if the parse operation succeeds. + /// If the parse operation fails, contains the default value of the underlying type + /// of . This parameter is passed uninitialized. + /// true to read value in case insensitive mode; false to read value in case sensitive mode. + /// If true, considers the value included in metadata attributes such as + /// [Display] attribute when parsing, otherwise only considers the member names. + /// true if the value parameter was converted successfully; otherwise, false. + public static bool TryParse( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + string? name, + out + """ + ).Append(fullyQualifiedName).Append(""" + value, + bool ignoreCase, + bool allowMatchingMetadataAttribute) + => ignoreCase + ? TryParseIgnoreCase(name, out value, allowMatchingMetadataAttribute) + : TryParseWithCase(name, out value, allowMatchingMetadataAttribute); + + private static bool TryParseIgnoreCase( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + string? name, + out + """ + ).Append(fullyQualifiedName).Append(""" + value, + bool allowMatchingMetadataAttribute) + { + """); if (enumToGenerate.IsDisplayAttributeUsed) { - sb.Append(@" - if (allowMatchingMetadataAttribute) - { - switch (name) - {"); - foreach (var member in enumToGenerate.Names) + sb.Append(""" + + if (allowMatchingMetadataAttribute) + { + switch (name) + { + """); + foreach (var (Key, Value) in enumToGenerate.Names) { - if (member.Value.DisplayName is not null && member.Value.IsDisplayNameTheFirstPresence) + if (Value.DisplayName is not null && Value.IsDisplayNameTheFirstPresence) { - sb.Append(@" - case string s when s.Equals(""").Append(member.Value.DisplayName).Append( - @""", global::System.StringComparison.OrdinalIgnoreCase): - value = ").Append(fullyQualifiedName).Append('.').Append(member.Key).Append(@"; - return true;"); + sb.Append(""" + + case string s when s.Equals(" + """ + ).Append(Value.DisplayName).Append(""" + ", global::System.StringComparison.OrdinalIgnoreCase): + value = + """ + ).Append(fullyQualifiedName).Append('.').Append(Key).Append(""" + ; + return true; + """); } } - sb.Append(@" - default: - break; - }; - }"); - } - - sb.Append(@" + sb.Append(""" - switch (name) - {"); - foreach (var member in enumToGenerate.Names) - { - sb.Append(@" - case string s when s.Equals(nameof(").Append(fullyQualifiedName).Append('.').Append(member.Key).Append( - @"), global::System.StringComparison.OrdinalIgnoreCase): - value = ").Append(fullyQualifiedName).Append('.').Append(member.Key).Append(@"; - return true;"); + default: + break; + }; + } + """); } - sb.Append(@" - case string s when ").Append(enumToGenerate.UnderlyingType).Append(@".TryParse(name, out var val): - value = (").Append(fullyQualifiedName).Append(@")val; - return true; - default: - value = default; - return false; - } + sb.Append(""" + + + switch (name) + { + """); + foreach (var (Key, _) in enumToGenerate.Names) + { + sb.Append(""" + + case string s when s.Equals(nameof( + """ + ).Append(fullyQualifiedName).Append('.').Append(Key).Append(""" + ), global::System.StringComparison.OrdinalIgnoreCase): + value = + """ + ).Append(fullyQualifiedName).Append('.').Append(Key).Append(""" + ; + return true; + """); } - private static bool TryParseWithCase( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - string? name, - out ").Append(fullyQualifiedName).Append(@" value, - bool allowMatchingMetadataAttribute) - {"); + sb.Append(""" + + case string s when + """ + ).Append(enumToGenerate.UnderlyingType).Append(""" + .TryParse(name, out var val): + value = ( + """).Append(fullyQualifiedName).Append(""" + )val; + return true; + default: + value = default; + return false; + } + } + + private static bool TryParseWithCase( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + string? name, + out + """ + ).Append(fullyQualifiedName).Append(""" + value, + bool allowMatchingMetadataAttribute) + { + """); if (enumToGenerate.IsDisplayAttributeUsed) { - sb.Append(@" - if (allowMatchingMetadataAttribute) - { - switch (name) - {"); + sb.Append(""" + + if (allowMatchingMetadataAttribute) + { + switch (name) + { + """); - foreach (var member in enumToGenerate.Names) + foreach (var (Key, Value) in enumToGenerate.Names) { - if (member.Value.DisplayName is not null && member.Value.IsDisplayNameTheFirstPresence) + if (Value.DisplayName is not null && Value.IsDisplayNameTheFirstPresence) { - sb.Append(@" - case """).Append(member.Value.DisplayName).Append(@""": - value = ").Append(fullyQualifiedName).Append('.').Append(member.Key).Append(@"; - return true;"); + sb.Append(""" + + case " + """ + ).Append(Value.DisplayName).Append(""" + ": + value = + """ + ).Append(fullyQualifiedName).Append('.').Append(Key).Append(""" + ; + return true; + """); } } - sb.Append(@" - default: - break; - }; - }"); + sb.Append(""" + + default: + break; + }; + } + """); } - sb.Append(@" + sb.Append(""" - switch (name) - {"); - foreach (var member in enumToGenerate.Names) - { - sb.Append(@" - case nameof(").Append(fullyQualifiedName).Append('.').Append(member.Key).Append(@"): - value = ").Append(fullyQualifiedName).Append('.').Append(member.Key).Append(@"; - return true;"); - } - sb.Append(@" - case string s when ").Append(enumToGenerate.UnderlyingType).Append(@".TryParse(name, out var val): - value = (").Append(fullyQualifiedName).Append(@")val; - return true; - default: - value = default; - return false; - } + switch (name) + { + """); + foreach (var (Key, _) in enumToGenerate.Names) + { + sb.Append(""" + + case nameof( + """ + ).Append(fullyQualifiedName).Append('.').Append(Key).Append(""" + ): + value = + """ + ).Append(fullyQualifiedName).Append('.').Append(Key).Append(""" + ; + return true; + """); } -#if NETCOREAPP && !NETCOREAPP2_0 && !NETCOREAPP1_1 && !NETCOREAPP1_0 - /// - /// Converts the string representation of the name or numeric value of - /// an to the equivalent instance. - /// - /// The case-sensitive string representation of the enumeration name or underlying value to convert - /// An object of type whose - /// value is represented by - public static ").Append(fullyQualifiedName).Append(@" Parse( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - in ReadOnlySpan name) - => TryParse(name, out var value, false, false) ? value : ThrowValueNotFound(name.ToString()); - - /// - /// Converts the string representation of the name or numeric value of - /// an to the equivalent instance. - /// - /// The case-sensitive string representation of the enumeration name or underlying value to convert - /// true to read value in case insensitive mode; false to read value in case sensitive mode. - /// An object of type whose - /// value is represented by - public static ").Append(fullyQualifiedName).Append(@" Parse( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - in ReadOnlySpan name, - bool ignoreCase) - => TryParse(name, out var value, ignoreCase, false) ? value : ThrowValueNotFound(name.ToString()); - - /// - /// Converts the string representation of the name or numeric value of - /// an to the equivalent instance. - /// - /// The case-sensitive string representation of the enumeration name or underlying value to convert - /// true to read value in case insensitive mode; false to read value in case sensitive mode. - /// If true, considers the value included in metadata attributes such as - /// [Display] attribute when parsing, otherwise only considers the member names. - /// An object of type whose - /// value is represented by - public static ").Append(fullyQualifiedName).Append(@" Parse( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - in ReadOnlySpan name, - bool ignoreCase, - bool allowMatchingMetadataAttribute) - => TryParse(name, out var value, ignoreCase, allowMatchingMetadataAttribute) ? value : ThrowValueNotFound(name.ToString()); - - /// - /// Converts the span representation of the name or numeric value of - /// an to the equivalent instance. - /// The return value indicates whether the conversion succeeded. - /// - /// The span representation of the enumeration name or underlying value to convert - /// When this method returns, contains an object of type - /// whose - /// value is represented by if the parse operation succeeds. - /// If the parse operation fails, contains the default value of the underlying type - /// of . This parameter is passed uninitialized. - /// true if the value parameter was converted successfully; otherwise, false. - public static bool TryParse( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - in ReadOnlySpan name, - out ").Append(fullyQualifiedName).Append(@" value) - => TryParse(name, out value, false, false);"); - sb.Append(@" - - /// - /// Converts the span representation of the name or numeric value of - /// an to the equivalent instance. - /// The return value indicates whether the conversion succeeded. - /// - /// The span representation of the enumeration name or underlying value to convert - /// When this method returns, contains an object of type - /// whose - /// value is represented by if the parse operation succeeds. - /// If the parse operation fails, contains the default value of the underlying type - /// of . This parameter is passed uninitialized. - /// true to read value in case insensitive mode; false to read value in case sensitive mode. - /// true if the value parameter was converted successfully; otherwise, false. - public static bool TryParse( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - in ReadOnlySpan name, - out ").Append(fullyQualifiedName).Append(@" value, - bool ignoreCase) - => TryParse(name, out value, ignoreCase, false);"); - - sb.Append(@" - - /// - /// Converts the span representation of the name or numeric value of - /// an to the equivalent instance. - /// The return value indicates whether the conversion succeeded. - /// - /// The span representation of the enumeration name or underlying value to convert - /// When this method returns, contains an object of type - /// whose - /// value is represented by if the parse operation succeeds. - /// If the parse operation fails, contains the default value of the underlying type - /// of . This parameter is passed uninitialized. - /// true to read value in case insensitive mode; false to read value in case sensitive mode. - /// If true, considers the value included in metadata attributes such as - /// [Display] attribute when parsing, otherwise only considers the member names. - /// true if the value parameter was converted successfully; otherwise, false. - public static bool TryParse( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - in ReadOnlySpan name, - out ").Append(fullyQualifiedName).Append(@" result, - bool ignoreCase, - bool allowMatchingMetadataAttribute) - => ignoreCase - ? TryParseIgnoreCase(in name, out result, allowMatchingMetadataAttribute) - : TryParseWithCase(in name, out result, allowMatchingMetadataAttribute); - - private static bool TryParseIgnoreCase( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - in ReadOnlySpan name, - out ").Append(fullyQualifiedName).Append(@" result, - bool allowMatchingMetadataAttribute) - {"); + sb.Append(""" + + case string s when + """ + ).Append(enumToGenerate.UnderlyingType).Append(""" + .TryParse(name, out var val): + value = ( + """ + ).Append(fullyQualifiedName).Append(""" + )val; + return true; + default: + value = default; + return false; + } + } + + #if NETCOREAPP && !NETCOREAPP2_0 && !NETCOREAPP1_1 && !NETCOREAPP1_0 + /// + /// Converts the string representation of the name or numeric value of + /// an to the equivalent instance. + /// + /// The case-sensitive string representation of the enumeration name or underlying value to convert + /// An object of type whose + /// value is represented by + public static + """ + ).Append(fullyQualifiedName).Append(""" + Parse( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + in ReadOnlySpan name) + => TryParse(name, out var value, false, false) ? value : ThrowValueNotFound(name.ToString()); + + /// + /// Converts the string representation of the name or numeric value of + /// an to the equivalent instance. + /// + /// The case-sensitive string representation of the enumeration name or underlying value to convert + /// true to read value in case insensitive mode; false to read value in case sensitive mode. + /// An object of type whose + /// value is represented by + public static + """ + ).Append(fullyQualifiedName).Append(""" + Parse( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + in ReadOnlySpan name, + bool ignoreCase) + => TryParse(name, out var value, ignoreCase, false) ? value : ThrowValueNotFound(name.ToString()); + + /// + /// Converts the string representation of the name or numeric value of + /// an to the equivalent instance. + /// + /// The case-sensitive string representation of the enumeration name or underlying value to convert + /// true to read value in case insensitive mode; false to read value in case sensitive mode. + /// If true, considers the value included in metadata attributes such as + /// [Display] attribute when parsing, otherwise only considers the member names. + /// An object of type whose + /// value is represented by + public static + """ + ).Append(fullyQualifiedName).Append(""" + Parse( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + in ReadOnlySpan name, + bool ignoreCase, + bool allowMatchingMetadataAttribute) + => TryParse(name, out var value, ignoreCase, allowMatchingMetadataAttribute) ? value : ThrowValueNotFound(name.ToString()); + + /// + /// Converts the span representation of the name or numeric value of + /// an to the equivalent instance. + /// The return value indicates whether the conversion succeeded. + /// + /// The span representation of the enumeration name or underlying value to convert + /// When this method returns, contains an object of type + /// whose + /// value is represented by if the parse operation succeeds. + /// If the parse operation fails, contains the default value of the underlying type + /// of . This parameter is passed uninitialized. + /// true if the value parameter was converted successfully; otherwise, false. + public static bool TryParse( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + in ReadOnlySpan name, + out + """ + ).Append(fullyQualifiedName).Append(""" + value) + => TryParse(name, out value, false, false); + """); + sb.Append(""" + + + /// + /// Converts the span representation of the name or numeric value of + /// an to the equivalent instance. + /// The return value indicates whether the conversion succeeded. + /// + /// The span representation of the enumeration name or underlying value to convert + /// When this method returns, contains an object of type + /// whose + /// value is represented by if the parse operation succeeds. + /// If the parse operation fails, contains the default value of the underlying type + /// of . This parameter is passed uninitialized. + /// true to read value in case insensitive mode; false to read value in case sensitive mode. + /// true if the value parameter was converted successfully; otherwise, false. + public static bool TryParse( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + in ReadOnlySpan name, + out + """ + ).Append(fullyQualifiedName).Append(""" + value, + bool ignoreCase) + => TryParse(name, out value, ignoreCase, false); + """); + + sb.Append(""" + + + /// + /// Converts the span representation of the name or numeric value of + /// an to the equivalent instance. + /// The return value indicates whether the conversion succeeded. + /// + /// The span representation of the enumeration name or underlying value to convert + /// When this method returns, contains an object of type + /// whose + /// value is represented by if the parse operation succeeds. + /// If the parse operation fails, contains the default value of the underlying type + /// of . This parameter is passed uninitialized. + /// true to read value in case insensitive mode; false to read value in case sensitive mode. + /// If true, considers the value included in metadata attributes such as + /// [Display] attribute when parsing, otherwise only considers the member names. + /// true if the value parameter was converted successfully; otherwise, false. + public static bool TryParse( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + in ReadOnlySpan name, + out + """ + ).Append(fullyQualifiedName).Append(""" + result, + bool ignoreCase, + bool allowMatchingMetadataAttribute) + => ignoreCase + ? TryParseIgnoreCase(in name, out result, allowMatchingMetadataAttribute) + : TryParseWithCase(in name, out result, allowMatchingMetadataAttribute); + + private static bool TryParseIgnoreCase( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + in ReadOnlySpan name, + out + """ + ).Append(fullyQualifiedName).Append(""" + result, + bool allowMatchingMetadataAttribute) + { + """); if (enumToGenerate.IsDisplayAttributeUsed) { - sb.Append(@" - if (allowMatchingMetadataAttribute) + sb.Append(""" + + if (allowMatchingMetadataAttribute) + { + switch (name) + { + """); + foreach (var (Key, Value) in enumToGenerate.Names) { - switch (name) - {"); - foreach (var member in enumToGenerate.Names) - { - if (member.Value.DisplayName is not null && member.Value.IsDisplayNameTheFirstPresence) + if (Value.DisplayName is not null && Value.IsDisplayNameTheFirstPresence) { - sb.Append(@" - case ReadOnlySpan current when current.Equals(""").Append(member.Value.DisplayName).Append( - @""".AsSpan(), global::System.StringComparison.OrdinalIgnoreCase): - result = ").Append(fullyQualifiedName).Append('.').Append(member.Key).Append(@"; - return true;"); + sb.Append(""" + + case ReadOnlySpan current when current.Equals(" + """ + ).Append(Value.DisplayName).Append(""" + ".AsSpan(), global::System.StringComparison.OrdinalIgnoreCase): + result = + """ + ).Append(fullyQualifiedName).Append('.').Append(Key).Append(""" + ; + return true; + """); } } - sb.Append(@" - default: - break; - }; - } -"); - } + sb.Append(""" - sb.Append(@" - switch (name) - {"); - foreach (var member in enumToGenerate.Names) - { - sb.Append(@" - case ReadOnlySpan current when current.Equals(nameof(").Append(fullyQualifiedName).Append('.').Append(member.Key).Append( - @").AsSpan(), global::System.StringComparison.OrdinalIgnoreCase): - result = ").Append(fullyQualifiedName).Append('.').Append(member.Key).Append(@"; - return true;"); + default: + break; + }; + } + + """); } - sb.Append(@" - case ReadOnlySpan current when ").Append(enumToGenerate.UnderlyingType).Append(@".TryParse(name, out var numericResult): - result = (").Append(fullyQualifiedName).Append(@")numericResult; - return true; - default: - result = default; - return false; - } + sb.Append(""" + + switch (name) + { + """); + foreach (var (Key, _) in enumToGenerate.Names) + { + sb.Append(""" + + case ReadOnlySpan current when current.Equals(nameof( + """ + ).Append(fullyQualifiedName).Append('.').Append(Key).Append(""" + ).AsSpan(), global::System.StringComparison.OrdinalIgnoreCase): + result = + """ + ).Append(fullyQualifiedName).Append('.').Append(Key).Append(""" + ; + return true; + """); } - private static bool TryParseWithCase( -#if NETCOREAPP3_0_OR_GREATER - [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] -#endif - in ReadOnlySpan name, - out ").Append(fullyQualifiedName).Append(@" result, - bool allowMatchingMetadataAttribute) - {"); + sb.Append(""" + + case ReadOnlySpan current when + """ + ).Append(enumToGenerate.UnderlyingType).Append(""" + .TryParse(name, out var numericResult): + result = ( + """ + ).Append(fullyQualifiedName).Append(""" + )numericResult; + return true; + default: + result = default; + return false; + } + } + + private static bool TryParseWithCase( + #if NETCOREAPP3_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] + #endif + in ReadOnlySpan name, + out + """ + ).Append(fullyQualifiedName).Append(""" + result, + bool allowMatchingMetadataAttribute) + { + """); if (enumToGenerate.IsDisplayAttributeUsed) { - sb.Append(@" - if (allowMatchingMetadataAttribute) + sb.Append(""" + + if (allowMatchingMetadataAttribute) + { + switch (name) + { + """); + foreach (var (Key, Value) in enumToGenerate.Names) { - switch (name) - {"); - foreach (var member in enumToGenerate.Names) - { - if (member.Value.DisplayName is not null && member.Value.IsDisplayNameTheFirstPresence) + if (Value.DisplayName is not null && Value.IsDisplayNameTheFirstPresence) { - sb.Append(@" - case ReadOnlySpan current when current.Equals(""").Append(member.Value.DisplayName).Append(@""".AsSpan(), global::System.StringComparison.Ordinal): - result = ").Append(fullyQualifiedName).Append('.').Append(member.Key).Append(@"; - return true;"); + sb.Append(""" + + case ReadOnlySpan current when current.Equals(" + """ + ).Append(Value.DisplayName).Append(""" + ".AsSpan(), global::System.StringComparison.Ordinal): + result = + """ + ).Append(fullyQualifiedName).Append('.').Append(Key).Append(""" + ; + return true; + """); } } - sb.Append(@" - default: - break; - }; - } -"); - } + sb.Append(""" - sb.Append(@" - switch (name) - {"); - foreach (var member in enumToGenerate.Names) - { - sb.Append(@" - case ReadOnlySpan current when current.Equals(nameof(").Append(fullyQualifiedName).Append('.').Append(member.Key).Append( - @").AsSpan(), global::System.StringComparison.Ordinal): - result = ").Append(fullyQualifiedName).Append('.').Append(member.Key).Append(@"; - return true;"); - } + default: + break; + }; + } - sb.Append(@" - case ReadOnlySpan current when ").Append(enumToGenerate.UnderlyingType).Append(@".TryParse(name, out var numericResult): - result = (").Append(fullyQualifiedName).Append(@")numericResult; - return true; - default: - result = default; - return false; - } + """); } -#endif - - /// - /// Retrieves an array of the values of the members defined in - /// . - /// Note that this returns a new array with every invocation, so - /// should be cached if appropriate. - /// - /// An array of the values defined in - public static ").Append(fullyQualifiedName).Append(@"[] GetValues() - { - return new[] - {"); - foreach (var member in enumToGenerate.Names) + + sb.Append(""" + + switch (name) + { + """); + foreach (var (Key, _) in enumToGenerate.Names) { - sb.Append(@" - ").Append(fullyQualifiedName).Append('.').Append(member.Key).Append(','); + sb.Append(""" + + case ReadOnlySpan current when current.Equals(nameof( + """ + ).Append(fullyQualifiedName).Append('.').Append(Key).Append(""" + ).AsSpan(), global::System.StringComparison.Ordinal): + result = + """ + ).Append(fullyQualifiedName).Append('.').Append(Key).Append(""" + ; + return true; + """); } - sb.Append(@" - }; - }"); + sb.Append(""" + + case ReadOnlySpan current when + """ + ).Append(enumToGenerate.UnderlyingType).Append(""" + .TryParse(name, out var numericResult): + result = ( + """ + ).Append(fullyQualifiedName).Append(""" + )numericResult; + return true; + default: + result = default; + return false; + } + } + #endif + + /// + /// Retrieves an array of the values of the members defined in + /// . + /// Note that this returns a new array with every invocation, so + /// should be cached if appropriate. + /// + /// An array of the values defined in + public static + """ + ).Append(fullyQualifiedName).Append(""" + [] GetValues() + { + return new[] + { + """); + foreach (var (Key, _) in enumToGenerate.Names) + { + sb.Append(""" - sb.Append(@" + + """).Append(fullyQualifiedName).Append('.').Append(Key).Append(','); + } - /// - /// Retrieves an array of the names of the members defined in - /// . - /// Note that this returns a new array with every invocation, so - /// should be cached if appropriate. - /// - /// An array of the names of the members defined in - public static string[] GetNames() + sb.Append(""" + + }; + } + """); + + sb.Append(""" + + + /// + /// Retrieves an array of the names of the members defined in + /// . + /// Note that this returns a new array with every invocation, so + /// should be cached if appropriate. + /// + /// An array of the names of the members defined in + public static string[] GetNames() + { + return new[] + { + """); + foreach (var (Key, _) in enumToGenerate.Names) { - return new[] - {"); - foreach (var member in enumToGenerate.Names) - { - sb.Append(@" - nameof(").Append(fullyQualifiedName).Append('.').Append(member.Key).Append("),"); - } + sb.Append(""" - sb.Append(@" - }; + nameof( + """).Append(fullyQualifiedName).Append('.').Append(Key).Append("),"); } - }"); + + sb.Append(""" + + }; + } + } + """); if (!string.IsNullOrEmpty(enumToGenerate.Namespace)) { - sb.Append(@" -}"); + sb.Append(""" + + } + """); } return sb.ToString(); diff --git a/tests/NetEscapades.EnumGenerators.Tests/EnumGeneratorTests.cs b/tests/NetEscapades.EnumGenerators.Tests/EnumGeneratorTests.cs index d860055..f4939f3 100644 --- a/tests/NetEscapades.EnumGenerators.Tests/EnumGeneratorTests.cs +++ b/tests/NetEscapades.EnumGenerators.Tests/EnumGeneratorTests.cs @@ -19,14 +19,16 @@ public EnumGeneratorTests(ITestOutputHelper output) [Fact] public Task CanGenerateEnumExtensionsInGlobalNamespace() { - const string input = @"using NetEscapades.EnumGenerators; + const string input = """ + using NetEscapades.EnumGenerators; -[EnumExtensions] -public enum MyEnum -{ - First, - Second, -}"; + [EnumExtensions] + public enum MyEnum + { + First, + Second, + } + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); Assert.Empty(diagnostics); @@ -36,17 +38,19 @@ public enum MyEnum [Fact] public Task CanGenerateEnumExtensionsInChildNamespace() { - const string input = @"using NetEscapades.EnumGenerators; + const string input = """ + using NetEscapades.EnumGenerators; -namespace MyTestNameSpace -{ - [EnumExtensions] - public enum MyEnum - { - First = 0, - Second = 1, - } -}"; + namespace MyTestNameSpace + { + [EnumExtensions] + public enum MyEnum + { + First = 0, + Second = 1, + } + } + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); Assert.Empty(diagnostics); @@ -56,20 +60,22 @@ public enum MyEnum [Fact] public Task CanGenerateEnumExtensionsInNestedClass() { - const string input = @"using NetEscapades.EnumGenerators; + const string input = """ + using NetEscapades.EnumGenerators; -namespace MyTestNameSpace -{ - public class InnerClass - { - [EnumExtensions] - internal enum MyEnum - { - First = 0, - Second = 1, - } - } -}"; + namespace MyTestNameSpace + { + public class InnerClass + { + [EnumExtensions] + internal enum MyEnum + { + First = 0, + Second = 1, + } + } + } + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); Assert.Empty(diagnostics); @@ -79,17 +85,19 @@ internal enum MyEnum [Fact] public Task CanGenerateEnumExtensionsWithCustomName() { - const string input = @"using NetEscapades.EnumGenerators; + const string input = """ + using NetEscapades.EnumGenerators; -namespace MyTestNameSpace -{ - [EnumExtensions(ExtensionClassName = ""A"")] - internal enum MyEnum - { - First = 0, - Second = 1, - } -}"; + namespace MyTestNameSpace + { + [EnumExtensions(ExtensionClassName = "A")] + internal enum MyEnum + { + First = 0, + Second = 1, + } + } + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); Assert.Empty(diagnostics); @@ -99,17 +107,19 @@ internal enum MyEnum [Fact] public Task CanGenerateEnumExtensionsWithCustomNamespace() { - const string input = @"using NetEscapades.EnumGenerators; + const string input = """ + using NetEscapades.EnumGenerators; -namespace MyTestNameSpace -{ - [EnumExtensions(ExtensionClassNamespace = ""A.B"")] - internal enum MyEnum - { - First = 0, - Second = 1, - } -}"; + namespace MyTestNameSpace + { + [EnumExtensions(ExtensionClassNamespace = "A.B")] + internal enum MyEnum + { + First = 0, + Second = 1, + } + } + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); Assert.Empty(diagnostics); @@ -119,17 +129,19 @@ internal enum MyEnum [Fact] public Task CanGenerateEnumExtensionsWithCustomNamespaceAndName() { - const string input = @"using NetEscapades.EnumGenerators; + const string input = """ + using NetEscapades.EnumGenerators; -namespace MyTestNameSpace -{ - [EnumExtensions(ExtensionClassNamespace = ""A.B"", ExtensionClassName = ""C"")] - internal enum MyEnum - { - First = 0, - Second = 1, - } -}"; + namespace MyTestNameSpace + { + [EnumExtensions(ExtensionClassNamespace = "A.B", ExtensionClassName = "C")] + internal enum MyEnum + { + First = 0, + Second = 1, + } + } + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); Assert.Empty(diagnostics); @@ -139,24 +151,26 @@ internal enum MyEnum [Fact] public Task CanGenerateEnumExtensionsWithDisplayName() { - const string input = @"using NetEscapades.EnumGenerators; -using System.ComponentModel.DataAnnotations; - -namespace MyTestNameSpace -{ - [EnumExtensions] - public enum MyEnum - { - First = 0, - - [Display(Name = ""2nd"")] - Second = 1, - Third = 2, + const string input = """ + using NetEscapades.EnumGenerators; + using System.ComponentModel.DataAnnotations; - [Display(Name = ""4th"")] - Fourth = 3 - } -}"; + namespace MyTestNameSpace + { + [EnumExtensions] + public enum MyEnum + { + First = 0, + + [Display(Name = "2nd")] + Second = 1, + Third = 2, + + [Display(Name = "4th")] + Fourth = 3 + } + } + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); Assert.Empty(diagnostics); @@ -169,26 +183,26 @@ public enum MyEnum [Fact] public Task CanGenerateEnumExtensionsWithDescription() { - var input = """ - using NetEscapades.EnumGenerators; - using System.ComponentModel; + const string input = """ + using NetEscapades.EnumGenerators; + using System.ComponentModel; - namespace MyTestNameSpace - { - [EnumExtensions] - public enum MyEnum + namespace MyTestNameSpace { - First = 0, + [EnumExtensions] + public enum MyEnum + { + First = 0, - [Description("2nd")] - Second = 1, - Third = 2, + [Description("2nd")] + Second = 1, + Third = 2, - [Description("4th")] - Fourth = 3 - } - }" - """; + [Description("4th")] + Fourth = 3 + } + }" + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); @@ -202,29 +216,29 @@ public enum MyEnum [Fact] public Task CanGenerateEnumExtensionsWithDescriptionAndDisplayName() { - var input = """ - using NetEscapades.EnumGenerators; - using System.ComponentModel; - using System.ComponentModel.DataAnnotations; + const string input = """ + using NetEscapades.EnumGenerators; + using System.ComponentModel; + using System.ComponentModel.DataAnnotations; - namespace MyTestNameSpace - { - [EnumExtensions] - public enum MyEnum + namespace MyTestNameSpace { - First = 0, - - [Description("2nd")] // takes precedence - [Display(Name = "Secundo")] - Second = 1, - Third = 2, - - [Display(Name = "4th")] // takes precedence - [Description("Number 4")] - Fourth = 3 - } - }" - """; + [EnumExtensions] + public enum MyEnum + { + First = 0, + + [Description("2nd")] // takes precedence + [Display(Name = "Secundo")] + Second = 1, + Third = 2, + + [Display(Name = "4th")] // takes precedence + [Description("Number 4")] + Fourth = 3 + } + }" + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); @@ -238,24 +252,26 @@ public enum MyEnum [Fact] public Task CanGenerateEnumExtensionsWithSameDisplayName() { - const string input = @"using NetEscapades.EnumGenerators; -using System.ComponentModel.DataAnnotations; - -namespace MyTestNameSpace -{ - [EnumExtensions] - public enum MyEnum - { - First = 0, - - [Display(Name = ""2nd"")] - Second = 1, - Third = 2, + const string input = """ + using NetEscapades.EnumGenerators; + using System.ComponentModel.DataAnnotations; - [Display(Name = ""2nd"")] - Fourth = 3 - } -}"; + namespace MyTestNameSpace + { + [EnumExtensions] + public enum MyEnum + { + First = 0, + + [Display(Name = "2nd")] + Second = 1, + Third = 2, + + [Display(Name = "2nd")] + Fourth = 3 + } + } + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); Assert.Empty(diagnostics); @@ -270,20 +286,20 @@ public enum MyEnum public Task CanGenerateEnumExtensionsForFlagsEnum(string usings, string attribute) { string input = $$""" - using NetEscapades.EnumGenerators; - {{usings}} + using NetEscapades.EnumGenerators; + {{usings}} - namespace MyTestNameSpace - { - [EnumExtensions, {{attribute}}] - public enum MyEnum + namespace MyTestNameSpace { - First = 1, - Second = 2, - Third = 4, + [EnumExtensions, {{attribute}}] + public enum MyEnum + { + First = 1, + Second = 2, + Third = 4, + } } - } - """; + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); @@ -297,19 +313,21 @@ public enum MyEnum [Fact] public Task CanHandleNamespaceAndClassNameAreTheSame() { - const string input = @"using NetEscapades.EnumGenerators; -using System.ComponentModel.DataAnnotations; + const string input = """ + using NetEscapades.EnumGenerators; + using System.ComponentModel.DataAnnotations; -namespace Foo -{ - public class Foo {} - - [EnumExtensions] - public enum TestEnum - { - Value1 - } -}"; + namespace Foo + { + public class Foo {} + + [EnumExtensions] + public enum TestEnum + { + Value1 + } + } + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); Assert.Empty(diagnostics); @@ -346,11 +364,11 @@ public enum StringTesting public Task CanGenerateForExternalEnum() { const string input = """ - using System; - using NetEscapades.EnumGenerators; + using System; + using NetEscapades.EnumGenerators; - [assembly:EnumExtensions()] - """; + [assembly:EnumExtensions()] + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); Assert.Empty(diagnostics); @@ -361,10 +379,10 @@ public Task CanGenerateForExternalEnum() public Task CanGenerateForExternalFlagsEnum() { const string input = """ - using NetEscapades.EnumGenerators; + using NetEscapades.EnumGenerators; - [assembly:EnumExtensions()] - """; + [assembly:EnumExtensions()] + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); Assert.Empty(diagnostics); @@ -375,11 +393,11 @@ public Task CanGenerateForExternalFlagsEnum() public Task CanGenerateForMultipleExternalEnums() { const string input = """ - using NetEscapades.EnumGenerators; + using NetEscapades.EnumGenerators; - [assembly:EnumExtensions()] - [assembly:EnumExtensions()] - """; + [assembly:EnumExtensions()] + [assembly:EnumExtensions()] + """; var (diagnostics, output) = TestHelpers.GetGeneratedTrees(input); Assert.Empty(diagnostics); @@ -390,10 +408,10 @@ public Task CanGenerateForMultipleExternalEnums() public Task CanGenerateExternalEnumExtensionsWithCustomName() { const string input = """ - using NetEscapades.EnumGenerators; + using NetEscapades.EnumGenerators; - [assembly:EnumExtensions(ExtensionClassName = "A")] - """; + [assembly:EnumExtensions(ExtensionClassName = "A")] + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); Assert.Empty(diagnostics); @@ -404,10 +422,10 @@ public Task CanGenerateExternalEnumExtensionsWithCustomName() public Task CanGenerateExternalEnumExtensionsWithCustomNamespace() { const string input = """ - using NetEscapades.EnumGenerators; + using NetEscapades.EnumGenerators; - [assembly:EnumExtensions(ExtensionClassNamespace = "A.B")] - """; + [assembly:EnumExtensions(ExtensionClassNamespace = "A.B")] + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); Assert.Empty(diagnostics); @@ -418,10 +436,10 @@ public Task CanGenerateExternalEnumExtensionsWithCustomNamespace() public Task CanGenerateExternalEnumExtensionsWithCustomNamespaceAndName() { const string input = """ - using NetEscapades.EnumGenerators; + using NetEscapades.EnumGenerators; - [assembly:EnumExtensions(ExtensionClassNamespace = "A.B", ExtensionClassName = "C")] - """; + [assembly:EnumExtensions(ExtensionClassNamespace = "A.B", ExtensionClassName = "C")] + """; var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); Assert.Empty(diagnostics);