using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using SharpGen.Logging;
using SharpGen.Model;
using SharpGen.Transform;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace SharpGen.Generator
{
public sealed class RoslynGenerator
{
private const string AutoGeneratedCommentText = "// \n";
public void Run(CsAssembly csAssembly, string generatedCodeFolder, Ioc ioc)
{
if (string.IsNullOrEmpty(generatedCodeFolder))
throw new ArgumentException("Value cannot be null or empty.", nameof(generatedCodeFolder));
var logger = ioc.Logger;
var generators = ioc.Generators;
var directoryToCreate = new HashSet(StringComparer.CurrentCulture);
// Remove the generated directory before creating it
if (!directoryToCreate.Contains(generatedCodeFolder))
{
directoryToCreate.Add(generatedCodeFolder);
if (Directory.Exists(generatedCodeFolder))
{
foreach (var oldGeneratedFile in Directory.EnumerateFiles(generatedCodeFolder, "*.cs", SearchOption.AllDirectories))
{
try
{
File.Delete(oldGeneratedFile);
}
catch
{
// ignored
}
}
}
}
if (!Directory.Exists(generatedCodeFolder))
Directory.CreateDirectory(generatedCodeFolder);
logger.Message("Process Assembly => {0}", generatedCodeFolder);
var trees = new[]
{
CreateTree("Enumerations", ns => ns.Enums, generators.Enum),
CreateTree("Structures", ns => ns.Structs, generators.Struct),
CreateTree("Functions", ns => ns.Classes, generators.Group),
CreateTree("Interfaces", ns => ns.Interfaces, generators.Interface)
};
SyntaxTree CreateTree(string fileName, Func> membersFunc,
IMultiCodeGenerator generator) where T : CsBase =>
CSharpSyntaxTree.Create(
GenerateCompilationUnit(
csAssembly.Namespaces.Select(
ns => GenerateNamespaceDeclaration(ns, membersFunc(ns), generator)
)
),
path: Path.Combine(generatedCodeFolder, $"{fileName}.cs")
);
foreach (var tree in trees)
File.WriteAllText(tree.FilePath, tree.GetCompilationUnitRoot().ToFullString());
}
private static CompilationUnitSyntax GenerateCompilationUnit(
IEnumerable namespaceDeclarations
) => CompilationUnit(
default,
default,
default,
List(
namespaceDeclarations
)
).NormalizeWhitespace(elasticTrivia: true);
private static NamespaceDeclarationSyntax GenerateNamespaceDeclaration(
CsBase csNamespace, IEnumerable elements, IMultiCodeGenerator generator
) where T : CsBase => NamespaceDeclaration(
ParseName(csNamespace.Name),
default,
default,
List(elements.OrderBy(element => element.Name).SelectMany(generator.GenerateCode))
).WithLeadingTrivia(Comment(AutoGeneratedCommentText));
}
}