diff --git a/src/GraphQL.Client.Abstractions/GraphQL.Client.Abstractions.csproj b/src/GraphQL.Client.Abstractions/GraphQL.Client.Abstractions.csproj index d7678b66..8e1faee1 100644 --- a/src/GraphQL.Client.Abstractions/GraphQL.Client.Abstractions.csproj +++ b/src/GraphQL.Client.Abstractions/GraphQL.Client.Abstractions.csproj @@ -15,4 +15,8 @@ + + + + diff --git a/src/GraphQL.Client.Abstractions/Utilities/StringExtensions.cs b/src/GraphQL.Client.Abstractions/Utilities/StringExtensions.cs new file mode 100644 index 00000000..38c718a8 --- /dev/null +++ b/src/GraphQL.Client.Abstractions/Utilities/StringExtensions.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; + +namespace GraphQL.Client.Abstractions.Utilities +{ + /// + /// Copied from https://github.com/jquense/StringUtils + /// + public static class StringExtensions + { + public static string StripIndent(this string str) => GraphQL.Client.Abstractions.Utilities.StringUtils.StripIndent(str); + + public static IEnumerable ToWords(this string str) => GraphQL.Client.Abstractions.Utilities.StringUtils.ToWords(str); + + public static string ToUpperFirst(this string str) => GraphQL.Client.Abstractions.Utilities.StringUtils.ToUpperFirst(str); + + public static string ToLowerFirst(this string str) => GraphQL.Client.Abstractions.Utilities.StringUtils.ToLowerFirst(str); + + public static string Capitalize(this string str) => GraphQL.Client.Abstractions.Utilities.StringUtils.Capitalize(str); + + public static string ToCamelCase(this string str) => GraphQL.Client.Abstractions.Utilities.StringUtils.ToCamelCase(str); + + public static string ToConstantCase(this string str) => GraphQL.Client.Abstractions.Utilities.StringUtils.ToConstantCase(str); + + public static string ToUpperCase(this string str) => GraphQL.Client.Abstractions.Utilities.StringUtils.ToUpperCase(str); + + public static string ToLowerCase(this string str) => GraphQL.Client.Abstractions.Utilities.StringUtils.ToLowerCase(str); + + + public static string ToPascalCase(this string str) => GraphQL.Client.Abstractions.Utilities.StringUtils.ToPascalCase(str); + + + public static string ToKebabCase(this string str) => GraphQL.Client.Abstractions.Utilities.StringUtils.ToKebabCase(str); + + + public static string ToSnakeCase(this string str) => GraphQL.Client.Abstractions.Utilities.StringUtils.ToSnakeCase(str); + } +} diff --git a/src/GraphQL.Client.Abstractions/Utilities/StringUtils.cs b/src/GraphQL.Client.Abstractions/Utilities/StringUtils.cs new file mode 100644 index 00000000..c643fd23 --- /dev/null +++ b/src/GraphQL.Client.Abstractions/Utilities/StringUtils.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace GraphQL.Client.Abstractions.Utilities +{ + /// + /// Copied from https://github.com/jquense/StringUtils + /// + public static class StringUtils + { + private static readonly Regex _reWords = new Regex(@"[A-Z\xc0-\xd6\xd8-\xde]?[a-z\xdf-\xf6\xf8-\xff]+(?:['’](?:d|ll|m|re|s|t|ve))?(?=[\xac\xb1\xd7\xf7\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xbf\u2000-\u206f \t\x0b\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000]|[A-Z\xc0-\xd6\xd8-\xde]|$)|(?:[A-Z\xc0-\xd6\xd8-\xde]|[^\ud800-\udfff\xac\xb1\xd7\xf7\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xbf\u2000-\u206f \t\x0b\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\d+\u2700-\u27bfa-z\xdf-\xf6\xf8-\xffA-Z\xc0-\xd6\xd8-\xde])+(?:['’](?:D|LL|M|RE|S|T|VE))?(?=[\xac\xb1\xd7\xf7\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xbf\u2000-\u206f \t\x0b\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000]|[A-Z\xc0-\xd6\xd8-\xde](?:[a-z\xdf-\xf6\xf8-\xff]|[^\ud800-\udfff\xac\xb1\xd7\xf7\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xbf\u2000-\u206f \t\x0b\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\d+\u2700-\u27bfa-z\xdf-\xf6\xf8-\xffA-Z\xc0-\xd6\xd8-\xde])|$)|[A-Z\xc0-\xd6\xd8-\xde]?(?:[a-z\xdf-\xf6\xf8-\xff]|[^\ud800-\udfff\xac\xb1\xd7\xf7\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xbf\u2000-\u206f \t\x0b\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\d+\u2700-\u27bfa-z\xdf-\xf6\xf8-\xffA-Z\xc0-\xd6\xd8-\xde])+(?:['’](?:d|ll|m|re|s|t|ve))?|[A-Z\xc0-\xd6\xd8-\xde]+(?:['’](?:D|LL|M|RE|S|T|VE))?|\d+|(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|\ud83c[\udffb-\udfff])?(?:\u200d(?:[^\ud800-\udfff]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff])[\ufe0e\ufe0f]?(?:[\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0]|\ud83c[\udffb-\udfff])?)*"); + private static readonly Regex _reIndent = new Regex(@"^[ \t]*(?=\S)", RegexOptions.Multiline); + + /// + /// Removes the leading indent from a multi-line string + /// + /// String + /// + public static string StripIndent(string str) + { + int indent = _reIndent.Matches(str).Cast().Select(m => m.Value.Length).Min(); + return new Regex(@"^[ \t]{" + indent + "}", RegexOptions.Multiline).Replace(str, ""); + } + + /// + /// Split a cased string into a series of "words" excluding the seperator. + /// + /// + /// + public static IEnumerable ToWords(string str) + { + foreach (Match match in _reWords.Matches(str)) + { + yield return match.Value; + } + } + + /// + /// Uppercase the first character in a string, leaving the rest of the string as is + /// + /// + /// a string with the first character uppercased + public static string ToUpperFirst(string str) => ChangeCaseFirst(str, c => c.ToUpperInvariant()); + + /// + /// Lowercase the first character in a string, leaving the rest of the string as is + /// + /// + /// a string with the first character lowercased + public static string ToLowerFirst(string str) => ChangeCaseFirst(str, c => c.ToLowerInvariant()); + + /// + /// Capitalizes a string, lowercasing the entire string and uppercasing the first character + /// + /// + /// a capitalized string + public static string Capitalize(string str) => ToUpperFirst(str.ToLowerInvariant()); + + /// + /// Converts a string to camelCase. + /// + /// + /// StringUtils.ToCamelCase("FOOBAR") // "foobar" + /// StringUtils.ToCamelCase("FOO_BAR") // "fooBar" + /// StringUtils.ToCamelCase("FooBar") // "fooBar" + /// StringUtils.ToCamelCase("foo bar") // "fooBar" + /// + /// + /// + public static string ToCamelCase(string str) => + ChangeCase(str, (word, index) => + (index == 0 ? word.ToLowerInvariant() : Capitalize(word))); + + /// + /// Convert a string to CONSTANT_CASE + /// + /// + /// StringUtils.ToConstantCase("fOo BaR") // "FOO_BAR" + /// StringUtils.ToConstantCase("FooBar") // "FOO_BAR" + /// StringUtils.ToConstantCase("Foo Bar") // "FOO_BAR" + /// + /// + /// + public static string ToConstantCase(string str) => ChangeCase(str, "_", w => w.ToUpperInvariant()); + + /// + /// Convert a string to UPPERCASE + /// + /// + /// StringUtils.ToUpperCase("foobar") // "FOOBAR" + /// StringUtils.ToUpperCase("FOO_BAR") // "FOO BAR" + /// StringUtils.ToUpperCase("FooBar") // "FOO BAR" + /// StringUtils.ToUpperCase("Foo Bar") // "FOO BAR" + /// + /// + /// + public static string ToUpperCase(string str) => ChangeCase(str, " ", (word) => word.ToUpperInvariant()); + + /// + /// Convert a string to lowercase + /// + /// + /// StringUtils.ToLowerCase("FOOBAR") // "foobar" + /// StringUtils.ToLowerCase("FOO_BAR") // "foo bar" + /// StringUtils.ToLowerCase("FooBar") // "foo bar" + /// StringUtils.ToLowerCase("Foo Bar") // "foo bar" + /// + /// + /// + public static string ToLowerCase(string str) => ChangeCase(str, " ", word => word.ToLowerInvariant()); + + /// + /// convert a string to PascalCase + /// + /// + /// StringUtils.ToPascalCase("FOOBAR") // "FooBar" + /// StringUtils.ToPascalCase("FOO_BAR") // "FooBar" + /// StringUtils.ToPascalCase("fooBar") // "FooBar" + /// StringUtils.ToPascalCase("Foo Bar") // "FooBar" + /// + /// + /// + public static string ToPascalCase(string str) => ChangeCase(str, Capitalize); + + /// + /// convert a string to kebab-case + /// + /// + /// StringUtils.ToKebabCase("FOOBAR") // "foo-bar" + /// StringUtils.ToKebabCase("FOO_BAR") // "foo-bar" + /// StringUtils.ToKebabCase("fooBar") // "foo-bar" + /// StringUtils.ToKebabCase("Foo Bar") // "foo-bar" + /// + /// + /// + public static string ToKebabCase(string str) => ChangeCase(str, "-", word => word.ToLowerInvariant()); + + /// + /// convert a string to snake_case + /// + /// + /// StringUtils.ToSnakeCase("FOOBAR") // "foo_bar" + /// StringUtils.ToSnakeCase("FOO_BAR") // "foo_bar" + /// StringUtils.ToSnakeCase("fooBar") // "foo_bar" + /// StringUtils.ToSnakeCase("Foo Bar") // "foo_bar" + /// + /// + /// + public static string ToSnakeCase(string str) => ChangeCase(str, "_", word => word.ToLowerInvariant()); + + public static string ChangeCase(string str, Func composer) => ChangeCase(str, "", composer); + + public static string ChangeCase(string str, string sep, Func composer) => ChangeCase(str, sep, (w, i) => composer(w)); + + public static string ChangeCase(string str, Func composer) => ChangeCase(str, "", composer); + + /// + /// Convert a string to a new case + /// + /// + /// Convert a string to inverse camelCase: CAMELcASE + /// + /// StringUtils.ChangeCase("my string", "", (word, index) => { + /// word = word.ToUpperInvariant(); + /// if (index > 0) + /// word = StringUtils.toLowerFirst(word); + /// return word + /// }); + /// // "MYsTRING" + /// + /// + /// an input string + /// a seperator string used between "words" in the string + /// a function that converts individual words to a new case + /// + public static string ChangeCase(string str, string sep, Func composer) + { + string result = ""; + int index = 0; + + foreach (string word in ToWords(str)) + { + result += ((index == 0 ? "" : sep) + composer(word, index++)); + } + + return result; + } + + private static string ChangeCaseFirst(string str, Func change) => change(str.Substring(0, 1)) + str.Substring(1); + } +} diff --git a/src/GraphQL.Client.Serializer.Newtonsoft/ConstantCaseEnumConverter.cs b/src/GraphQL.Client.Serializer.Newtonsoft/ConstantCaseEnumConverter.cs index 5eb45f73..d618a490 100644 --- a/src/GraphQL.Client.Serializer.Newtonsoft/ConstantCaseEnumConverter.cs +++ b/src/GraphQL.Client.Serializer.Newtonsoft/ConstantCaseEnumConverter.cs @@ -1,9 +1,9 @@ using System; using System.Linq; using System.Reflection; +using GraphQL.Client.Abstractions.Utilities; using Newtonsoft.Json; using Newtonsoft.Json.Converters; -using Panic.StringUtils.Extensions; namespace GraphQL.Client.Serializer.Newtonsoft { diff --git a/src/GraphQL.Client.Serializer.Newtonsoft/GraphQL.Client.Serializer.Newtonsoft.csproj b/src/GraphQL.Client.Serializer.Newtonsoft/GraphQL.Client.Serializer.Newtonsoft.csproj index f603fc93..4bbcb784 100644 --- a/src/GraphQL.Client.Serializer.Newtonsoft/GraphQL.Client.Serializer.Newtonsoft.csproj +++ b/src/GraphQL.Client.Serializer.Newtonsoft/GraphQL.Client.Serializer.Newtonsoft.csproj @@ -9,7 +9,6 @@ - diff --git a/src/GraphQL.Client.Serializer.SystemTextJson/ConstantCaseJsonNamingPolicy.cs b/src/GraphQL.Client.Serializer.SystemTextJson/ConstantCaseJsonNamingPolicy.cs index b2ea49eb..138b0276 100644 --- a/src/GraphQL.Client.Serializer.SystemTextJson/ConstantCaseJsonNamingPolicy.cs +++ b/src/GraphQL.Client.Serializer.SystemTextJson/ConstantCaseJsonNamingPolicy.cs @@ -1,5 +1,5 @@ using System.Text.Json; -using Panic.StringUtils.Extensions; +using GraphQL.Client.Abstractions.Utilities; namespace GraphQL.Client.Serializer.SystemTextJson { diff --git a/src/GraphQL.Client.Serializer.SystemTextJson/GraphQL.Client.Serializer.SystemTextJson.csproj b/src/GraphQL.Client.Serializer.SystemTextJson/GraphQL.Client.Serializer.SystemTextJson.csproj index 93fe58af..9433b8dd 100644 --- a/src/GraphQL.Client.Serializer.SystemTextJson/GraphQL.Client.Serializer.SystemTextJson.csproj +++ b/src/GraphQL.Client.Serializer.SystemTextJson/GraphQL.Client.Serializer.SystemTextJson.csproj @@ -15,8 +15,4 @@ - - - -