using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using MapTo.Extensions;
using MapTo.Sources;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace MapTo
{
///
/// MapTo source generator.
///
[Generator]
public class MapToGenerator : ISourceGenerator
{
///
public void Initialize(GeneratorInitializationContext context)
{
context.RegisterForSyntaxNotifications(() => new MapToSyntaxReceiver());
}
///
public void Execute(GeneratorExecutionContext context)
{
try
{
var options = SourceGenerationOptions.From(context);
var compilation = context.Compilation
.AddSource(ref context, UseUpdateAttributeSource.Generate(options))
.AddSource(ref context, AddDataAttributeSource.Generate(options))
.AddSource(ref context, JsonExtensionAttributeSource.Generate(options))
.AddSource(ref context, MapFromAttributeSource.Generate(options))
.AddSource(ref context, IgnoreMemberAttributeSource.Generate(options))
.AddSource(ref context, ITypeConverterSource.Generate(options))
.AddSource(ref context, MapTypeConverterAttributeSource.Generate(options))
.AddSource(ref context, MapPropertyAttributeSource.Generate(options))
.AddSource(ref context, MappingContextSource.Generate(options));
if (context.SyntaxReceiver is MapToSyntaxReceiver receiver && receiver.CandidateTypes.Any())
{
AddGeneratedMappingsClasses(context, compilation, receiver.CandidateTypes, options);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
private static void AddGeneratedMappingsClasses(GeneratorExecutionContext context, Compilation compilation, IEnumerable candidateTypes, SourceGenerationOptions options)
{
foreach (var typeDeclarationSyntax in candidateTypes)
{
var mappingContext = MappingContext.Create(compilation, options, typeDeclarationSyntax);
mappingContext.Diagnostics.ForEach(context.ReportDiagnostic);
if (mappingContext.Model is null)
{
continue;
}
var (source, hintName) = typeDeclarationSyntax switch
{
StructDeclarationSyntax => MapStructSource.Generate(mappingContext.Model),
ClassDeclarationSyntax => MapClassSource.Generate(mappingContext.Model),
RecordDeclarationSyntax => MapRecordSource.Generate(mappingContext.Model),
_ => throw new ArgumentOutOfRangeException()
};
context.AddSource(hintName, source);
}
}
}
}