| File: ToolBlockGenerator.cs | Web Access |
| Project: src\aspnetcore\src\Components\AI\gen\Microsoft.AspNetCore.Components.AI.SourceGenerators.csproj (Microsoft.AspNetCore.Components.AI.SourceGenerators) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Microsoft.AspNetCore.Components.AI.SourceGenerators; [Generator] public class ToolBlockGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) { // Step 1: Parse classes with [ToolBlock] into an equatable parse result // (candidate and/or diagnostics). var parseResults = context.SyntaxProvider .ForAttributeWithMetadataName( "Microsoft.AspNetCore.Components.AI.ToolBlockAttribute", predicate: static (node, _) => node is ClassDeclarationSyntax, transform: static (ctx, ct) => ToolBlockParser.Parse(ctx, ct)); // Step 2: Report per-declaration diagnostics and emit a handler for each valid candidate. context.RegisterSourceOutput(parseResults, static (spc, result) => { foreach (var info in result.Diagnostics) { spc.ReportDiagnostic(Diagnostic.Create( DiagnosticDescriptors.ById(info.DescriptorId), info.Location?.ToLocation() ?? Location.None, info.MessageArg)); } if (result.Candidate is not null) { ToolBlockEmitter.EmitHandler(spc, result.Candidate); } }); // Step 3: Collect all valid candidates and emit the aggregate registration. var candidates = parseResults .Where(static r => r.Candidate is not null) .Select(static (r, _) => r.Candidate!) .Collect(); context.RegisterSourceOutput(candidates, static (spc, candidates) => { ToolBlockEmitter.EmitRegistration(spc, candidates); }); } }