89 lines
3.0 KiB
C#
89 lines
3.0 KiB
C#
using System;
|
|
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
using Microsoft.CodeAnalysis.Text;
|
|
|
|
namespace Nebula.SourceGenerators;
|
|
|
|
|
|
[Generator]
|
|
public class ViewConstructorGenerator : IIncrementalGenerator
|
|
{
|
|
private static readonly string ViewModelAttribute = "Nebula.Shared.ViewHelper.ViewModelRegisterAttribute";
|
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
|
{
|
|
var provider = context.SyntaxProvider
|
|
.CreateSyntaxProvider(
|
|
(s, _) => s is ClassDeclarationSyntax,
|
|
(ctx, _) => SourceHelper.GetClassDeclarationForSourceGen(ctx,ViewModelAttribute))
|
|
.Where(t => t.reportAttributeFound)
|
|
.Select((t, _) => t.Item1);
|
|
|
|
context.RegisterSourceOutput(context.CompilationProvider.Combine(provider.Collect()),
|
|
(ctx, t) => GenerateCode(ctx, t.Left, t.Right));
|
|
}
|
|
|
|
private void GenerateCode(SourceProductionContext context, Compilation compilation,
|
|
ImmutableArray<ClassDeclarationSyntax> classDeclarations)
|
|
{
|
|
foreach (var classDeclarationSyntax in classDeclarations)
|
|
{
|
|
var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);
|
|
if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol)
|
|
continue;
|
|
|
|
var viewModelName = classSymbol.Name;
|
|
var viewModelNamespace = classSymbol.ContainingNamespace.ToDisplayString();
|
|
|
|
var viewModelRegisterAttr = classSymbol.GetAttributes()
|
|
.FirstOrDefault(attr => attr.AttributeClass?.ToDisplayString() == ViewModelAttribute);
|
|
|
|
var viewTypeArg = viewModelRegisterAttr?.ConstructorArguments.FirstOrDefault();
|
|
if (viewTypeArg?.Value is not INamedTypeSymbol viewTypeSymbol)
|
|
continue;
|
|
|
|
try
|
|
{
|
|
var viewName = viewTypeSymbol.Name;
|
|
var viewNamespace = viewTypeSymbol.ContainingNamespace.ToDisplayString();
|
|
|
|
var code = $@"
|
|
namespace {viewNamespace}
|
|
{{
|
|
public partial class {viewName}
|
|
{{
|
|
public {viewName}({viewModelNamespace}.{viewModelName} viewModel)
|
|
: this()
|
|
{{
|
|
DataContext = viewModel;
|
|
}}
|
|
}}
|
|
}}";
|
|
|
|
// Add the source code to the compilation.
|
|
context.AddSource($"{viewName}_viewConstructAuto.g.cs", SourceText.From(code, Encoding.UTF8));
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
var coder1 = $@"
|
|
// <auto-generated/>
|
|
// Error!
|
|
namespace {viewModelNamespace}
|
|
{{
|
|
public partial class {viewModelName}
|
|
{{
|
|
// {e.Message}
|
|
}}
|
|
}}";
|
|
|
|
// Add the source code to the compilation.
|
|
context.AddSource($"{viewModelName}_viewError.g.cs", SourceText.From(coder1, Encoding.UTF8));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
} |