Skip to content

Commit

Permalink
moved out code generation logic into the shared project
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexNav73 committed Feb 25, 2024
1 parent 6793025 commit dec144e
Show file tree
Hide file tree
Showing 22 changed files with 224 additions and 152 deletions.
8 changes: 4 additions & 4 deletions build/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,28 +133,28 @@ internal partial class Build : NukeBuild
DotNetPack(s => s
.SetProject(Solution.CoreCraft)
.Apply(PackSettingsBase)
.SetVersion(MakePreviewIfNeeded("0.6.0", "0.6.5"))
.SetVersion(MakePreviewIfNeeded("0.6.0", "0.6.6"))
.SetDescription("A core library to build cross-platform and highly customizable domain models")
.AddPackageTags("Model", "Domain"));
DotNetPack(s => s
.SetProject(Solution.CoreCraft_Generators)
.Apply(PackSettingsBase)
.SetVersion(MakePreviewIfNeeded("0.6.0", "0.6.5"))
.SetVersion(MakePreviewIfNeeded("0.6.0", "0.6.6"))
.SetDescription("Roslyn Source Generators for generating domain models using 'CoreCraft' library")
.AddPackageTags("Model", "Domain", "SourceGenerator", "Generator"));
DotNetPack(s => s
.SetProject(Solution.CoreCraft_Storage_Sqlite)
.Apply(PackSettingsBase)
.SetVersion(MakePreviewIfNeeded("0.6.0", "0.6.5"))
.SetVersion(MakePreviewIfNeeded("0.6.0", "0.6.6"))
.SetDescription("SQLite storage implementation for 'CoreCraft' library")
.AddPackageTags("Model", "Domain", "SQLite"));
DotNetPack(s => s
.SetProject(Solution.CoreCraft_Storage_Json)
.Apply(PackSettingsBase)
.SetVersion(MakePreviewIfNeeded("0.3.0", "0.3.5"))
.SetVersion(MakePreviewIfNeeded("0.3.0", "0.3.6"))
.SetDescription("Json storage implementation for 'CoreCraft' library")
.AddPackageTags("Model", "Domain", "Json"));
Expand Down
68 changes: 10 additions & 58 deletions src/CoreCraft.Generators/ApplicationModelGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using System.Collections.Immutable;
using CoreCraft.Generators.Serialization;
using CoreCraft.SourceGeneration;
using CoreCraft.SourceGeneration.Generators;
using CoreCraft.SourceGeneration.Serialization;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;

namespace CoreCraft.Generators;

