Created
January 29, 2021 18:48
-
-
Save ihorbond/38b0e9537ffd65b7542db7a31348aa41 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Reflection; | |
using System.Text; | |
using Microsoft.CodeAnalysis; | |
using Microsoft.CodeAnalysis.CSharp; | |
using Microsoft.CodeAnalysis.CSharp.Syntax; | |
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; | |
namespace iProQDesignerAPI.CodeGeneration | |
{ | |
/// <summary> | |
/// Generates 4 files: I{Entity}ServiceCore, {Entity}ServiceCore, I{Entity}Repository, {Entity}Repository | |
/// TODO: | |
/// 1. register created services and repos with DI | |
/// 2. add new line characters between fields and constructor | |
/// 3. ability to generate code from db entity directly | |
/// 4. optional controller generation | |
/// </summary> | |
public static class Program | |
{ | |
private static string CurrentProject { get => Assembly.GetCallingAssembly().GetName().Name; } | |
public static void Main(string[] args) | |
{ | |
string entityName = args.Length > 0 ? args[0] : "YourEntityName"; | |
const string comment = @" | |
/// <summary> | |
/// This code was autogenerated by iProQDesingerAPI.CodeGeneration project | |
/// </summary> | |
"; | |
var dict = new Dictionary<string, CompilationUnitSyntax> | |
{ | |
{ | |
Path.GetRelativePath(CurrentProject, $@"iProQDesigner.Core\Interfaces\Services\I{entityName}ServiceCore.cs"), | |
CreateCoreServiceInterface(entityName, namespaceName: "iProQDesigner.Core.Interfaces.Services", comment) | |
}, | |
{ | |
Path.GetRelativePath(CurrentProject, $@"iProQDesigner.Core\Services\{entityName}ServiceCore.cs"), | |
CreateCoreService(entityName, namespaceName: "iProQDesigner.Core.Services", comment) | |
}, | |
{ | |
Path.GetRelativePath(CurrentProject, $@"iProQDesigner.Core\Interfaces\Repositories\I{entityName}Repository.cs"), | |
CreateRepoInterface(entityName, namespaceName: "iProQDesigner.Core.Interfaces.Repositories", comment) | |
}, | |
{ | |
Path.GetRelativePath(CurrentProject, $@"iProQDesigner.Infrastructure\Data\Repositories\{entityName}Repository.cs"), | |
CreateRepoImplementation(entityName, namespaceName: "iProQDesigner.Infrastructure.Data.Repositories", comment) | |
}, | |
}; | |
var sb = new StringBuilder(); | |
// go thru dictionary keys and write files | |
dict.Keys.ToList().ForEach(path => | |
{ | |
var code = dict[path]; | |
//var namespaceMember = code.Members.FirstOrDefault(m => m.IsKind(SyntaxKind.NamespaceDeclaration)); | |
sb.AppendLine(code.ToFullString()); | |
using var writer = new StreamWriter(File.Create(path)); | |
code.WriteTo(writer); | |
}); | |
Console.Write(sb.ToString()); | |
Console.Read(); | |
} | |
static CompilationUnitSyntax CreateCoreServiceInterface(string entityName, string namespaceName, string comment) | |
{ | |
var @using = new[] | |
{ | |
UsingDirective(ParseName("iProQDesigner.Core.Models")), | |
UsingDirective(ParseName("System.Threading.Tasks")) | |
}; | |
var interfaceDeclaraton = InterfaceDeclaration($"I{entityName}ServiceCore") | |
.AddModifiers(Token(SyntaxKind.PublicKeyword)); | |
var @namespace = NamespaceDeclaration(IdentifierName(namespaceName)) | |
.AddMembers(interfaceDeclaraton) | |
.WithLeadingTrivia(ParseLeadingTrivia(comment)); | |
var compilationUnit = CompilationUnit() | |
.AddUsings(@using) | |
.AddMembers(@namespace) | |
.NormalizeWhitespace(); | |
return compilationUnit; | |
} | |
static CompilationUnitSyntax CreateCoreService(string entityName, string namespaceName, string comment) | |
{ | |
var @using = new[] | |
{ | |
UsingDirective(ParseName("System")), | |
UsingDirective(ParseName("iProQDesigner.Core.Guards")), | |
UsingDirective(ParseName("iProQDesigner.Core.Models")), | |
UsingDirective(ParseName("iProQDesigner.Core.Interfaces.Repositories")), | |
UsingDirective(ParseName("iProQDesigner.Core.Interfaces.Services")) | |
}; | |
string repoName = Char.ToLowerInvariant(entityName[0]) + entityName[1..]; | |
var fieldDeclaration = FieldDeclaration(VariableDeclaration(ParseTypeName($"I{entityName}Repository")) | |
.AddVariables(VariableDeclarator($"_{repoName}Repository"))) | |
.AddModifiers( | |
Token(SyntaxKind.PrivateKeyword), | |
Token(SyntaxKind.ReadOnlyKeyword)); | |
var constructorDeclaration = ConstructorDeclaration($"{entityName}ServiceCore") | |
.AddModifiers(Token(SyntaxKind.PublicKeyword)) | |
.AddParameterListParameters( | |
Parameter(Identifier($"{repoName}Repository")).WithType(ParseTypeName($"I{entityName}Repository"))) | |
.WithBody(Block( | |
SingletonList<StatementSyntax>( | |
ExpressionStatement( | |
AssignmentExpression( | |
SyntaxKind.SimpleAssignmentExpression, | |
IdentifierName($"_{repoName}Repository"), | |
IdentifierName($"{repoName}Repository")))))); | |
var classDeclaration = ClassDeclaration($"{entityName}ServiceCore") | |
.AddModifiers(Token(SyntaxKind.PublicKeyword)) | |
.AddBaseListTypes(SimpleBaseType(IdentifierName($"I{entityName}ServiceCore"))) | |
.AddMembers(fieldDeclaration, constructorDeclaration); | |
var @namespace = NamespaceDeclaration(IdentifierName(namespaceName)) | |
.AddMembers(classDeclaration) | |
.WithLeadingTrivia(ParseLeadingTrivia(comment)); | |
var compilationUnit = CompilationUnit() | |
.AddUsings(@using) | |
.AddMembers(@namespace) | |
.NormalizeWhitespace(); | |
return compilationUnit; | |
} | |
static CompilationUnitSyntax CreateRepoInterface(string entityName, string namespaceName, string comment) | |
{ | |
var @using = new[] | |
{ | |
UsingDirective(ParseName("iProQDesigner.Core.Models")), | |
UsingDirective(ParseName("System.Threading.Tasks")) | |
}; | |
var interfaceDeclaraton = InterfaceDeclaration($"I{entityName}Repository") | |
.AddModifiers(Token(SyntaxKind.PublicKeyword)) | |
.AddBaseListTypes(SimpleBaseType(IdentifierName($"IGenericRepository<{entityName}>"))); | |
var @namespace = NamespaceDeclaration(IdentifierName(namespaceName)) | |
.AddMembers(interfaceDeclaraton) | |
.WithLeadingTrivia(ParseLeadingTrivia(comment)); | |
var compilationUnit = CompilationUnit() | |
.AddUsings(@using) | |
.AddMembers(@namespace) | |
.NormalizeWhitespace(); | |
return compilationUnit; | |
} | |
static CompilationUnitSyntax CreateRepoImplementation(string entityName, string namespaceName, string comment) | |
{ | |
var fieldsDeclaration = FieldDeclaration(VariableDeclaration(PredefinedType(Token(SyntaxKind.StringKeyword))) | |
.AddVariables( | |
VariableDeclarator(Identifier("_tableName"), null, EqualsValueClause(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal($"{entityName}")))), | |
VariableDeclarator(Identifier("_pkName"), null, EqualsValueClause(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal($"{entityName}Id")))))) | |
.AddModifiers( | |
Token(SyntaxKind.PrivateKeyword), | |
Token(SyntaxKind.ConstKeyword)); | |
var constructorDeclaration = ConstructorDeclaration($"{entityName}Repository") | |
.AddModifiers(Token(SyntaxKind.PublicKeyword)) | |
.WithInitializer( | |
ConstructorInitializer(SyntaxKind.BaseConstructorInitializer) | |
.AddArgumentListArguments( | |
Argument(IdentifierName("_tableName")), | |
Argument(IdentifierName("_pkName")))) | |
.WithBody(Block()); | |
var classDeclaration = ClassDeclaration($"{entityName}Repository") | |
.AddModifiers(Token(SyntaxKind.PublicKeyword)) | |
.AddBaseListTypes( | |
SimpleBaseType(IdentifierName($"GenericRepository<{entityName}>")), | |
SimpleBaseType(IdentifierName(Identifier($"I{entityName}Repository")))) | |
.AddMembers(fieldsDeclaration, constructorDeclaration); | |
var @using = new[] | |
{ | |
UsingDirective(ParseName("iProQDesigner.Core.Models")), | |
UsingDirective(ParseName("iProQDesigner.Core.Interfaces.Repositories")), | |
UsingDirective(ParseName("System")), | |
UsingDirective(ParseName("System.Data")), | |
UsingDirective(ParseName("System.Threading.Tasks")), | |
UsingDirective(ParseName("Dapper")) | |
}; | |
var @namespace = NamespaceDeclaration(IdentifierName(namespaceName)) | |
.AddMembers(classDeclaration) | |
.WithLeadingTrivia(ParseLeadingTrivia(comment)); | |
var compilationUnit = CompilationUnit() | |
.AddUsings(@using) | |
.AddMembers(@namespace) | |
.NormalizeWhitespace(); | |
return compilationUnit; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment