Skip to content

Commit 46b2dc3

Browse files
Substitution of ToPascalCase logic with a more general one
1 parent 399c6a5 commit 46b2dc3

File tree

1 file changed

+80
-41
lines changed

1 file changed

+80
-41
lines changed

XmlSchemaClassGenerator/CodeUtilities.cs

Lines changed: 80 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,55 @@ namespace XmlSchemaClassGenerator
1414
{
1515
public static class CodeUtilities
1616
{
17-
// Match non-letter followed by letter
18-
private static readonly Regex PascalCaseRegex = new(@"[^\p{L}]\p{L}", RegexOptions.Compiled);
19-
20-
// Uppercases first letter and all letters following non-letters.
21-
// Examples: testcase -> Testcase, html5element -> Html5Element, test_case -> Test_Case
22-
public static string ToPascalCase(this string s) => string.IsNullOrEmpty(s) ? s
23-
: char.ToUpperInvariant(s[0]) + PascalCaseRegex.Replace(s.Substring(1), m => m.Value[0] + char.ToUpperInvariant(m.Value[1]).ToString());
17+
private static readonly Regex invalidCharsRgx = new Regex("[^_a-zA-Z0-9]");
18+
private static readonly Regex whiteSpace = new Regex(@"(?<=\s)");
19+
private static readonly Regex startsWithLowerCaseChar = new Regex("^[a-z]");
20+
private static readonly Regex firstCharFollowedByUpperCasesOnly = new Regex("(?<=[A-Z])[A-Z0-9]+$");
21+
private static readonly Regex lowerCaseNextToNumber = new Regex("(?<=[0-9])[a-z]");
22+
private static readonly Regex upperCaseInside = new Regex("(?<=[A-Z])[A-Z]+?((?=[A-Z][a-z])|(?=[0-9]))");
23+
24+
// Credits: chviLadislav
25+
// https://stackoverflow.com/questions/18627112/how-can-i-convert-text-to-pascal-case
26+
// Example output:
27+
// "WARD_VS_VITAL_SIGNS" "WardVsVitalSigns"
28+
// "Who am I?" "WhoAmI"
29+
// "I ate before you got here" "IAteBeforeYouGotHere"
30+
// "Hello|Who|Am|I?" "HelloWhoAmI"
31+
// "Live long and prosper" "LiveLongAndProsper"
32+
// "Lorem ipsum dolor..." "LoremIpsumDolor"
33+
// "CoolSP" "CoolSp"
34+
// "AB9CD" "Ab9Cd"
35+
// "CCCTrigger" "CccTrigger"
36+
// "CIRC" "Circ"
37+
// "ID_SOME" "IdSome"
38+
// "ID_SomeOther" "IdSomeOther"
39+
// "ID_SOMEOther" "IdSomeOther"
40+
// "CCC_SOME_2Phases" "CccSome2Phases"
41+
// "AlreadyGoodPascalCase" "AlreadyGoodPascalCase"
42+
// "999 999 99 9 " "999999999"
43+
// "1 2 3 " "123"
44+
// "1 AB cd EFDDD 8" "1AbCdEfddd8"
45+
// "INVALID VALUE AND _2THINGS" "InvalidValueAnd2Things"
46+
public static string ToPascalCase(this string original)
47+
{
48+
// replace white spaces with undescore, then replace all invalid chars with empty string
49+
var pascalCase = invalidCharsRgx.Replace(whiteSpace.Replace(original, "_"), string.Empty)
50+
// split by underscores
51+
.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries)
52+
// set first letter to uppercase
53+
.Select(w => startsWithLowerCaseChar.Replace(w, m => m.Value.ToUpper()))
54+
// replace second and all following upper case letters to lower if there is no next lower (ABC -> Abc)
55+
.Select(w => firstCharFollowedByUpperCasesOnly.Replace(w, m => m.Value.ToLower()))
56+
// set upper case the first lower case following a number (Ab9cd -> Ab9Cd)
57+
.Select(w => lowerCaseNextToNumber.Replace(w, m => m.Value.ToUpper()))
58+
// lower second and next upper case letters except the last if it follows by any lower (ABcDEf -> AbcDef)
59+
.Select(w => upperCaseInside.Replace(w, m => m.Value.ToLower()));
60+
61+
return string.Concat(pascalCase);
62+
}
2463

2564
public static string ToCamelCase(this string s) => string.IsNullOrEmpty(s) ? s
26-
: char.ToLowerInvariant(s[0]) + s.Substring(1);
65+
: char.ToLowerInvariant(s[0]) + s.Substring(1);
2766

2867
public static string ToBackingField(this string propertyName, string privateFieldPrefix)
2968
=> string.Concat(privateFieldPrefix, propertyName.ToCamelCase());
@@ -76,37 +115,37 @@ private static Type GetIntegerDerivedType(XmlSchemaDatatype xml, GeneratorConfig
76115
Type FromDigitRestriction(TotalDigitsRestrictionModel totalDigits
77116
) => xml.TypeCode switch
78117
{
79-
XmlTypeCode.PositiveInteger or XmlTypeCode.NonNegativeInteger => totalDigits?.Value switch
80-
{
81-
< 3 => typeof(byte),
82-
< 5 => typeof(ushort),
83-
< 10 => typeof(uint),
84-
< 20 => typeof(ulong),
85-
< 30 => typeof(decimal),
86-
_ => null
87-
},
88-
XmlTypeCode.Integer or XmlTypeCode.NegativeInteger or XmlTypeCode.NonPositiveInteger => totalDigits
89-
?.Value switch
90-
{
91-
< 3 => typeof(sbyte),
92-
< 5 => typeof(short),
93-
< 10 => typeof(int),
94-
< 19 => typeof(long),
95-
< 29 => typeof(decimal),
96-
_ => null
97-
},
98-
XmlTypeCode.Decimal
99-
when restrictions.OfType<FractionDigitsRestrictionModel>().SingleOrDefault() is { IsSupported: true, Value: 0 } => totalDigits
100-
?.Value switch
101-
{
102-
< 3 => typeof(sbyte),
103-
< 5 => typeof(short),
104-
< 10 => typeof(int),
105-
< 19 => typeof(long),
106-
< 29 => typeof(decimal),
107-
_ => null
108-
},
109-
_ => null
118+
XmlTypeCode.PositiveInteger or XmlTypeCode.NonNegativeInteger => totalDigits?.Value switch
119+
{
120+
< 3 => typeof(byte),
121+
< 5 => typeof(ushort),
122+
< 10 => typeof(uint),
123+
< 20 => typeof(ulong),
124+
< 30 => typeof(decimal),
125+
_ => null
126+
},
127+
XmlTypeCode.Integer or XmlTypeCode.NegativeInteger or XmlTypeCode.NonPositiveInteger => totalDigits
128+
?.Value switch
129+
{
130+
< 3 => typeof(sbyte),
131+
< 5 => typeof(short),
132+
< 10 => typeof(int),
133+
< 19 => typeof(long),
134+
< 29 => typeof(decimal),
135+
_ => null
136+
},
137+
XmlTypeCode.Decimal
138+
when restrictions.OfType<FractionDigitsRestrictionModel>().SingleOrDefault() is { IsSupported: true, Value: 0 } => totalDigits
139+
?.Value switch
140+
{
141+
< 3 => typeof(sbyte),
142+
< 5 => typeof(short),
143+
< 10 => typeof(int),
144+
< 19 => typeof(long),
145+
< 29 => typeof(decimal),
146+
_ => null
147+
},
148+
_ => null
110149
};
111150

112151
Type FromFallback() => configuration.UseIntegerDataTypeAsFallback && configuration.IntegerDataType != null ? configuration.IntegerDataType : typeof(string);
@@ -124,8 +163,8 @@ public static Type GetEffectiveType(this XmlSchemaDatatype type, GeneratorConfig
124163
XmlTypeCode.Time => typeof(DateTime),
125164
XmlTypeCode.Idref => typeof(string),
126165
XmlTypeCode.Integer or XmlTypeCode.NegativeInteger or XmlTypeCode.NonNegativeInteger or XmlTypeCode.NonPositiveInteger or XmlTypeCode.PositiveInteger => GetIntegerDerivedType(type, configuration, restrictions),
127-
XmlTypeCode.Decimal when restrictions.OfType<FractionDigitsRestrictionModel>().SingleOrDefault() is { IsSupported: true, Value: 0 } => GetIntegerDerivedType(type, configuration, restrictions),
128-
_ => type.ValueType,
166+
XmlTypeCode.Decimal when restrictions.OfType<FractionDigitsRestrictionModel>().SingleOrDefault() is { IsSupported: true, Value: 0 } => GetIntegerDerivedType(type, configuration, restrictions),
167+
_ => type.ValueType,
129168
};
130169

131170
if (schemaType.IsDerivedFrom(GuidQualifiedName))

0 commit comments

Comments
 (0)