diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/SolutionRenameStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/SolutionRenameStep.cs index bf5ad938af..abdb9e45f5 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/SolutionRenameStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/SolutionRenameStep.cs @@ -64,7 +64,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps RenameHelper.RenameAll(_entries, _projectNamePlaceHolder, _projectName); RenameHelper.RenameAll(_entries, _projectNamePlaceHolder.ToCamelCase(), _projectName.ToCamelCase()); RenameHelper.RenameAll(_entries, _projectNamePlaceHolder.ToKebabCase(), _projectName.ToKebabCase()); + RenameHelper.RenameAll(_entries, _projectNamePlaceHolder.ToSnakeCase().ToUpper(), _projectName.ToSnakeCase().ToUpper()); } } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs b/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs index f8086c8ecd..6aa3deb4f0 100644 --- a/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs +++ b/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; @@ -312,6 +313,75 @@ namespace System : Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + "-" + char.ToLowerInvariant(m.Value[1])); } + /// + /// Converts given PascalCase/camelCase string to snake case. + /// Example: "ThisIsSampleSentence" is converted to "this_is_a_sample_sentence". + /// https://github.com/npgsql/npgsql/blob/dev/src/Npgsql/NameTranslation/NpgsqlSnakeCaseNameTranslator.cs#L51 + /// + /// String to convert. + /// + public static string ToSnakeCase(this string str) + { + if (string.IsNullOrWhiteSpace(str)) + { + return str; + } + + var builder = new StringBuilder(str.Length + Math.Min(2, str.Length / 5)); + var previousCategory = default(UnicodeCategory?); + + for (var currentIndex = 0; currentIndex < str.Length; currentIndex++) + { + var currentChar = str[currentIndex]; + if (currentChar == '_') + { + builder.Append('_'); + previousCategory = null; + continue; + } + + var currentCategory = char.GetUnicodeCategory(currentChar); + switch (currentCategory) + { + case UnicodeCategory.UppercaseLetter: + case UnicodeCategory.TitlecaseLetter: + if (previousCategory == UnicodeCategory.SpaceSeparator || + previousCategory == UnicodeCategory.LowercaseLetter || + previousCategory != UnicodeCategory.DecimalDigitNumber && + previousCategory != null && + currentIndex > 0 && + currentIndex + 1 < str.Length && + char.IsLower(str[currentIndex + 1])) + { + builder.Append('_'); + } + + currentChar = char.ToLower(currentChar); + break; + + case UnicodeCategory.LowercaseLetter: + case UnicodeCategory.DecimalDigitNumber: + if (previousCategory == UnicodeCategory.SpaceSeparator) + { + builder.Append('_'); + } + break; + + default: + if (previousCategory != null) + { + previousCategory = UnicodeCategory.SpaceSeparator; + } + continue; + } + + builder.Append(currentChar); + previousCategory = currentCategory; + } + + return builder.ToString(); + } + /// /// Converts string to enum value. /// @@ -476,4 +546,4 @@ namespace System return encoding.GetBytes(str); } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.Core.Tests/System/StringExtensions_Tests.cs b/framework/test/Volo.Abp.Core.Tests/System/StringExtensions_Tests.cs index 23d961dfa7..69b02d07c1 100644 --- a/framework/test/Volo.Abp.Core.Tests/System/StringExtensions_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/System/StringExtensions_Tests.cs @@ -83,6 +83,16 @@ namespace System "ThisIsSampleText".ToKebabCase().ShouldBe("this-is-sample-text"); } + [Fact] + public void ToSnakeCase_Test() + { + (null as string).ToSnakeCase().ShouldBe(null); + "helloMoon".ToSnakeCase().ShouldBe("hello_moon"); + "HelloWorld".ToSnakeCase().ShouldBe("hello_world"); + "HelloIsparta".ToSnakeCase().ShouldBe("hello_isparta"); + "ThisIsSampleText".ToSnakeCase().ShouldBe("this_is_sample_text"); + } + [Fact] public void ToSentenceCase_Test() { @@ -247,4 +257,4 @@ namespace System _cultureScope.Dispose(); } } -} \ No newline at end of file +}