using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace LANCommander.SDK.SourceGenerators; [Generator] public class CmdletRegistrationGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) { var cmdletClasses = context.SyntaxProvider .ForAttributeWithMetadataName( "System.Management.Automation.CmdletAttribute", predicate: static (node, _) => node is ClassDeclarationSyntax, transform: static (ctx, _) => GetCmdletInfo(ctx)) .Where(static info => info is not null) .Select(static (info, _) => info!.Value); context.RegisterSourceOutput( cmdletClasses.Collect(), static (spc, cmdlets) => Execute(spc, cmdlets)); } private static CmdletInfo? GetCmdletInfo(GeneratorAttributeSyntaxContext context) { var typeSymbol = (INamedTypeSymbol)context.TargetSymbol; foreach (var attr in typeSymbol.GetAttributes()) { if (attr.AttributeClass?.ToDisplayString() != "System.Management.Automation.CmdletAttribute") continue; if (attr.ConstructorArguments.Length < 2) continue; var verb = attr.ConstructorArguments[0].Value?.ToString(); var noun = attr.ConstructorArguments[1].Value?.ToString(); if (verb is null || noun is null) continue; return new CmdletInfo { CmdletName = $"{verb}-{noun}", FullTypeName = typeSymbol.ToDisplayString() }; } return null; } private static void Execute(SourceProductionContext context, ImmutableArray cmdlets) { if (cmdlets.IsDefaultOrEmpty) return; var sorted = cmdlets.OrderBy(c => c.CmdletName).ToList(); var sb = new StringBuilder(); sb.AppendLine("// "); sb.AppendLine("using System.Management.Automation.Runspaces;"); sb.AppendLine(); sb.AppendLine("namespace LANCommander.SDK.PowerShell.Extensions;"); sb.AppendLine(); sb.AppendLine("public static class InitialSessionStateExtensions"); sb.AppendLine("{"); sb.AppendLine(" public static void AddCustomCmdlets(this InitialSessionState initialSessionState)"); sb.AppendLine(" {"); foreach (var cmdlet in sorted) { sb.AppendLine($" initialSessionState.Commands.Add(new SessionStateCmdletEntry(\"{cmdlet.CmdletName}\", typeof({cmdlet.FullTypeName}), null));"); } sb.AppendLine(" }"); sb.AppendLine("}"); context.AddSource("InitialSessionStateExtensions.g.cs", sb.ToString()); } private struct CmdletInfo { public string CmdletName; public string FullTypeName; } }