LANCommander/LANCommander.SDK.SourceGenerators/CmdletRegistrationGenerator.cs

90 lines
3 KiB
C#

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<CmdletInfo> cmdlets)
{
if (cmdlets.IsDefaultOrEmpty)
return;
var sorted = cmdlets.OrderBy(c => c.CmdletName).ToList();
var sb = new StringBuilder();
sb.AppendLine("// <auto-generated/>");
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;
}
}