@@ -14,56 +14,31 @@ public sealed partial class ValidationsGenerator : IIncrementalGenerator
1414{
1515 public void Initialize ( IncrementalGeneratorInitializationContext context )
1616 {
17- // Get the MSBuild properties for controlling attribute generation
18- var generatorSettings = context . AnalyzerConfigOptionsProvider
19- . Select ( ( configOptions , _ ) =>
20- {
21- configOptions . GlobalOptions . TryGetValue ( "build_property.RootNamespace" , out var rootNamespace ) ;
22- configOptions . GlobalOptions . TryGetValue ( "build_property.GenerateBuiltinValidatableTypeAttribute" , out var generateAttribute ) ;
23-
24- var shouldGenerate = ! string . IsNullOrEmpty ( rootNamespace ) &&
25- string . Equals ( generateAttribute , "true" , StringComparison . OrdinalIgnoreCase ) ;
26-
27- return new GeneratorSettings ( rootNamespace , shouldGenerate ) ;
28- } ) ;
29-
30- // Emit the ValidatableTypeAttribute conditionally
31- context . RegisterSourceOutput ( generatorSettings , EmitValidatableTypeAttribute ) ;
32-
3317 // Find the builder.Services.AddValidation() call in the application.
3418 var addValidation = context . SyntaxProvider . CreateSyntaxProvider (
3519 predicate : FindAddValidation ,
3620 transform : TransformAddValidation
3721 ) ;
3822
39- // Extract types that have been marked with [ValidatableType].
40- // This handles both the framework attribute and the auto-generated attribute.
41- var validatableTypesWithAttribute = context . SyntaxProvider . ForAttributeWithMetadataName (
23+ // Extract types that have been marked with framework [ValidatableType].
24+ var frameworkValidatableTypes = context . SyntaxProvider . ForAttributeWithMetadataName (
4225 "Microsoft.Extensions.Validation.ValidatableTypeAttribute" ,
4326 predicate : ShouldTransformSymbolWithAttribute ,
4427 transform : TransformValidatableTypeWithAttribute
4528 ) ;
4629
47- // Extract types that have been marked with the embedded [ValidatableType].
48- var generatedValidatableTypesWithAttribute = context . SyntaxProvider . CreateSyntaxProvider (
49- predicate : ShouldTransformSymbolWithEmbeddedValidatableTypeAttribute ,
50- transform : ( context , cancellation ) => context
51- ) . Combine ( generatorSettings )
52- . Select ( ( combined , cancellation ) =>
53- {
54- var ( syntaxContext , settings ) = combined ;
55- if ( ! settings . ShouldGenerateAttribute || string . IsNullOrEmpty ( settings . RootNamespace ) )
56- {
57- return [ ] ;
58- }
59-
60- return TransformValidatableTypeWithEmbeddedValidatableTypeAttribute ( syntaxContext , settings , cancellation ) ;
61- } )
62- . Where ( t => t . Length > 0 ) ;
30+ // Extract types that have been marked with generated [ValidatableType].
31+ var generatedValidatableTypes = context . SyntaxProvider . ForAttributeWithMetadataName (
32+ "Microsoft.Extensions.Validation.Generated.ValidatableTypeAttribute" ,
33+ predicate : ShouldTransformSymbolWithAttribute ,
34+ transform : TransformValidatableTypeWithAttribute
35+ ) ;
6336
64- var allValidatableTypes = generatedValidatableTypesWithAttribute . Collect ( )
65- . Combine ( validatableTypesWithAttribute . Collect ( ) )
66- . SelectMany ( ( pair , cancellation ) => pair . Left . Concat ( pair . Right ) . ToImmutableArray ( ) ) ;
37+ // Combine both sources of validatable types
38+ var validatableTypesWithAttribute = frameworkValidatableTypes
39+ . Collect ( )
40+ . Combine ( generatedValidatableTypes . Collect ( ) )
41+ . SelectMany ( ( pair , _ ) => pair . Left . Concat ( pair . Right ) . ToImmutableArray ( ) ) ;
6742
6843 // Extract all minimal API endpoints in the application.
6944 var endpoints = context . SyntaxProvider
@@ -77,7 +52,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
7752 . Select ( ExtractValidatableEndpoint ) ;
7853
7954 // Join all validatable types encountered in the type graph.
80- var validatableTypes = allValidatableTypes
55+ var validatableTypes = validatableTypesWithAttribute
8156 . Concat ( validatableTypesFromEndpoints )
8257 . Distinct ( ValidatableTypeComparer . Instance )
8358 . Collect ( ) ;
@@ -89,43 +64,4 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
8964 // ValidatableTypeInfo for all validatable types.
9065 context . RegisterSourceOutput ( emitInputs , Emit ) ;
9166 }
92-
93- private static void EmitValidatableTypeAttribute ( SourceProductionContext context , GeneratorSettings settings )
94- {
95- // Only emit if the build property is set to true and root namespace is provided
96- if ( ! settings . ShouldGenerateAttribute )
97- {
98- return ;
99- }
100-
101- // First, emit the EmbeddedAttribute if it doesn't exist
102- var embeddedAttributeSource = """
103- // <auto-generated/>
104- namespace Microsoft.CodeAnalysis
105- {
106- [global::System.AttributeUsage(global::System.AttributeTargets.All, AllowMultiple = true, Inherited = false)]
107- internal sealed class EmbeddedAttribute : global::System.Attribute
108- {
109- }
110- }
111- """ ;
112-
113- context . AddSource ( "EmbeddedAttribute.g.cs" , embeddedAttributeSource ) ;
114-
115- // Generate the ValidatableTypeAttribute in the project's root namespace
116- var validatableTypeAttributeSource = $$ """
117- // <auto-generated/>
118- namespace {{ settings . RootNamespace }} ;
119-
120- [global::Microsoft.CodeAnalysis.EmbeddedAttribute]
121- [global::System.AttributeUsage(global::System.AttributeTargets.Class)]
122- internal sealed class ValidatableTypeAttribute : global::System.Attribute
123- {
124- }
125- """ ;
126-
127- context . AddSource ( "ValidatableTypeAttribute.g.cs" , validatableTypeAttributeSource ) ;
128- }
129-
130- internal readonly record struct GeneratorSettings ( string ? RootNamespace , bool ShouldGenerateAttribute ) ;
13167}
0 commit comments