@@ -49,6 +49,13 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
4949 transform : static ( ctx , _ ) => GetDurableTaskTypeInfo ( ctx ) )
5050 . Where ( static info => info != null ) ! ;
5151
52+ // Create providers for DurableEvent attributes
53+ IncrementalValuesProvider < DurableEventTypeInfo > durableEventAttributes = context . SyntaxProvider
54+ . CreateSyntaxProvider (
55+ predicate : static ( node , _ ) => node is AttributeSyntax ,
56+ transform : static ( ctx , _ ) => GetDurableEventTypeInfo ( ctx ) )
57+ . Where ( static info => info != null ) ! ;
58+
5259 // Create providers for Durable Functions
5360 IncrementalValuesProvider < DurableFunction > durableFunctions = context . SyntaxProvider
5461 . CreateSyntaxProvider (
@@ -65,15 +72,23 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
6572 } ) ;
6673
6774 // Collect all results and check if Durable Functions is referenced
68- IncrementalValueProvider < ( Compilation , ImmutableArray < DurableTaskTypeInfo > , ImmutableArray < DurableFunction > , string ? ) > compilationAndTasks =
75+ IncrementalValueProvider < ( Compilation , ImmutableArray < DurableTaskTypeInfo > , ImmutableArray < DurableEventTypeInfo > , ImmutableArray < DurableFunction > , string ? ) > compilationAndTasks =
6976 durableTaskAttributes . Collect ( )
77+ . Combine ( durableEventAttributes . Collect ( ) )
7078 . Combine ( durableFunctions . Collect ( ) )
7179 . Combine ( context . CompilationProvider )
7280 . Combine ( projectTypeProvider )
73- . Select ( ( x , _ ) => ( x . Left . Right , x . Left . Left . Left , x . Left . Left . Right , x . Right ) ) ;
81+ // Roslyn's IncrementalValueProvider.Combine creates nested tuple pairs: ((Left, Right), Right)
82+ // After multiple .Combine() calls, we unpack the nested structure:
83+ // x.Right = projectType (string?)
84+ // x.Left.Right = Compilation
85+ // x.Left.Left.Left.Left = DurableTaskAttributes (orchestrators, activities, entities)
86+ // x.Left.Left.Left.Right = DurableEventAttributes (events)
87+ // x.Left.Left.Right = DurableFunctions (Azure Functions metadata)
88+ . Select ( ( x , _ ) => ( x . Left . Right , x . Left . Left . Left . Left , x . Left . Left . Left . Right , x . Left . Left . Right , x . Right ) ) ;
7489
7590 // Generate the source
76- context . RegisterSourceOutput ( compilationAndTasks , static ( spc , source ) => Execute ( spc , source . Item1 , source . Item2 , source . Item3 , source . Item4 ) ) ;
91+ context . RegisterSourceOutput ( compilationAndTasks , static ( spc , source ) => Execute ( spc , source . Item1 , source . Item2 , source . Item3 , source . Item4 , source . Item5 ) ) ;
7792 }
7893
7994 static DurableTaskTypeInfo ? GetDurableTaskTypeInfo ( GeneratorSyntaxContext context )
@@ -170,6 +185,49 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
170185 return new DurableTaskTypeInfo ( className , taskName , inputType , outputType , kind ) ;
171186 }
172187
188+ static DurableEventTypeInfo ? GetDurableEventTypeInfo ( GeneratorSyntaxContext context )
189+ {
190+ AttributeSyntax attribute = ( AttributeSyntax ) context . Node ;
191+
192+ ITypeSymbol ? attributeType = context . SemanticModel . GetTypeInfo ( attribute . Name ) . Type ;
193+ if ( attributeType ? . ToString ( ) != "Microsoft.DurableTask.DurableEventAttribute" )
194+ {
195+ return null ;
196+ }
197+
198+ // DurableEventAttribute can be applied to both class and struct (record)
199+ TypeDeclarationSyntax ? typeDeclaration = attribute . Parent ? . Parent as TypeDeclarationSyntax ;
200+ if ( typeDeclaration == null )
201+ {
202+ return null ;
203+ }
204+
205+ // Verify that the attribute is being used on a non-abstract type
206+ if ( typeDeclaration . Modifiers . Any ( SyntaxKind . AbstractKeyword ) )
207+ {
208+ return null ;
209+ }
210+
211+ if ( context . SemanticModel . GetDeclaredSymbol ( typeDeclaration ) is not ITypeSymbol eventType )
212+ {
213+ return null ;
214+ }
215+
216+ string eventName = eventType . Name ;
217+
218+ if ( attribute . ArgumentList ? . Arguments . Count > 0 )
219+ {
220+ ExpressionSyntax expression = attribute . ArgumentList . Arguments [ 0 ] . Expression ;
221+ Optional < object ? > constantValue = context . SemanticModel . GetConstantValue ( expression ) ;
222+ if ( constantValue . HasValue && constantValue . Value is string value )
223+ {
224+ eventName = value ;
225+ }
226+ }
227+
228+ return new DurableEventTypeInfo ( eventName , eventType ) ;
229+ }
230+
173231 static DurableFunction ? GetDurableFunction ( GeneratorSyntaxContext context )
174232 {
175233 MethodDeclarationSyntax method = ( MethodDeclarationSyntax ) context . Node ;
@@ -186,10 +244,11 @@ static void Execute(
186244 SourceProductionContext context ,
187245 Compilation compilation ,
188246 ImmutableArray < DurableTaskTypeInfo > allTasks ,
247+ ImmutableArray < DurableEventTypeInfo > allEvents ,
189248 ImmutableArray < DurableFunction > allFunctions ,
190249 string ? projectType )
191250 {
192- if ( allTasks . IsDefaultOrEmpty && allFunctions . IsDefaultOrEmpty )
251+ if ( allTasks . IsDefaultOrEmpty && allEvents . IsDefaultOrEmpty && allFunctions . IsDefaultOrEmpty )
193252 {
194253 return ;
195254 }
@@ -565,5 +624,34 @@ static string GetRenderedTypeExpression(ITypeSymbol? symbol)
565624 return expression ;
566625 }
567626 }
627+
628+ class DurableEventTypeInfo
629+ {
630+ public DurableEventTypeInfo ( string eventName , ITypeSymbol eventType )
631+ {
632+ this . TypeName = GetRenderedTypeExpression ( eventType ) ;
633+ this . EventName = eventName ;
634+ }
635+
636+ public string TypeName { get ; }
637+ public string EventName { get ; }
638+
639+ static string GetRenderedTypeExpression ( ITypeSymbol ? symbol )
640+ {
641+ if ( symbol == null )
642+ {
643+ return "object" ;
644+ }
645+
646+ string expression = symbol . ToString ( ) ;
647+ if ( expression . StartsWith ( "System." , StringComparison . Ordinal )
648+ && symbol . ContainingNamespace . Name == "System" )
649+ {
650+ expression = expression . Substring ( "System." . Length ) ;
651+ }
652+
653+ return expression ;
654+ }
655+ }
568656 }
569657}
0 commit comments