5
5
using System . Collections . Generic ;
6
6
using System . Linq ;
7
7
using System . Reflection ;
8
+ using System . Text . RegularExpressions ;
8
9
using Microsoft . AspNet . Razor . TagHelpers ;
9
10
10
11
namespace Microsoft . AspNet . Razor . Runtime . TagHelpers
@@ -15,6 +16,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
15
16
public static class TagHelperDescriptorFactory
16
17
{
17
18
private const string TagHelperNameEnding = "TagHelper" ;
19
+ private const string HtmlCaseRegexReplacement = "-$1$2" ;
20
+
21
+ // This matches the following AFTER the start of the input string (MATCH).
22
+ // Any letter/number followed by an uppercase letter then lowercase letter: 1(Aa), a(Aa), A(Aa)
23
+ // Any lowercase letter followed by an uppercase letter: a(A)
24
+ // Each match is then prefixed by a "-" via the ToHtmlCase method.
25
+ private static readonly Regex HtmlCaseRegex =
26
+ new Regex ( "(?<!^)((?<=[a-zA-Z0-9])[A-Z][a-z])|((?<=[a-z])[A-Z])" , RegexOptions . None ) ;
18
27
19
28
// TODO: Investigate if we should cache TagHelperDescriptors for types:
20
29
// https://github.com/aspnet/Razor/issues/165
@@ -55,7 +64,7 @@ private static IEnumerable<string> GetTagNames(Type tagHelperType)
55
64
name = name . Substring ( 0 , name . Length - TagHelperNameEnding . Length ) ;
56
65
}
57
66
58
- return new [ ] { name } ;
67
+ return new [ ] { ToHtmlCase ( name ) } ;
59
68
}
60
69
61
70
// Remove duplicate tag names.
@@ -75,7 +84,7 @@ private static TagHelperAttributeDescriptor ToAttributeDescriptor(PropertyInfo p
75
84
var attributeNameAttribute = property . GetCustomAttribute < HtmlAttributeNameAttribute > ( inherit : false ) ;
76
85
var attributeName = attributeNameAttribute != null ?
77
86
attributeNameAttribute . Name :
78
- property . Name ;
87
+ ToHtmlCase ( property . Name ) ;
79
88
80
89
return new TagHelperAttributeDescriptor ( attributeName , property . Name , property . PropertyType . FullName ) ;
81
90
}
@@ -97,5 +106,22 @@ private static bool IsValidProperty(PropertyInfo property)
97
106
property . SetMethod != null &&
98
107
property . SetMethod . IsPublic ;
99
108
}
109
+
110
+ /// <summary>
111
+ /// Converts from pascal/camel case to lower kebab-case.
112
+ /// </summary>
113
+ /// <example>
114
+ /// SomeThing => some-thing
115
+ /// capsONInside => caps-on-inside
116
+ /// CAPSOnOUTSIDE => caps-on-outside
117
+ /// ALLCAPS => allcaps
118
+ /// One1Two2Three3 => one1-two2-three3
119
+ /// ONE1TWO2THREE3 => one1two2three3
120
+ /// First_Second_ThirdHi => first_second_third-hi
121
+ /// </example>
122
+ private static string ToHtmlCase ( string name )
123
+ {
124
+ return HtmlCaseRegex . Replace ( name , HtmlCaseRegexReplacement ) . ToLowerInvariant ( ) ;
125
+ }
100
126
}
101
127
}
0 commit comments