88
99using System . Globalization ;
1010using System . Linq ;
11- using System . Runtime . CompilerServices ;
1211using System . Text ;
1312using System . Text . RegularExpressions ;
1413using System . Xml . Linq ;
@@ -18,68 +17,128 @@ namespace NJsonSchema
1817 /// <summary>Provides name conversion utility methods.</summary>
1918 public class ConversionUtilities
2019 {
20+ private static readonly char [ ] _camelCaseCleanupChars = [ ' ' , '/' ] ;
21+
22+ #if NET8_0_OR_GREATER
23+ private static readonly System . Buffers . SearchValues < char > CamelCaseCleanupChars = System . Buffers . SearchValues . Create ( _camelCaseCleanupChars ) ;
24+ #else
25+ private static readonly char [ ] CamelCaseCleanupChars = _camelCaseCleanupChars ;
26+ #endif
27+
28+ /// <summary>Converts the input to a camel case identifier.</summary>
29+ /// <param name="input">The input.</param>
30+ /// <returns>The converted input. </returns>
31+ public static string ConvertToCamelCase ( string input )
32+ {
33+ return ConvertToCamelCase ( input , firstCharacterMustBeAlpha : false , CamelCaseMode . None ) ;
34+ }
35+
2136 /// <summary>Converts the first letter to lower case and dashes to camel case.</summary>
2237 /// <param name="input">The input.</param>
2338 /// <param name="firstCharacterMustBeAlpha">Specifies whether to add an _ when the first character is not alpha.</param>
2439 /// <returns>The converted input.</returns>
2540 public static string ConvertToLowerCamelCase ( string input , bool firstCharacterMustBeAlpha )
2641 {
27- if ( string . IsNullOrEmpty ( input ) )
28- {
29- return string . Empty ;
30- }
31-
32- var lowered = char . ToLowerInvariant ( input [ 0 ] ) + ( input . Length > 1 ? input . Substring ( 1 ) : "" ) ;
33- var cleaned = lowered . Replace ( ' ' , '_' ) . Replace ( '/' , '_' ) ;
34- input = ConvertDashesToCamelCase ( cleaned ) ;
35-
36- if ( string . IsNullOrEmpty ( input ) )
37- {
38- return string . Empty ;
39- }
40-
41- if ( firstCharacterMustBeAlpha && char . IsNumber ( input [ 0 ] ) )
42- {
43- return "_" + input ;
44- }
45-
46- return input ;
42+ return ConvertToCamelCase ( input , firstCharacterMustBeAlpha , CamelCaseMode . FirstLower ) ;
4743 }
4844
4945 /// <summary>Converts the first letter to upper case and dashes to camel case.</summary>
5046 /// <param name="input">The input.</param>
5147 /// <param name="firstCharacterMustBeAlpha">Specifies whether to add an _ when the first character is not alpha.</param>
5248 /// <returns>The converted input.</returns>
5349 public static string ConvertToUpperCamelCase ( string input , bool firstCharacterMustBeAlpha )
50+ {
51+ return ConvertToCamelCase ( input , firstCharacterMustBeAlpha , CamelCaseMode . FirstUpper ) ;
52+ }
53+
54+ private static string ConvertToCamelCase ( string input , bool firstCharacterMustBeAlpha , CamelCaseMode mode )
5455 {
5556 if ( string . IsNullOrEmpty ( input ) )
5657 {
5758 return string . Empty ;
5859 }
5960
60- var cleaned = Capitalize ( input ) . Replace ( ' ' , '_' ) . Replace ( '/' , '_' ) ;
61- input = ConvertDashesToCamelCase ( cleaned ) ;
61+ if ( input . AsSpan ( ) . IndexOfAny ( CamelCaseCleanupChars ) != - 1 )
62+ {
63+ input = input . Replace ( ' ' , '_' ) . Replace ( '/' , '_' ) ;
64+ }
6265
63- if ( firstCharacterMustBeAlpha && char . IsNumber ( input [ 0 ] ) )
66+ if ( input . AsSpan ( ) . IndexOf ( '-' ) == - 1 )
6467 {
65- return "_" + input ;
68+ // no need for expensive conversion
69+ var c = input [ 0 ] ;
70+ if ( char . IsNumber ( c ) )
71+ {
72+ return firstCharacterMustBeAlpha ? "_" + input : input ;
73+ }
74+
75+ var newFirst = mode switch
76+ {
77+ CamelCaseMode . FirstUpper => char . ToUpperInvariant ( c ) ,
78+ CamelCaseMode . FirstLower => char . ToLowerInvariant ( c ) ,
79+ _ => c
80+ } ;
81+
82+ if ( newFirst != c )
83+ {
84+ return newFirst + input [ 1 ..] ;
85+ }
86+
87+ return input ;
6688 }
6789
68- return input ;
90+ return DoFullCamelCaseConversion ( input , firstCharacterMustBeAlpha , mode ) ;
6991 }
7092
71- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
72- private static string Capitalize ( string input )
93+ private static string DoFullCamelCaseConversion ( string input , bool firstCharacterMustBeAlpha , CamelCaseMode mode )
7394 {
74- if ( char . IsUpper ( input [ 0 ] ) )
75- {
76- return input ;
77- }
78- if ( input . Length == 1 )
95+ var capacity = input . Length + ( firstCharacterMustBeAlpha ? 1 : 0 ) ;
96+ var buffer = capacity < 2 ? stackalloc char [ capacity ] : new char [ capacity ] ;
97+
98+ var sb = new ValueStringBuilder ( buffer ) ;
99+
100+ var caseFlag = false ;
101+ for ( var i = 0 ; i < input . Length ; i ++ )
79102 {
80- return char . ToUpperInvariant ( input [ 0 ] ) . ToString ( ) ;
103+ var c = input [ i ] ;
104+ if ( c == '-' )
105+ {
106+ caseFlag = true ;
107+ }
108+ else if ( caseFlag )
109+ {
110+ sb . Append ( char . ToUpperInvariant ( c ) ) ;
111+ caseFlag = false ;
112+ }
113+ else
114+ {
115+ if ( i == 0 )
116+ {
117+ if ( firstCharacterMustBeAlpha && char . IsNumber ( c ) )
118+ {
119+ sb . Append ( '_' ) ;
120+ }
121+ else if ( mode == CamelCaseMode . FirstUpper )
122+ {
123+ c = char . ToUpperInvariant ( c ) ;
124+ }
125+ else if ( mode == CamelCaseMode . FirstLower )
126+ {
127+ c = char . ToLowerInvariant ( c ) ;
128+ }
129+ }
130+ sb . Append ( c ) ;
131+ }
81132 }
82- return char . ToUpperInvariant ( input [ 0 ] ) + input . Substring ( 1 ) ;
133+
134+ return sb . ToString ( ) ;
135+ }
136+
137+ private enum CamelCaseMode
138+ {
139+ None ,
140+ FirstLower ,
141+ FirstUpper ,
83142 }
84143
85144 /// <summary>Converts the string to a string literal which can be used in C# or TypeScript code.</summary>
@@ -135,7 +194,7 @@ internal static string ConvertToStringLiteral(string input, string? prefix, stri
135194 break ;
136195 default :
137196 // ASCII printable character
138- if ( c is >= ( char ) 0x20 and <= ( char ) 0x7e )
197+ if ( c is >= ( char ) 0x20 and <= ( char ) 0x7e )
139198 {
140199 literal . Append ( c ) ;
141200 // As UTF16 escaped character
@@ -158,20 +217,6 @@ internal static string ConvertToStringLiteral(string input, string? prefix, stri
158217 return literal . ToString ( ) ;
159218 }
160219
161- /// <summary>Converts the input to a camel case identifier.</summary>
162- /// <param name="input">The input.</param>
163- /// <returns>The converted input. </returns>
164- public static string ConvertToCamelCase ( string input )
165- {
166- if ( string . IsNullOrEmpty ( input ) )
167- {
168- return string . Empty ;
169- }
170-
171- return ConvertDashesToCamelCase ( input . Replace ( " " , "_" ) . Replace ( "/" , "_" ) ) ;
172- }
173-
174-
175220 private static readonly char [ ] _whiteSpaceChars = [ '\n ' , '\r ' , '\t ' , ' ' ] ;
176221
177222 /// <summary>Trims white spaces from the text.</summary>
@@ -354,36 +399,5 @@ private static string CreateTabString(int tabCount)
354399 var tabString = new string ( ' ' , 4 * tabCount ) ;
355400 return tabString ;
356401 }
357-
358- private static string ConvertDashesToCamelCase ( string input )
359- {
360- if ( ! input . Contains ( '-' ) )
361- {
362- // no conversion necessary
363- return input ;
364- }
365-
366- // we are removing at least one character
367- var sb = new ValueStringBuilder ( input . Length - 1 ) ;
368- var caseFlag = false ;
369- foreach ( var c in input )
370- {
371- if ( c == '-' )
372- {
373- caseFlag = true ;
374- }
375- else if ( caseFlag )
376- {
377- sb . Append ( char . ToUpperInvariant ( c ) ) ;
378- caseFlag = false ;
379- }
380- else
381- {
382- sb . Append ( c ) ;
383- }
384- }
385-
386- return sb . ToString ( ) ;
387- }
388402 }
389403}
0 commit comments