-
-
Notifications
You must be signed in to change notification settings - Fork 539
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add C# Source Generator #1726
base: master
Are you sure you want to change the base?
Add C# Source Generator #1726
Conversation
Directory.Packages.props
Outdated
@@ -14,9 +14,12 @@ | |||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" /> | |||
<PackageVersion Include="NodaTime" Version="3.1.9" /> | |||
<PackageVersion Include="NSwag.Core.Yaml" Version="14.0.0-preview011" /> | |||
<PackageVersion Include="Parlot" Version="0.0.25.0" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Source generators do not support transient dependencies: dotnet/sdk#17775
Because of that need to explicitly install some transient packages.
For example, it'll be used here to include Parlot
into NuGet package https://github.com/RicoSuter/NJsonSchema/pull/1726/files#diff-ead3877feb09b2619c61d0feb8b85e0c85c627756febe0dda0829dafe13d5325R39
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<None Update="Tests\**\*.json" CopyToOutputDirectory="PreserveNewest" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<AdditionalFiles |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this project you can see how Source Generator actually works
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\NJsonSchema.CodeGeneration.CSharp\NJsonSchema.CodeGeneration.CSharp.csproj" PrivateAssets="All"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With PrivateAssets="All"
it will not add NJsonSchema.CodeGeneration.CSharp
as a dependency of NJsonSchema.SourceGenerators.CSharp
NuGet package as I assume it's not needed. Code from NJsonSchema.SourceGenerators.CSharp
should be enough to generate C# classes. For more advanced scenarios NJsonSchema.CodeGeneration.CSharp
can be installed explicitly in client's projects.
<ItemGroup> | ||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" PrivateAssets="all" /> | ||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" PrivateAssets="all" /> | ||
<PackageReference Include="Newtonsoft.Json" GeneratePathProperty="true" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deliberately didn't add PrivateAssets="all"
for Newtonsoft.Json
so it will be included as NuGet dependency. In the generated code Newtonsoft attributes will be used. That way client don't need to install Newtonsoft.Json
in their project explicitly.
@@ -0,0 +1,74 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My main concern is whether we should create a separate project for the source generator or add them to the existing NJsonSchema.CodeGeneration.CSharp
. Frankly speaking, I didn't try the second approach at all, but in theory, it should work.
Below are my thoughts.
Add Source Generator to new NJsonSchema.SourceGenerators.CSharp
Pros:
- Clients will install that package only if they know they need to use a source generator.
- Easier to maintain as source generator projects require additional configuration (
IsRoslynComponent
, exclude NU5128 warning, etc.)
Cons:
- The names of the NuGet packages could be confusing.
NJsonSchema.CodeGeneration.CSharp
andNJsonSchema.SourceGenerators.CSharp
may sound a bit synonimical.
Add Source Generator to existing NJsonSchema.CodeGeneration.CSharp
Pros:
- We don't introduce a new NuGet package.
- By installing
NJsonSchema.CodeGeneration.CSharp
client can use either classes from the library or/and Source Generator.
Cons:
- It'll automatically install the source generator when the client does a package upgrade. (However, the source generator will not do much without additional configuration. Not sure if this is an issue).
- The size of the NuGet package will slightly increase as it'll include DLLs for the source generator.
- The project might be harder to maintain as it will be a mix of regular code and code that will go to the source generator.
You can check my implementation of Source Generator for NSwag to see how to support transient packages automatically https://github.com/HavenDV/H.NSwag.Generator |
Thank you @HavenDV. Amazing library 🙂 However, I have some issues with project references. I asked about them here: HavenDV/H.Generators.Extensions#15 |
<ItemGroup> | ||
<None Update="NJsonSchema.SourceGenerators.CSharp.nuspec" /> | ||
|
||
<None Include="$(PkgFluid_Core)\lib\netstandard2.0\Fluid.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is how dependencies are added to the NuGet package. More details here https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.cookbook.md#use-functionality-from-nuget-packages
|
||
<Target Name="GetDependencyTargetPaths"> | ||
<ItemGroup> | ||
<TargetPathWithTargetPlatformMoniker Include="$(PkgFluid_Core)\lib\netstandard2.0\Fluid.dll" IncludeRuntimeDependency="false" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case if Source Generator needs to be added as a project reference (in NJsonSchema.Demo
) it needs additional configuration. More details here https://www.thinktecture.com/en/net/roslyn-source-generators-using-3rd-party-libraries/
@@ -21,7 +21,7 @@ namespace System.Runtime.CompilerServices | |||
/// This class should not be used by developers in source code. | |||
/// </summary> | |||
[EditorBrowsable(EditorBrowsableState.Never)] | |||
public static class IsExternalInit | |||
internal static class IsExternalInit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without that change build of NJsonSchema.SourceGenerators.CSharp.Tests
was failing. Here suggests to make it internal
if code is a part of a library
9e35119
to
56c5c54
Compare
56c5c54
to
de1a601
Compare
What's in this PR
This change aims to add a C# Source generator that automatically creates classes based on JSON schema. The idea is to make code generation more straightforward for generic scenarios. I've tried that approach on my project and it worked quite well. I thought it'd be good to make it a part of the library. This Source Generator has few configurable properties and can be extended in the future if needed.
Current approach
To generate C# classes you need to create a separate console project that will generate a
.cs
file and put it somewhere in your Solution. Then you need to manually run that console application to generate/regenerate the models. Here's exampleNew (additional) approach
Add the following elements in the
.csproj
file of your project where the generated.cs
file will exist:After that Source Generator will automatically create a
.cs
file during compilation. No additional console project or manual job is needed.Concerns
I have some questions/concerns regarding the implementation and have put them in the comments. We can start from this main one.
Also added some explanatory comments about why something was implemented that way. As tooling for the Source Generators is not the best for now and there is a lot of msbuild magic in the
.csproj
files.