@@ -23,7 +23,7 @@ public class AttributeAnalyzer : DiagnosticAnalyzer
2323 ASP006ParameterRegex . Descriptor ,
2424 ASP007MissingParameter . Descriptor ,
2525 ASP008ValidRouteParameterName . Descriptor ,
26- ASP009LowercaseUrl . Descriptor ) ;
26+ ASP009KebabCaseUrl . Descriptor ) ;
2727
2828 public override void Initialize ( AnalysisContext context )
2929 {
@@ -134,19 +134,17 @@ context.Node is AttributeSyntax attribute &&
134134 ASP008ValidRouteParameterName . Descriptor ,
135135 location ,
136136 name == null
137- ? ImmutableDictionary < string , string > . Empty
138- : ImmutableDictionary < string , string > . Empty . Add ( nameof ( Text ) , name ) ) ) ;
137+ ? ImmutableDictionary < string , string > . Empty
138+ : ImmutableDictionary < string , string > . Empty . Add ( nameof ( Text ) , name ) ) ) ;
139139 }
140140
141- if ( IsUpperCase ( segment , out var lowercase ) )
141+ if ( ShouldKebabCase ( segment , out var kebabCase ) )
142142 {
143143 context . ReportDiagnostic (
144144 Diagnostic . Create (
145- ASP009LowercaseUrl . Descriptor ,
145+ ASP009KebabCaseUrl . Descriptor ,
146146 segment . Span . GetLocation ( ) ,
147- lowercase == null
148- ? ImmutableDictionary < string , string > . Empty
149- : ImmutableDictionary < string , string > . Empty . Add ( nameof ( Text ) , lowercase ) ) ) ;
147+ ImmutableDictionary < string , string > . Empty . Add ( nameof ( Text ) , kebabCase ) ) ) ;
150148 }
151149 }
152150 }
@@ -518,8 +516,7 @@ private static bool HasInvalidName(PathSegment segment, out Location location, o
518516 parameter . Name . EndsWith ( " " , StringComparison . OrdinalIgnoreCase ) )
519517 {
520518 location = parameter . Name . GetLocation ( ) ;
521- correctName = parameter . Name . ToString ( )
522- . Trim ( ) ;
519+ correctName = parameter . Name . ToString ( ) . Trim ( ) ;
523520 return true ;
524521 }
525522
@@ -540,7 +537,7 @@ private static bool HasInvalidName(PathSegment segment, out Location location, o
540537 return false ;
541538 }
542539
543- private static bool IsUpperCase ( PathSegment segment , out string lowercase )
540+ private static bool IsUppercase ( PathSegment segment , out string lowercase )
544541 {
545542 if ( segment . Parameter == null &&
546543 segment . Span . Length > 0 &&
@@ -562,5 +559,56 @@ private static bool IsUpperCase(PathSegment segment, out string lowercase)
562559 lowercase = null ;
563560 return false ;
564561 }
562+
563+ private static bool ShouldKebabCase ( PathSegment segment , out string kebabCase )
564+ {
565+ if ( segment . Parameter == null &&
566+ IsHumpOrSnakeCased ( segment . Span ) )
567+ {
568+ var builder = StringBuilderPool . Borrow ( ) ;
569+ for ( var i = 0 ; i < segment . Span . Length ; i ++ )
570+ {
571+ var c = segment . Span [ i ] ;
572+ if ( char . IsUpper ( c ) )
573+ {
574+ if ( i > 0 )
575+ {
576+ _ = builder . Append ( "-" ) ;
577+ }
578+
579+ _ = builder . Append ( char . ToLower ( c ) ) ;
580+ }
581+ else if ( c == '_' )
582+ {
583+ _ = builder . Append ( "-" ) ;
584+ }
585+ else
586+ {
587+ _ = builder . Append ( c ) ;
588+ }
589+ }
590+
591+ kebabCase = builder . Return ( ) ;
592+ return true ;
593+ }
594+
595+ kebabCase = null ;
596+ return false ;
597+
598+ bool IsHumpOrSnakeCased ( Span span )
599+ {
600+ for ( var i = 0 ; i < segment . Span . Length ; i ++ )
601+ {
602+ var c = segment . Span [ i ] ;
603+ if ( char . IsUpper ( c ) ||
604+ c == '_' )
605+ {
606+ return true ;
607+ }
608+ }
609+
610+ return false ;
611+ }
612+ }
565613 }
566614}
0 commit comments