@@ -5,7 +5,7 @@ public class FileNameRuleAnalyzer : IIncrementalGenerator
55{
66 public const string DiagnosticId = "TWA001" ;
77 private const string Category = "Naming" ;
8-
8+
99 private static readonly DiagnosticDescriptor Rule = new (
1010 DiagnosticId ,
1111 "File name should use kebab-case" ,
@@ -15,10 +15,10 @@ public class FileNameRuleAnalyzer : IIncrementalGenerator
1515 isEnabledByDefault : false ,
1616 description : "C# file names should use kebab-case format with hyphens separating words, all lowercase."
1717 ) ;
18-
18+
1919 // Regex pattern for valid kebab-case file names
2020 private static readonly Regex KebabCasePattern = new ( @"^[a-z][a-z0-9]*(?:-[a-z0-9]+)*\.cs$" , RegexOptions . Compiled ) ;
21-
21+
2222 // Default exception patterns
2323 private static readonly string [ ] DefaultExceptions =
2424 [
@@ -38,7 +38,7 @@ public class FileNameRuleAnalyzer : IIncrementalGenerator
3838 "AnalyzerReleases.Shipped.md" ,
3939 "AnalyzerReleases.Unshipped.md"
4040 ] ;
41-
41+
4242 public void Initialize ( IncrementalGeneratorInitializationContext context )
4343 {
4444 // Create a value provider that provides all syntax trees with config options
@@ -49,72 +49,72 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
4949 ( Compilation compilation , AnalyzerConfigOptionsProvider configOptions ) = source ;
5050 return compilation . SyntaxTrees . Select ( tree => ( tree , configOptions ) ) ;
5151 } ) ;
52-
52+
5353 // Register diagnostics for each syntax tree
5454 context . RegisterSourceOutput ( syntaxTreesWithConfig , ( spc , source ) =>
5555 {
5656 ( SyntaxTree tree , AnalyzerConfigOptionsProvider configOptions ) = source ;
5757 AnalyzeFileNaming ( spc , tree , configOptions ) ;
5858 } ) ;
5959 }
60-
60+
6161 private void AnalyzeFileNaming ( SourceProductionContext context , SyntaxTree tree , AnalyzerConfigOptionsProvider configOptions )
6262 {
6363 string filePath = tree . FilePath ;
64-
64+
6565 // Skip if file path is empty or null
6666 if ( string . IsNullOrEmpty ( filePath ) )
6767 return ;
68-
68+
6969 string fileName = Path . GetFileName ( filePath ) ;
70-
70+
7171 // Skip if not a C# file
7272 if ( ! fileName . EndsWith ( ".cs" , StringComparison . OrdinalIgnoreCase ) )
7373 return ;
74-
74+
7575 // Get configured exceptions
7676 string [ ] exceptions = GetConfiguredExceptions ( configOptions , tree ) ;
77-
77+
7878 // Check if file matches any exception pattern
7979 if ( IsFileExcepted ( fileName , exceptions ) )
8080 return ;
81-
81+
8282 // Check if file name follows kebab-case pattern
8383 if ( ! KebabCasePattern . IsMatch ( fileName ) )
8484 {
8585 var location = Location . Create (
8686 tree ,
8787 TextSpan . FromBounds ( 0 , 0 )
8888 ) ;
89-
89+
9090 var diagnostic = Diagnostic . Create ( Rule , location , fileName ) ;
9191 context . ReportDiagnostic ( diagnostic ) ;
9292 }
9393 }
94-
94+
9595 private string [ ] GetConfiguredExceptions ( AnalyzerConfigOptionsProvider configOptions , SyntaxTree tree )
9696 {
9797 // Get file-specific options
9898 AnalyzerConfigOptions options = configOptions . GetOptions ( tree ) ;
99-
99+
100100 // Try to get configured exceptions from .editorconfig
101101 if ( options . TryGetValue (
102- "dotnet_diagnostic.TWA001.excluded_files" ,
102+ "dotnet_diagnostic.TWA001.excluded_files" ,
103103 out string ? configuredExceptions ) && ! string . IsNullOrEmpty ( configuredExceptions ) )
104104 {
105105 // Split by semicolon and trim whitespace
106106 IEnumerable < string > additionalExceptions = configuredExceptions
107107 . Split ( [ ';' ] , StringSplitOptions . RemoveEmptyEntries )
108108 . Select ( s => s . Trim ( ) ) ;
109-
109+
110110 // Merge defaults with configured exceptions
111111 return [ .. DefaultExceptions , .. additionalExceptions ] ;
112112 }
113-
113+
114114 // Return default exceptions if not configured
115115 return DefaultExceptions ;
116116 }
117-
117+
118118 private bool IsFileExcepted ( string fileName , string [ ] exceptions )
119119 {
120120 foreach ( string exception in exceptions )
@@ -125,7 +125,7 @@ private bool IsFileExcepted(string fileName, string[] exceptions)
125125 string pattern = exception
126126 . Replace ( "." , "\\ ." )
127127 . Replace ( "*" , ".*" ) ;
128-
128+
129129 if ( Regex . IsMatch ( fileName , $ "^{ pattern } $", RegexOptions . IgnoreCase ) )
130130 return true ;
131131 }
@@ -136,7 +136,7 @@ private bool IsFileExcepted(string fileName, string[] exceptions)
136136 return true ;
137137 }
138138 }
139-
139+
140140 return false ;
141141 }
142142}
0 commit comments