[Generator(LanguageNames.CSharp)]
internal partial class ApplicationModelGenerator : GeneratorBase
internal sealed class ApplicationModelGenerator : GeneratorBase
{
protected override void ExecuteInternal(
SourceProductionContext context,
Expand All @@ -16,68 +18,18 @@ protected override void ExecuteInternal(
var options = new JsonSerializerSettings();
var serializer = JsonSerializer.Create(options);

foreach (var file in files)
foreach (var (name, content) in files)
{
ModelScheme modelScheme = null;

using (var stringStream = new StringReader(file.content))
using (var reader = new JsonTextReader(stringStream))
{
modelScheme = DtoConverter.Convert(serializer.Deserialize<ModelSchemeDto>(reader));
}
ModelScheme modelScheme = ModelSchemeReader.Read(serializer, content);

if (modelScheme == null)
{
throw new InvalidOperationException($"Failed to deserialize model file [{file.name}]");
throw new InvalidOperationException($"Failed to deserialize model file [{name}]");
}

var code = ModelGenerator.Generate(assemblyName, name, modelScheme);

using (var writer = new StringWriter())
using (var code = new IndentedTextWriter(writer, " "))
{
code.Preamble();
Generate(assemblyName, file.name, code, modelScheme);

AddSourceFile(context, file.name, writer.ToString());
}
AddSourceFile(context, name, code);
}
}

private void Generate(string assemblyName, string modelName, IndentedTextWriter code, ModelScheme modelScheme)
{
var @namespace = $"{assemblyName}.{modelName}";

code.WriteLine($"namespace {@namespace}");
code.Block(() =>
{
code.WriteLine("using CoreCraft.Core;");
code.WriteLine("using CoreCraft.ChangesTracking;");
code.WriteLine("using CoreCraft.Persistence;");
code.WriteLine($"using {@namespace}.Entities;");
code.EmptyLine();
GenerateModelShards(code, modelScheme.Shards);
});
code.EmptyLine();

code.WriteLine($"namespace {@namespace}.Entities");
code.Block(() =>
{
GenerateEntities(code, modelScheme.Shards);
});
}

private static string DefineProperty(string type, string name, string accessors = "get; private set;")
{
return string.Join(" ", type, name, "{", accessors, "}").Trim();
}

private static string ToCamelCase(string value)
{
if (value.Length > 1)
{
return $"{char.ToLower(value[0])}{value.Substring(1)}";
}

return value;
}
}
4 changes: 0 additions & 4 deletions src/CoreCraft.Generators/CoreCraft.Generators.AssemblyInfo.cs

This file was deleted.

7 changes: 7 additions & 0 deletions src/CoreCraft.Generators/CoreCraft.Generators.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,11 @@
<None Include="$(PkgNewtonsoft_Json)\lib\netstandard2.0\*.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>

<Import Project="..\CoreCraft.SourceGeneration\CoreCraft.SourceGeneration.projitems" Label="Shared" />

<ItemGroup>
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
<InternalsVisibleTo Include="CoreCraft.Generators.Tests" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects Condition="'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' &lt; '16.0'">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>b11d3e00-59b5-4227-ab86-2f20e5fa330b</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>CoreCraft.SourceGeneration</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Extensions\IndentedTextWriterExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Generators\EntitiesGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Generators\GeneratorCommon.cs" />
<Compile Include="$(MSBuildThisFileDirectory)generators\ModelGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Generators\ModelShardGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ModelScheme.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Serialization\DtoConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)serialization\ModelSchemeReader.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Serialization\ModelSchemeDto.cs" />
</ItemGroup>
</Project>
13 changes: 13 additions & 0 deletions src/CoreCraft.SourceGeneration/CoreCraft.SourceGeneration.shproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>b11d3e00-59b5-4227-ab86-2f20e5fa330b</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="CoreCraft.SourceGeneration.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace CoreCraft.Generators;
namespace CoreCraft.SourceGeneration.Extensions;

internal static class IndentedTextWriterExtensions
{
Expand Down Expand Up @@ -111,7 +111,7 @@ public static void GeneratedInterfaceAttributes(this IndentedTextWriter code)

public static void GeneratedCodeAttribute(this IndentedTextWriter code)
{
code.WriteLine($"[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"C# Source Generator\", \"{typeof(GeneratorBase).Assembly.GetName().Version}\")]");
code.WriteLine($"[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"C# Source Generator\", \"{typeof(IndentedTextWriterExtensions).Assembly.GetName().Version}\")]");
}

public static void CompilerGeneratedCodeAttribute(this IndentedTextWriter code)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
namespace CoreCraft.Generators;
using CoreCraft.SourceGeneration.Extensions;

internal partial class ApplicationModelGenerator
namespace CoreCraft.SourceGeneration.Generators;

internal sealed class EntitiesGenerator(IndentedTextWriter code) : GeneratorCommon
{
public void GenerateEntities(IndentedTextWriter code, IEnumerable<ModelShard> shards)
public void Generate(IEnumerable<ModelShard> shards)
{
code.WriteLine("using CoreCraft.Core;");
code.EmptyLine();

foreach (var modelShard in shards)
{
DefineEntities(code, modelShard);
DefineEntities(modelShard);
code.EmptyLine();
}
}

private void DefineEntities(IndentedTextWriter code, ModelShard modelShard)
private void DefineEntities(ModelShard modelShard)
{
foreach (var entity in modelShard.Collections.Select(x => x.Entity))
{
DefineEntityType(code, entity);
DefineEntityType(entity);
code.EmptyLine();
DefineEntityPropertiesClass(code, entity);
DefineEntityPropertiesClass(entity);
code.EmptyLine();
}
}

private void DefineEntityType(IndentedTextWriter code, Entity entity)
private void DefineEntityType(Entity entity)
{
code.GeneratedClassAttributes();
code.WriteLine($"public sealed record {entity.Name}(global::System.Guid Id) : Entity(Id)");
Expand All @@ -38,13 +40,13 @@ private void DefineEntityType(IndentedTextWriter code, Entity entity)
});
}

private void DefineEntityPropertiesClass(IndentedTextWriter code, Entity entity)
private void DefineEntityPropertiesClass(Entity entity)
{
code.GeneratedClassAttributes();
code.WriteLine($"public sealed partial record {entity.PropertiesType} : Properties");
code.Block(() =>
{
DefineCtor(code, entity);
DefineCtor(entity);
code.EmptyLine();
foreach (var prop in entity.Properties)
Expand All @@ -53,11 +55,11 @@ private void DefineEntityPropertiesClass(IndentedTextWriter code, Entity entity)
}
code.EmptyLine();
ImplementEntityPropertiesMethods(code, entity);
ImplementEntityPropertiesMethods(entity);
code.EmptyLine();
});

void DefineCtor(IndentedTextWriter code, Entity entity)
void DefineCtor(Entity entity)
{
code.WriteLine($"public {entity.PropertiesType}()");
code.Block(() =>
Expand All @@ -69,7 +71,7 @@ void DefineCtor(IndentedTextWriter code, Entity entity)
});
}

void ImplementEntityPropertiesMethods(IndentedTextWriter code, Entity entity)
void ImplementEntityPropertiesMethods(Entity entity)
{
code.NoIndent(c => c.WriteLine("#if NET5_0_OR_GREATER"));
code.WriteLine($"public override {entity.PropertiesType} ReadFrom(IPropertiesBag bag)");
Expand Down
19 changes: 19 additions & 0 deletions src/CoreCraft.SourceGeneration/Generators/GeneratorCommon.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace CoreCraft.SourceGeneration.Generators;

internal abstract class GeneratorCommon
{
protected static string DefineProperty(string type, string name, string accessors = "get; private set;")
{
return string.Join(" ", type, name, "{", accessors, "}").Trim();
}

protected static string ToCamelCase(string value)
{
if (value.Length > 1)
{
return $"{char.ToLower(value[0])}{value.Substring(1)}";
}

return value;
}
}
36 changes: 36 additions & 0 deletions src/CoreCraft.SourceGeneration/Generators/ModelGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using CoreCraft.SourceGeneration.Extensions;

namespace CoreCraft.SourceGeneration.Generators;

internal static class ModelGenerator
{
public static string Generate(string assemblyName, string modelName, ModelScheme modelScheme)
{
var @namespace = $"{assemblyName}.{modelName}";
using var writer = new StringWriter();
using var code = new IndentedTextWriter(writer, " ");

code.Preamble();

code.WriteLine($"namespace {@namespace}");
code.Block(() =>
{
code.WriteLine("using CoreCraft.Core;");
code.WriteLine("using CoreCraft.ChangesTracking;");
code.WriteLine("using CoreCraft.Persistence;");
code.WriteLine($"using {@namespace}.Entities;");
code.EmptyLine();
new ModelShardGenerator(code).Generate(modelScheme.Shards);
});
code.EmptyLine();

code.WriteLine($"namespace {@namespace}.Entities");
code.Block(() =>
{
new EntitiesGenerator(code).Generate(modelScheme.Shards);
});

return writer.ToString();
}
}
Loading

0 comments on commit dec144e

Please sign in to comment.