├── src ├── Tools │ ├── Tests │ │ ├── Templates │ │ │ ├── 0001-Markup.g.cs │ │ │ ├── 0002-MarkupTask.g.cs │ │ │ ├── 0092-SqlClient.g.cs │ │ │ ├── 0003-MarkupAsyncTask.g.cs │ │ │ ├── 0004-Programmatic.g.cs │ │ │ ├── 0005-ProgrammaticTask.g.cs │ │ │ ├── 0091-EmbeddedReferences.g.cs │ │ │ ├── 0006-ProgrammaticAsyncTask.g.cs │ │ │ ├── 0030-MultipleFiles-Output │ │ │ │ ├── Class3.cs │ │ │ │ ├── Class1.cs │ │ │ │ └── Class2.cs │ │ │ ├── 0071-IEnumerable-SingleLineCSV.g.cs │ │ │ ├── 0070-IEnumerable.g.cs │ │ │ ├── 0072-IEnumerable-MultiLineCSV.g.cs │ │ │ ├── 0001-Markup.cs │ │ │ ├── 0050-Subtemplates-Delegates-Output │ │ │ │ └── Class1.cs │ │ │ ├── 0063-Symbols-IIF.g.cs │ │ │ ├── 0010-InterpolationMarkup.g.cs │ │ │ ├── 0011-InterpolationProgrammatic.g.cs │ │ │ ├── 0004-Programmatic.cs │ │ │ ├── 0090-Debugging.g.cs │ │ │ ├── 0060-Symbols-IF.g.cs │ │ │ ├── 0062-Symbols-Nested-IFs.g.cs │ │ │ ├── 0002-MarkupTask.cs │ │ │ ├── 0020-SubtemplateMarkupToVoid.g.cs │ │ │ ├── 0022-SubtemplateMarkupToFS.g.cs │ │ │ ├── 0021-SubtemplateProgrammaticToVoid.g.cs │ │ │ ├── 0023-SubtemplateProgrammaticToFS.g.cs │ │ │ ├── 0005-ProgrammaticTask.cs │ │ │ ├── 0070-IEnumerable.cs │ │ │ ├── 0072-IEnumerable-SQL-Insert.g.cs │ │ │ ├── 0003-MarkupAsyncTask.cs │ │ │ ├── 0006-ProgrammaticAsyncTask.cs │ │ │ ├── 0040-ImplicitIndent.g.cs │ │ │ ├── 0071-IEnumerable-SingleLineCSV.cs │ │ │ ├── 0072-IEnumerable-MultiLineCSV.cs │ │ │ ├── 0061-Symbols-IF-ELSE.g.cs │ │ │ ├── 0024-SubtemplateMarkupToFSFunc.g.cs │ │ │ ├── 0025-SubtemplateProgrammaticToFSFunc.g.cs │ │ │ ├── 0010-InterpolationMarkup.cs │ │ │ ├── 0011-InterpolationProgrammatic.cs │ │ │ ├── 0022-SubtemplateMarkupToFS.cs │ │ │ ├── 0072-IEnumerable-SQL-Insert.cs │ │ │ ├── 0020-SubtemplateMarkupToVoid.cs │ │ │ ├── 0063-Symbols-IIF.cs │ │ │ ├── 0023-SubtemplateProgrammaticToFS.cs │ │ │ ├── 0060-Symbols-IF.cs │ │ │ ├── 0021-SubtemplateProgrammaticToVoid.cs │ │ │ ├── 0062-Symbols-Nested-IFs.cs │ │ │ ├── 0030-MultipleFiles.cs │ │ │ ├── 0092-SqlClient.cs │ │ │ ├── 0024-SubtemplateMarkupToFSFunc.cs │ │ │ ├── 0091-EmbeddedReferences.cs │ │ │ ├── 0025-SubtemplateProgrammaticToFSFunc.cs │ │ │ ├── 0073-IEnumerable-Nested-Lists.cs │ │ │ ├── 0040-ImplicitIndent.cs │ │ │ ├── 0061-Symbols-IF-ELSE.cs │ │ │ ├── 0051-Subtemplates-Looping.cs │ │ │ ├── 0090-Debugging.cs │ │ │ ├── 0050-Subtemplates-Delegates.cs │ │ │ └── 0074-IEnumerable-With-Delegates.cs │ │ ├── TemplateBuildTests.cs │ │ └── CodegenCS.Tools.Tests.csproj │ ├── TemplateDownloader │ │ └── TemplateCatalog.cs │ ├── TemplateLauncher │ │ ├── ModelFactoryBuilder.cs │ │ └── DependencyContainerExtensions.cs │ ├── dotnet-codegencs │ │ ├── ErrorResult.cs │ │ ├── dotnet-codegencs.nuspec │ │ ├── NuGetReadMe.md │ │ └── Program.cs │ └── CodegenCS.Tools.CliTool.Tests │ │ └── CodegenCS.Tools.CliTool.Tests.csproj ├── debug.snk ├── VisualStudio │ ├── VS2019Extension │ │ ├── Resources │ │ │ ├── RunTemplateCommand.png │ │ │ └── VisualStudioPackage.ico │ │ └── Properties │ │ │ └── AssemblyInfo.cs │ ├── VS2022Extension │ │ ├── Resources │ │ │ ├── RunTemplateCommand.png │ │ │ └── VisualStudioPackage.ico │ │ └── Properties │ │ │ └── AssemblyInfo.cs │ ├── reset-experimental-visualstudio.ps1 │ ├── CodegenCS.Runtime.VisualStudio │ │ ├── ExecutionContext │ │ │ └── VSExecutionContext.cs │ │ └── Logging │ │ │ └── VsOutputWindowPaneOutputLogger.cs │ ├── Shared │ │ └── Utils │ │ │ ├── Utils.cs │ │ │ └── AssembliesLoader.cs │ └── Tests │ │ ├── InjectionTests.cs │ │ └── CodegenCS.VisualStudio.Tests.csproj ├── Core │ ├── CodegenCS │ │ ├── ControlFlow │ │ │ ├── TrimLeadingWhitespaceSymbol.cs │ │ │ ├── TrimTrailingWhitespaceSymbol.cs │ │ │ ├── EndIfSymbol.cs │ │ │ ├── IControlFlowSymbol.cs │ │ │ ├── WriteRawSymbol.cs │ │ │ ├── IfSymbol.cs │ │ │ ├── UnbalancedIfsException.cs │ │ │ └── ElseSymbol.cs │ │ ├── README.md │ │ ├── ICodegenOutputFile.cs │ │ ├── IO │ │ │ └── SaveFilesResult.cs │ │ ├── CodegenCS.Core.nuspec │ │ ├── Utils │ │ │ ├── IOUtils.cs │ │ │ └── TypeUtils.cs │ │ ├── Templating │ │ │ └── InlineTemplateLoader.cs │ │ ├── RawString.cs │ │ └── CodegenOutputFile.cs │ ├── CodegenCS.Tests │ │ ├── TemplateTests │ │ │ ├── 2-ICodegenMultifileTemplate-TestsOutput │ │ │ │ ├── Test21 │ │ │ │ │ ├── Products.cs │ │ │ │ │ └── Users.cs │ │ │ │ └── Test22 │ │ │ │ │ ├── Products.cs │ │ │ │ │ └── Users.cs │ │ │ ├── 1-ICodegenTemplate-TestsOutput │ │ │ │ └── Test01 │ │ │ │ │ └── Users.cs │ │ │ ├── 3-ICodegenStringTemplate-TestsOutput │ │ │ │ ├── Test31 │ │ │ │ │ └── Users.cs │ │ │ │ └── Test32 │ │ │ │ │ └── MyDatabase.cs │ │ │ ├── 1-ICodegenTemplate │ │ │ │ └── ICodegenTemplateTests.cs │ │ │ └── 2-ICodegenMultifileTemplate │ │ │ │ └── ICodegenMultifileTemplateTests.cs │ │ ├── DotNet │ │ │ └── DotNetCodegenContextTests.cs │ │ ├── CoreTests │ │ │ └── 60-FormattingTests.cs │ │ ├── SchemaTests │ │ │ └── InputModelTests.cs │ │ └── CodegenCS.Tests.csproj │ ├── CodegenCS.Runtime │ │ ├── CommandLine │ │ │ ├── IAutoBindCommandLineArgs.cs │ │ │ ├── CommandLineArgsException.cs │ │ │ ├── CommandLineArgs.cs │ │ │ └── AutoBindCommandLineArgsTypeResolver.cs │ │ ├── ExecutionContext │ │ │ └── ExecutionContext.cs │ │ ├── CodegenCS.Runtime.nuspec │ │ ├── Logging │ │ │ ├── DebugOutputLogger.cs │ │ │ └── ILogger.cs │ │ └── DependencyContainerExtensions.cs │ ├── CodegenCS.Models │ │ ├── IInputModel.cs │ │ ├── IInputModelAdapter.cs │ │ ├── CodegenCS.Models.nuspec │ │ ├── IModelFactory.cs │ │ ├── IJsonInputModel.cs │ │ └── JsonInputModelParser.cs │ └── CodegenCS.DotNet │ │ ├── CodegenCS.DotNet.nuspec │ │ ├── ProjectType.cs │ │ ├── BuildActionType.cs │ │ ├── DotNetCodegenContext.cs │ │ └── CodegenCS.DotNet.csproj ├── .editorconfig ├── Directory.build.props ├── SourceGenerator │ ├── CodegenCS.SourceGenerator │ │ ├── AnalyzerReleases.Shipped.md │ │ └── AnalyzerReleases.Unshipped.md │ └── README.md ├── NuGet.config ├── Models │ ├── CodegenCS.Models.DbSchema │ │ ├── DbSchema │ │ │ ├── ForeignKeyMember.cs │ │ │ ├── IndexMember.cs │ │ │ ├── Table.cs │ │ │ ├── Index.cs │ │ │ ├── Column.cs │ │ │ ├── ForeignKey.cs │ │ │ └── DatabaseSchema.cs │ │ ├── NuGetReadMe.md │ │ ├── CodegenCS.Models.DbSchema.nuspec │ │ └── README.md │ ├── CodegenCS.Models.NSwagAdapter │ │ ├── OpenApiDocumentAdapter.cs │ │ ├── CodegenCS.Models.NSwagAdapter.nuspec │ │ ├── README.md │ │ └── SampleModels │ │ │ └── petstore-openapi3.yaml │ ├── CodegenCS.Models.DbSchema.Extractor │ │ ├── MSSQL │ │ │ └── RefreshSqlServerSchema.csx │ │ ├── PostgreSQL │ │ │ └── RefreshPgsqlSchema.csx │ │ └── CliCommand.cs │ └── README.md ├── MSBuild │ ├── CodegenCS.MSBuild │ │ └── build │ │ │ ├── CodegenCS.MSBuild.props │ │ │ └── CodegenCS.MSBuild.targets │ └── README.md ├── build-external.ps1 ├── build-clean.ps1 ├── build-include.ps1 ├── build-models.ps1 ├── build-core.ps1 └── build-visualstudio.ps1 ├── .gitmodules ├── Samples ├── MSBuild1 │ ├── Template1.csx │ ├── Template2.csx │ ├── MSBuild1.csproj │ ├── TestClass.cs │ └── Template3.csx ├── MSBuild2 │ ├── Template1.csx │ ├── Template2.csx │ ├── packages.config │ ├── Template3.csx │ ├── Web.config │ ├── Web.Debug.config │ ├── Web.Release.config │ └── Properties │ │ └── AssemblyInfo.cs ├── NuGet.config ├── SourceGenerator1 │ ├── SampleClass.cs │ ├── Template1.csx │ ├── Template2.csx │ ├── AnotherSampleClass.cs │ ├── SourceGenerator1.csproj │ └── Template3.csx ├── SourceGenerator2 │ ├── IDbConnectionFactory.cs │ ├── SourceGenerator2.csproj │ ├── Program.cs │ └── SampleSourceGenerator.SimplePocos.DemoProject.csproj ├── PrebuildEvent │ ├── PrebuildEvent.csproj │ └── RunTemplates.ps1 └── Samples.sln ├── .github └── FUNDING.yml └── LICENSE /src/Tools/Tests/Templates/0001-Markup.g.cs: -------------------------------------------------------------------------------- 1 | My first template -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0002-MarkupTask.g.cs: -------------------------------------------------------------------------------- 1 | My first template -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0092-SqlClient.g.cs: -------------------------------------------------------------------------------- 1 | My template worked -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0003-MarkupAsyncTask.g.cs: -------------------------------------------------------------------------------- 1 | My first template -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0004-Programmatic.g.cs: -------------------------------------------------------------------------------- 1 | My first template -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0005-ProgrammaticTask.g.cs: -------------------------------------------------------------------------------- 1 | My first template -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0091-EmbeddedReferences.g.cs: -------------------------------------------------------------------------------- 1 | My template worked -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0006-ProgrammaticAsyncTask.g.cs: -------------------------------------------------------------------------------- 1 | My first template -------------------------------------------------------------------------------- /src/debug.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Drizin/CodegenCS/HEAD/src/debug.snk -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0030-MultipleFiles-Output/Class3.cs: -------------------------------------------------------------------------------- 1 | public class Class3 {} 2 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0071-IEnumerable-SingleLineCSV.g.cs: -------------------------------------------------------------------------------- 1 | I have to buy: Milk, Eggs, Diet Coke -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0070-IEnumerable.g.cs: -------------------------------------------------------------------------------- 1 | I have to buy: 2 | Milk 3 | Eggs 4 | Diet Coke -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0072-IEnumerable-MultiLineCSV.g.cs: -------------------------------------------------------------------------------- 1 | I have to buy: 2 | Milk, 3 | Eggs, 4 | Diet Coke -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0001-Markup.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | FormattableString Main() => $"My first template"; 4 | } -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0030-MultipleFiles-Output/Class1.cs: -------------------------------------------------------------------------------- 1 | public class Class1() 2 | { 3 | public Class1() 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0030-MultipleFiles-Output/Class2.cs: -------------------------------------------------------------------------------- 1 | public class Class2() 2 | { 3 | public Class2() 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/External/command-line-api"] 2 | path = src/External/command-line-api 3 | url = https://github.com/Drizin/CodegenCS-command-line-api.git 4 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0050-Subtemplates-Delegates-Output/Class1.cs: -------------------------------------------------------------------------------- 1 | // Class1 is a new stream (different file) 2 | public class Class1() 3 | { 4 | // ... 5 | } 6 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0063-Symbols-IIF.g.cs: -------------------------------------------------------------------------------- 1 | public class User 2 | { 3 | public string FirstName { get; set; } 4 | public string FirstName { get; set; } 5 | } 6 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0010-InterpolationMarkup.g.cs: -------------------------------------------------------------------------------- 1 | public class MyFirstClass { 2 | public void HelloRick() { 3 | Console.WriteLine("Hello, Rick") 4 | } 5 | } -------------------------------------------------------------------------------- /src/VisualStudio/VS2019Extension/Resources/RunTemplateCommand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Drizin/CodegenCS/HEAD/src/VisualStudio/VS2019Extension/Resources/RunTemplateCommand.png -------------------------------------------------------------------------------- /src/VisualStudio/VS2022Extension/Resources/RunTemplateCommand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Drizin/CodegenCS/HEAD/src/VisualStudio/VS2022Extension/Resources/RunTemplateCommand.png -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0011-InterpolationProgrammatic.g.cs: -------------------------------------------------------------------------------- 1 | public class MyFirstClass { 2 | public void HelloRick() { 3 | Console.WriteLine("Hello, Rick") 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/VisualStudio/VS2019Extension/Resources/VisualStudioPackage.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Drizin/CodegenCS/HEAD/src/VisualStudio/VS2019Extension/Resources/VisualStudioPackage.ico -------------------------------------------------------------------------------- /src/VisualStudio/VS2022Extension/Resources/VisualStudioPackage.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Drizin/CodegenCS/HEAD/src/VisualStudio/VS2022Extension/Resources/VisualStudioPackage.ico -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0004-Programmatic.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | void Main(ICodegenOutputFile writer) 4 | { 5 | writer.Write($"My first template"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0090-Debugging.g.cs: -------------------------------------------------------------------------------- 1 | I have to buy: 2 | Milk 3 | Eggs 4 | Diet Coke 5 | Will write some more stuff 6 | writing something here 7 | last part 8 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0060-Symbols-IF.g.cs: -------------------------------------------------------------------------------- 1 | public class MyApiClient 2 | { 3 | public MyApiClient(HttpClient httpClient) 4 | { 5 | _httpClient = httpClient; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Core/CodegenCS/ControlFlow/TrimLeadingWhitespaceSymbol.cs: -------------------------------------------------------------------------------- 1 | namespace CodegenCS.ControlFlow 2 | { 3 | public class TrimLeadingWhitespaceSymbol : IControlFlowSymbol 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/Core/CodegenCS/ControlFlow/TrimTrailingWhitespaceSymbol.cs: -------------------------------------------------------------------------------- 1 | namespace CodegenCS.ControlFlow 2 | { 3 | public class TrimTrailingWhitespaceSymbol : IControlFlowSymbol 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0062-Symbols-Nested-IFs.g.cs: -------------------------------------------------------------------------------- 1 | public class MyApiClient 2 | { 3 | public MyApiClient(HttpClient httpClient) 4 | { 5 | _httpClient = httpClient; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0002-MarkupTask.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | Task Main() 4 | { 5 | return Task.FromResult((FormattableString)$"My first template"); 6 | } 7 | } -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0020-SubtemplateMarkupToVoid.g.cs: -------------------------------------------------------------------------------- 1 | namespace MyNamespace 2 | { 3 | public class MyFirstClass { 4 | public void HelloWorld() { 5 | // ... 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0022-SubtemplateMarkupToFS.g.cs: -------------------------------------------------------------------------------- 1 | namespace MyNamespace 2 | { 3 | public class MyFirstClass { 4 | public void HelloWorld() { 5 | // ... 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /src/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # CS1591: Missing XML comment for publicly visible type or member 4 | dotnet_diagnostic.CS1591.severity = none 5 | 6 | [*.csproj] 7 | indent_style = space 8 | indent_size = 2 9 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0021-SubtemplateProgrammaticToVoid.g.cs: -------------------------------------------------------------------------------- 1 | namespace MyNamespace 2 | { 3 | public class MyFirstClass { 4 | public void HelloWorld() { 5 | // ... 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0023-SubtemplateProgrammaticToFS.g.cs: -------------------------------------------------------------------------------- 1 | namespace MyNamespace 2 | { 3 | public class MyFirstClass { 4 | public void HelloWorld() { 5 | // ... 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /src/Core/CodegenCS/README.md: -------------------------------------------------------------------------------- 1 | This page was moved / split into multiple plages. 2 | 3 | Please go to the [Main Project Page](https://github.com/Drizin/CodegenCS/) 4 | is only about the **CodegenCS Core Library**: 5 | 6 | -------------------------------------------------------------------------------- /Samples/MSBuild1/Template1.csx: -------------------------------------------------------------------------------- 1 | // Sample template that starts with markup (Main method returns an interpolated string) 2 | 3 | class Template1 4 | { 5 | FormattableString Main() => $$"""public class MyFirstClass {}"""; 6 | } -------------------------------------------------------------------------------- /Samples/MSBuild2/Template1.csx: -------------------------------------------------------------------------------- 1 | // Sample template that starts with markup (Main method returns an interpolated string) 2 | 3 | class Template1 4 | { 5 | FormattableString Main() => $$"""public class MyFirstClass {}"""; 6 | } -------------------------------------------------------------------------------- /src/Directory.build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0005-ProgrammaticTask.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | Task Main(ICodegenOutputFile writer) 4 | { 5 | writer.Write($"My first template"); 6 | return Task.CompletedTask; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/SourceGenerator/CodegenCS.SourceGenerator/AnalyzerReleases.Shipped.md: -------------------------------------------------------------------------------- 1 | ; Shipped analyzer releases 2 | ; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md 3 | 4 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0070-IEnumerable.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | string[] groceries = new string[] { "Milk", "Eggs", "Diet Coke" }; 4 | 5 | FormattableString Main() => $$""" 6 | I have to buy: 7 | {{groceries}} 8 | """; 9 | } -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0072-IEnumerable-SQL-Insert.g.cs: -------------------------------------------------------------------------------- 1 | INSERT INTO [Person].[Address] 2 | ( 3 | [AddressLine1], 4 | [AddressLine2], 5 | [City] 6 | ) 7 | VALUES 8 | ( 9 | @AddressLine1, 10 | @AddressLine2, 11 | @City 12 | ) -------------------------------------------------------------------------------- /Samples/MSBuild1/Template2.csx: -------------------------------------------------------------------------------- 1 | // Sample template that writes programmatically 2 | 3 | class Template2 4 | { 5 | void Main(ICodegenOutputFile writer) 6 | { 7 | writer.Write($$"""public class MySecondClass {}"""); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Samples/MSBuild2/Template2.csx: -------------------------------------------------------------------------------- 1 | // Sample template that writes programmatically 2 | 3 | class Template2 4 | { 5 | void Main(ICodegenOutputFile writer) 6 | { 7 | writer.Write($$"""public class MySecondClass {}"""); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0003-MarkupAsyncTask.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | async Task Main(ILogger logger) 4 | { 5 | await logger.WriteLineAsync($"Generating MyTemplate..."); 6 | return $"My first template"; 7 | } 8 | } -------------------------------------------------------------------------------- /Samples/NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Tests/TemplateTests/2-ICodegenMultifileTemplate-TestsOutput/Test21/Products.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// POCO for Products 3 | /// 4 | public class Products 5 | { 6 | public int Description { get; set; } 7 | public string ProductId { get; set; } 8 | } -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0006-ProgrammaticAsyncTask.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | async Task Main(ILogger logger, ICodegenOutputFile writer) 4 | { 5 | await logger.WriteLineAsync($"Generating MyTemplate..."); 6 | writer.Write($"My first template"); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0040-ImplicitIndent.g.cs: -------------------------------------------------------------------------------- 1 | namespace CodegenCS.Sample 2 | { 3 | public class MyAutogeneratedClass 4 | { 5 | public void HelloCodeGenerationWorld() 6 | { 7 | Console.WriteLine("Hello World"); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Samples/MSBuild2/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Runtime/CommandLine/IAutoBindCommandLineArgs.cs: -------------------------------------------------------------------------------- 1 | namespace CodegenCS.Runtime 2 | { 3 | /// 4 | /// 5 | /// 6 | public interface IAutoBindCommandLineArgs 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Tests/TemplateTests/1-ICodegenTemplate-TestsOutput/Test01/Users.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// POCO for Users 3 | /// 4 | public class Users 5 | { 6 | public int UserId { get; set; } 7 | public string FirstName { get; set; } 8 | public string LastName { get; set; } 9 | } -------------------------------------------------------------------------------- /src/Core/CodegenCS.Tests/TemplateTests/3-ICodegenStringTemplate-TestsOutput/Test31/Users.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// POCO for Users 3 | /// 4 | public class Users 5 | { 6 | public int UserId { get; set; } 7 | public string FirstName { get; set; } 8 | public string LastName { get; set; } 9 | } -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0071-IEnumerable-SingleLineCSV.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | string[] groceries = new string[] { "Milk", "Eggs", "Diet Coke" }; 4 | 5 | FormattableString Main() => $$""" 6 | I have to buy: {{groceries.Render(RenderEnumerableOptions.SingleLineCSV)}} 7 | """; 8 | } -------------------------------------------------------------------------------- /Samples/SourceGenerator1/SampleClass.cs: -------------------------------------------------------------------------------- 1 | namespace SampleProjectWithSourceGenerator 2 | { 3 | public partial class SampleClass 4 | { 5 | public SampleClass() 6 | { 7 | Initialize(); // Guess what? This method will be generated on the fly! 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Tests/TemplateTests/2-ICodegenMultifileTemplate-TestsOutput/Test21/Users.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// POCO for Users 3 | /// 4 | public class Users 5 | { 6 | public int UserId { get; set; } 7 | public string FirstName { get; set; } 8 | public string LastName { get; set; } 9 | } -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0072-IEnumerable-MultiLineCSV.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | string[] groceries = new string[] { "Milk", "Eggs", "Diet Coke" }; 4 | 5 | FormattableString Main() => $$""" 6 | I have to buy: 7 | {{groceries.Render(RenderEnumerableOptions.MultiLineCSV)}} 8 | """; 9 | } -------------------------------------------------------------------------------- /Samples/MSBuild1/MSBuild1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0061-Symbols-IF-ELSE.g.cs: -------------------------------------------------------------------------------- 1 | public class MyApiClient 2 | { 3 | public void InvokeApi() 4 | { 5 | try 6 | { 7 | restApi.Invoke(); 8 | } 9 | catch (Exception ex) 10 | { 11 | Log.Error(ex); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0024-SubtemplateMarkupToFSFunc.g.cs: -------------------------------------------------------------------------------- 1 | namespace MyNamespace 2 | { 3 | public class MyFirstClass 4 | { 5 | public MyFirstClass() 6 | { 7 | } 8 | public void HelloRick() 9 | { 10 | Console.WriteLine("Hello, Rick") 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Core/CodegenCS/ControlFlow/EndIfSymbol.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Text; 5 | 6 | namespace CodegenCS.ControlFlow 7 | { 8 | [DebuggerDisplay("[ENDIF()]")] 9 | public class EndIfSymbol : IControlFlowSymbol 10 | { 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0025-SubtemplateProgrammaticToFSFunc.g.cs: -------------------------------------------------------------------------------- 1 | namespace MyNamespace 2 | { 3 | public class MyFirstClass 4 | { 5 | public MyFirstClass() 6 | { 7 | } 8 | public void HelloRick() 9 | { 10 | Console.WriteLine("Hello, Rick") 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Models/IInputModel.cs: -------------------------------------------------------------------------------- 1 | namespace CodegenCS.Models 2 | { 3 | /// 4 | /// Input Models are loaded by Command-line tool (dotnet-codegencs) and will be automatically injected into template constructors or entrypoints. 5 | /// 6 | public interface IInputModel 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Models/CodegenCS.Models.DbSchema/DbSchema/ForeignKeyMember.cs: -------------------------------------------------------------------------------- 1 | namespace CodegenCS.Models.DbSchema 2 | { 3 | public class ForeignKeyMember 4 | { 5 | public int PKColumnOrdinalPosition { get; set; } 6 | public string PKColumnName { get; set; } 7 | 8 | public string FKColumnName { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Core/CodegenCS/ControlFlow/IControlFlowSymbol.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CodegenCS.ControlFlow 6 | { 7 | /// 8 | /// Any control-flow symbol, like IF / ELSE / ENDIF 9 | /// 10 | public interface IControlFlowSymbol 11 | { 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0010-InterpolationMarkup.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | string _name = "Rick"; 4 | 5 | FormattableString Main() => $$""" 6 | public class MyFirstClass { 7 | public void Hello{{_name}}() { 8 | Console.WriteLine("Hello, {{_name}}") 9 | } 10 | } 11 | """; 12 | } 13 | -------------------------------------------------------------------------------- /src/Tools/TemplateDownloader/TemplateCatalog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CodegenCS.Tools.TemplateDownloader 6 | { 7 | internal class TemplateMetadata 8 | { 9 | public string[] Description { get; set; } 10 | public string[] ModelType { get; set; } 11 | public string Uri { get; set; } 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0011-InterpolationProgrammatic.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | string _name = "Rick"; 4 | 5 | void Main(ICodegenOutputFile writer) 6 | { 7 | writer.WriteLine($$""" 8 | public class MyFirstClass { 9 | public void Hello{{_name}}() { 10 | Console.WriteLine("Hello, {{_name}}") 11 | } 12 | } 13 | """); 14 | } 15 | } -------------------------------------------------------------------------------- /src/Core/CodegenCS.Models/IInputModelAdapter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace CodegenCS.Models 5 | { 6 | /// 7 | /// Input Model Adapters are used to load third-party models 8 | /// 9 | public interface IInputModelAdapter 10 | { 11 | bool CanLoadType(Type targetType); 12 | Task LoadFromContentAsync(string content, string filePath); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Samples/SourceGenerator1/Template1.csx: -------------------------------------------------------------------------------- 1 | // Sample template that starts with markup (Main method returns an interpolated string) 2 | 3 | // If you look in CSPROJ you'll see this file described as: 4 | // 5 | // CodegenCSOutput="File" means that the output of this file is saved into a real file 6 | 7 | class Template1 8 | { 9 | FormattableString Main() => $$"""public class MyFirstClass {}"""; 10 | } -------------------------------------------------------------------------------- /src/Models/CodegenCS.Models.DbSchema/DbSchema/IndexMember.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace CodegenCS.Models.DbSchema 6 | { 7 | public class IndexMember 8 | { 9 | public string ColumnName { get; set; } 10 | 11 | public int IndexOrdinalPosition { get; set; } 12 | 13 | public bool IsDescendingKey { get; set; } 14 | public bool IsIncludedColumn { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Core/CodegenCS/ControlFlow/WriteRawSymbol.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace CodegenCS.ControlFlow 4 | { 5 | [DebuggerDisplay("[RAW({Text,nq})]")] 6 | public sealed class WriteRawSymbol : IControlFlowSymbol 7 | { 8 | public string Text { get; set; } 9 | 10 | public WriteRawSymbol() 11 | { 12 | } 13 | internal WriteRawSymbol(string text) 14 | { 15 | Text = text; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Tools/TemplateLauncher/ModelFactoryBuilder.cs: -------------------------------------------------------------------------------- 1 | using CodegenCS.Models; 2 | using CodegenCS.Models.NSwagAdapter; 3 | using System.Collections.Generic; 4 | 5 | 6 | namespace CodegenCS 7 | { 8 | public class ModelFactoryBuilder 9 | { 10 | public static IModelFactory CreateModelFactory(string[] searchPaths) 11 | { 12 | return new ModelFactory(searchPaths, new List() { new OpenApiDocumentAdapter() }); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0022-SubtemplateMarkupToFS.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | string _ns = "MyNamespace"; 4 | 5 | FormattableString Main() => $$""" 6 | namespace {{_ns}} 7 | { 8 | {{WriteClass}} 9 | } 10 | """; 11 | 12 | FormattableString WriteClass() => $$""" 13 | public class MyFirstClass { 14 | public void HelloWorld() { 15 | // ... 16 | } 17 | } 18 | """; 19 | } 20 | -------------------------------------------------------------------------------- /src/Core/CodegenCS/ControlFlow/IfSymbol.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Text; 5 | 6 | namespace CodegenCS.ControlFlow 7 | { 8 | [DebuggerDisplay("[IF({IfConditionValue,nq})]")] 9 | public class IfSymbol : IControlFlowSymbol 10 | { 11 | public bool IfConditionValue { get; set; } 12 | public IfSymbol(bool condition) 13 | { 14 | IfConditionValue = condition; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Samples/SourceGenerator2/IDbConnectionFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.SqlClient; 3 | 4 | namespace MyProject.POCOs 5 | { 6 | public class IDbConnectionFactory 7 | { 8 | public static IDbConnection CreateConnection() 9 | { 10 | return new SqlConnection(@"Data Source=(local); Initial Catalog=AdventureWorks2019; Integrated Security=True;"); 11 | // Implement your own factory... e.g. new NpgsqlConnection (...) 12 | } 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /Samples/MSBuild1/TestClass.cs: -------------------------------------------------------------------------------- 1 | using MyNamespace; // only generated by MSBuild Task 2 | 3 | namespace MSBuild.Test 4 | { 5 | public class TestClass 6 | { 7 | public TestClass() 8 | { 9 | // All classes below are generated by the MSBuild Task 10 | var c1 = new Class1(); 11 | var c2 = new Class2(); 12 | var c3 = new Class3(); 13 | var mf = new MyFirstClass(); 14 | var ms = new MySecondClass(); 15 | } 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Tests/TemplateTests/2-ICodegenMultifileTemplate-TestsOutput/Test22/Products.cs: -------------------------------------------------------------------------------- 1 | /// Copyright Rick Drizin (just kidding - this is MIT license - use however you like it!) 2 | using System; 3 | using System.IO; 4 | using System.Collections.Generic; 5 | 6 | namespace MyNamespace 7 | { 8 | /// 9 | /// POCO for Products 10 | /// 11 | public class Products 12 | { 13 | public int Description { get; set; } 14 | public string ProductId { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /Samples/SourceGenerator1/Template2.csx: -------------------------------------------------------------------------------- 1 | // Sample template that writes programmatically 2 | 3 | // If you look in CSPROJ you'll see this file described as: 4 | // 5 | // CodegenCSOutput="Memory" means that the output of this file is just rendered into the compilation but it's not saved into a real file 6 | 7 | class Template2 8 | { 9 | void Main(ICodegenOutputFile writer) 10 | { 11 | writer.Write($$"""public class MySecondClass {}"""); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0072-IEnumerable-SQL-Insert.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | string[] cols = new string[] { "AddressLine1", "AddressLine2", "City" }; 4 | 5 | FormattableString Main() => $$""" 6 | INSERT INTO [Person].[Address] 7 | ( 8 | {{cols.Select(col => "[" + col + "]").Render(RenderEnumerableOptions.MultiLineCSV)}} 9 | ) 10 | VALUES 11 | ( 12 | {{cols.Select(col => "@" + col).Render(RenderEnumerableOptions.MultiLineCSV)}} 13 | ) 14 | """; 15 | } 16 | -------------------------------------------------------------------------------- /Samples/SourceGenerator1/AnotherSampleClass.cs: -------------------------------------------------------------------------------- 1 | namespace SampleProjectWithSourceGenerator 2 | { 3 | public partial class AnotherSampleClass 4 | { 5 | public AnotherSampleClass() 6 | { 7 | Initialize(); // Guess what? This method will be generated on the fly! 8 | var myFirstClass = new MyFirstClass(); // this class is physically generated by Template1.csx (Template1.g.cs) 9 | var mySecondClass = new MySecondClass(); // this class is generated in-memory by Template2.csx 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Tests/TemplateTests/2-ICodegenMultifileTemplate-TestsOutput/Test22/Users.cs: -------------------------------------------------------------------------------- 1 | /// Copyright Rick Drizin (just kidding - this is MIT license - use however you like it!) 2 | using System; 3 | using System.IO; 4 | using System.Collections.Generic; 5 | 6 | namespace MyNamespace 7 | { 8 | /// 9 | /// POCO for Users 10 | /// 11 | public class Users 12 | { 13 | public int UserId { get; set; } 14 | public string FirstName { get; set; } 15 | public string LastName { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Core/CodegenCS/ICodegenOutputFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CodegenCS 6 | { 7 | public interface ICodegenOutputFile : ICodegenTextWriter 8 | { 9 | void SetContext(ICodegenContext Context); 10 | string RelativePath { get; set; } 11 | } 12 | public interface ICodegenOutputFile : ICodegenOutputFile 13 | where FT : struct, IComparable, IConvertible, IFormattable // FT should be enum. 14 | { 15 | FT FileType { get; set; } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0020-SubtemplateMarkupToVoid.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | string _ns = "MyNamespace"; 4 | 5 | FormattableString Main() => $$""" 6 | namespace {{_ns}} 7 | { 8 | {{WriteClass}} 9 | } 10 | """; 11 | 12 | void WriteClass(ICodegenOutputFile writer) 13 | { 14 | writer.Write($$""" 15 | public class MyFirstClass { 16 | public void HelloWorld() { 17 | // ... 18 | } 19 | } 20 | """); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0063-Symbols-IIF.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | void Main(ICodegenOutputFile writer) 4 | { 5 | RenderMyApiClient(writer, true); 6 | } 7 | void RenderMyApiClient(ICodegenOutputFile w, bool isVisibilityPublic) 8 | { 9 | w.WriteLine($$""" 10 | public class User 11 | { 12 | {{IIF(isVisibilityPublic, $"public ")}}string FirstName { get; set; } 13 | {{IIF(isVisibilityPublic, $"public ", $"protected ")}}string FirstName { get; set; } 14 | } 15 | """); 16 | } 17 | } -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0023-SubtemplateProgrammaticToFS.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | string _ns = "MyNamespace"; 4 | 5 | void Main(ICodegenOutputFile writer) 6 | { 7 | writer.Write($$""" 8 | namespace {{_ns}} 9 | { 10 | {{WriteClass}} 11 | } 12 | """); 13 | } 14 | 15 | 16 | FormattableString WriteClass => $$""" 17 | public class MyFirstClass { 18 | public void HelloWorld() { 19 | // ... 20 | } 21 | } 22 | """; 23 | } 24 | -------------------------------------------------------------------------------- /src/Core/CodegenCS/ControlFlow/UnbalancedIfsException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CodegenCS.ControlFlow 6 | { 7 | /// 8 | /// When there is an unbalanced number of IF/ELSE/ENDIF. Each IF should have a matching ENDIF, and may have an optional ELSE. 9 | /// 10 | public class UnbalancedIfsException : Exception 11 | { 12 | /// 13 | public UnbalancedIfsException() : base("Unbalanced number of IF/ELSE/ENDIF") 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Core/CodegenCS/IO/SaveFilesResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace CodegenCS.IO 6 | { 7 | public class SaveFilesResult 8 | { 9 | public List SavedFiles { get; internal set; } 10 | 11 | /// 12 | /// List of files that exist under outputFolder and that were NOT saved as part of this ICodegenContext. 13 | /// Only returned if getUnknownFiles is true 14 | /// 15 | public List UnknownFiles { get; internal set; } 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Tools/TemplateLauncher/DependencyContainerExtensions.cs: -------------------------------------------------------------------------------- 1 | using CodegenCS.Models; 2 | using DependencyContainer = CodegenCS.Utils.DependencyContainer; 3 | 4 | namespace CodegenCS 5 | { 6 | public static class DependencyContainerExtensions 7 | { 8 | public static DependencyContainer AddModelFactory(this DependencyContainer dependencyContainer, string[] searchPaths) 9 | { 10 | dependencyContainer.RegisterSingleton(ModelFactoryBuilder.CreateModelFactory(searchPaths)); 11 | return dependencyContainer; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/SourceGenerator/CodegenCS.SourceGenerator/AnalyzerReleases.Unshipped.md: -------------------------------------------------------------------------------- 1 | ; Unshipped analyzer release 2 | ; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md 3 | 4 | ### New Rules 5 | 6 | Rule ID | Category | Severity | Notes 7 | --------|----------|----------|-------------------- 8 | CODEGENCS001 | Design | Error | [Documentation](CODEGENCS001_Documentation_Link) 9 | CODEGENCS002 | Design | Error | [Documentation](CODEGENCS002_Documentation_Link) 10 | CODEGENCS003 | Design | Error | [Documentation](CODEGENCS003_Documentation_Link) 11 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0060-Symbols-IF.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | void Main(IModelFactory factory, ICodegenOutputFile writer) 4 | { 5 | RenderMyApiClient(writer, true); 6 | } 7 | void RenderMyApiClient(ICodegenOutputFile w, bool injectHttpClient) 8 | { 9 | w.WriteLine($$""" 10 | public class MyApiClient 11 | { 12 | public MyApiClient({{IF(injectHttpClient)}}HttpClient httpClient{{ENDIF}}) 13 | { {{IF(injectHttpClient)}} 14 | _httpClient = httpClient; {{ENDIF}} 15 | } 16 | } 17 | """); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Models/CodegenCS.Models.NSwagAdapter/OpenApiDocumentAdapter.cs: -------------------------------------------------------------------------------- 1 | using NSwag; 2 | using System; 3 | using System.Threading.Tasks; 4 | 5 | namespace CodegenCS.Models.NSwagAdapter 6 | { 7 | public class OpenApiDocumentAdapter : IInputModelAdapter 8 | { 9 | public bool CanLoadType(Type targetType) 10 | { 11 | return targetType == typeof(OpenApiDocument); 12 | } 13 | 14 | public async Task LoadFromContentAsync(string content, string filePath) 15 | { 16 | var document = await OpenApiDocument.FromJsonAsync(content); 17 | return document; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0021-SubtemplateProgrammaticToVoid.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | string _ns = "MyNamespace"; 4 | 5 | void Main(ICodegenOutputFile writer) 6 | { 7 | writer.Write($$""" 8 | namespace {{_ns}} 9 | { 10 | {{WriteClass}} 11 | } 12 | """); 13 | } 14 | 15 | 16 | void WriteClass(ICodegenOutputFile writer) 17 | { 18 | writer.Write($$""" 19 | public class MyFirstClass { 20 | public void HelloWorld() { 21 | // ... 22 | } 23 | } 24 | """); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0062-Symbols-Nested-IFs.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | void Main(ICodegenOutputFile writer) 4 | { 5 | RenderMyApiClient(writer, true, true); 6 | } 7 | void RenderMyApiClient(ICodegenOutputFile w, bool generateConstructor, bool injectHttpClient) 8 | { 9 | w.WriteLine($$""" 10 | {{IF(generateConstructor)}}public class MyApiClient 11 | { 12 | public MyApiClient({{IF(injectHttpClient)}}HttpClient httpClient{{ENDIF}}) 13 | { {{IF(injectHttpClient)}} 14 | _httpClient = httpClient; {{ENDIF}} 15 | } 16 | } {{ENDIF}} 17 | """); 18 | } 19 | } -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0030-MultipleFiles.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | void Main(ICodegenContext context) 4 | { 5 | context["Class1.cs"].WriteLine(GenerateClass("Class1")); 6 | context["Class2.cs"].WriteLine(GenerateClass("Class2")); 7 | context["Class3.cs"].WriteLine("public class Class3 {}"); 8 | context.DefaultOutputFile.WriteLine("this goes to standard output"); // e.g. "MyTemplate.g.cs" 9 | } 10 | 11 | FormattableString GenerateClass(string className) => $$""" 12 | public class {{className}} 13 | { 14 | public {{className}}() 15 | { 16 | } 17 | } 18 | """; 19 | } 20 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0092-SqlClient.cs: -------------------------------------------------------------------------------- 1 | #r "System.Data.dll" 2 | #r "System.Data.SqlClient.dll" 3 | #r "System.Data.Common.dll" 4 | using System.Data.SqlClient; 5 | 6 | class MyTemplate 7 | { 8 | private readonly string CONNECTION_STRING = "Data Source=;Initial Catalog='yourdb';Persist Security Info=True;Encrypt=false;User ID=;Password='';"; 9 | async Task Main() 10 | { 11 | using (SqlConnection sqlConnection = new SqlConnection(CONNECTION_STRING)) 12 | { 13 | sqlConnection.Open(); 14 | return $"My template worked"; 15 | } 16 | return $"My template failed"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Runtime/ExecutionContext/ExecutionContext.cs: -------------------------------------------------------------------------------- 1 | namespace CodegenCS.Runtime 2 | { 3 | /// 4 | /// Provides information about the template being executed 5 | /// 6 | public class ExecutionContext 7 | { 8 | /// 9 | /// Full path of the Template being executed 10 | /// 11 | public string TemplatePath { get; set; } // DLL or CS? Why not have both? 12 | public string CurrentDirectory { get; set; } 13 | public ExecutionContext(string templatePath, string currentDirectory) 14 | { 15 | TemplatePath = templatePath; 16 | CurrentDirectory = currentDirectory; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Models/CodegenCS.Models.DbSchema/NuGetReadMe.md: -------------------------------------------------------------------------------- 1 | # CodegenCS.Models.DbSchema 2 | 3 | This is an InputModel (Schema) to be used with CodegenCS code generator, which allows CodegenCS to generate code based on a Database Schema. 4 | 5 | Basically it contains classes to represent the Database Schema, and there's another project with Schema Reader classes (MSSQL and PostgreSQL) to extract the Schema from those databases. 6 | 7 | Check out the [main project](https://github.com/Drizin/CodegenCS) to see more information. 8 | 9 | ## Code 10 | [https://github.com/Drizin/CodegenCS/tree/master/src/Models/CodegenCS.Models.DbSchema](https://github.com/Drizin/CodegenCS/tree/master/src/Models/CodegenCS.Models.DbSchema) 11 | 12 | ## License 13 | MIT License 14 | -------------------------------------------------------------------------------- /src/MSBuild/CodegenCS.MSBuild/build/CodegenCS.MSBuild.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | $(MSBuildThisFileDirectory)..\tasks\netstandard2.0 7 | 8 | $(CustomTasksFolder)\$(MSBuildThisFileName).dll 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Core/CodegenCS/CodegenCS.Core.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CodegenCS.Core 5 | CodegenCS.Core 6 | Rick Drizin 7 | Rick Drizin 8 | MIT 9 | https://github.com/Drizin/CodegenCS 10 | false 11 | C# Library for Code Generation 12 | Copyright Rick Drizin 2019 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Models/CodegenCS.Models.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CodegenCS.Models 5 | CodegenCS.Models 6 | Rick Drizin 7 | Rick Drizin 8 | MIT 9 | https://github.com/Drizin/CodegenCS 10 | false 11 | C# Library for Code Generation 12 | Copyright Rick Drizin 2019 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Runtime/CodegenCS.Runtime.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CodegenCS.Runtime 5 | CodegenCS.Runtime 6 | Rick Drizin 7 | Rick Drizin 8 | MIT 9 | https://github.com/Drizin/CodegenCS 10 | false 11 | C# Library for Code Generation 12 | Copyright Rick Drizin 2019 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0024-SubtemplateMarkupToFSFunc.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | FormattableString Main() => $$""" 4 | namespace MyNamespace 5 | { 6 | {{GenerateClass("MyFirstClass", "Rick")}} 7 | } 8 | """; 9 | 10 | // Subtemplates should ideally be a METHOD that returns the type you need. 11 | // (in this case the method returns another interpolated string) 12 | FormattableString GenerateClass(string className, string name) => $$""" 13 | public class {{className}} 14 | { 15 | public {{className}}() 16 | { 17 | } 18 | public void Hello{{name}}() 19 | { 20 | Console.WriteLine("Hello, {{name}}") 21 | } 22 | } 23 | """; 24 | } -------------------------------------------------------------------------------- /src/Core/CodegenCS.Runtime/CommandLine/CommandLineArgsException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CodegenCS.Runtime 4 | { 5 | /// 6 | /// Templates are resolved using dependency injection. If during the template construction (resolving) dotnet-codegencs get an ArgumentException 7 | /// it will show the error message. CommandLineArgsException extends ArgumentException and allows to write a custom help message (with colors etc). 8 | /// 9 | public class CommandLineArgsException : ArgumentException 10 | { 11 | public Action ShowHelp { get; private set; } 12 | public CommandLineArgsException(string errorMessage, Action showHelp) : base(errorMessage) 13 | { 14 | ShowHelp = showHelp; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.DotNet/CodegenCS.DotNet.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CodegenCS.DotNet 5 | CodegenCS.DotNet 6 | Rick Drizin 7 | Rick Drizin 8 | MIT 9 | https://github.com/Drizin/CodegenCS 10 | false 11 | C# Library for Code Generation - .NET and Visual Studio utilities 12 | Copyright Rick Drizin 2019 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Core/CodegenCS/ControlFlow/ElseSymbol.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Text; 5 | 6 | namespace CodegenCS.ControlFlow 7 | { 8 | [DebuggerDisplay("[ELSE({IfConditionValue,nq})]")] 9 | public class ElseSymbol : IControlFlowSymbol 10 | { 11 | public bool? IfConditionValue { get; set; } 12 | public ElseSymbol() // empty constructor is invoked by the template-text static getter, since the text doesn't know the previous if condition 13 | { 14 | } 15 | internal ElseSymbol(bool ifConditionValue) // but when this is processed by the TextWriter we have to check the current IF block and we know the state 16 | { 17 | IfConditionValue = ifConditionValue; 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Models/IModelFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace CodegenCS.Models 5 | { 6 | /// 7 | /// Can be injected into any template and can be used to load models from file. 8 | /// Loading can be just a deserialization or can use an that describes a custom factory for loading third-party models 9 | /// 10 | public interface IModelFactory 11 | { 12 | Task LoadModelFromFileAsync(string filePath); 13 | TModel LoadModelFromFile(string filePath); 14 | Task LoadModelFromFileAsync(Type modelType, string filePath); 15 | object LoadModelFromFile(Type modelType, string filePath); 16 | bool CanCreateModel(Type modelType); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Samples/MSBuild1/Template3.csx: -------------------------------------------------------------------------------- 1 | // Sample template that writes programmatically to multiple files 2 | 3 | class Template3 4 | { 5 | void Main(ICodegenContext context) 6 | { 7 | var classes = new string[] { "Class1", "Class2", "Class3" }; 8 | 9 | foreach (var className in classes) 10 | { 11 | context[$"{className}.g.cs"].Write(GenerateClass("MyNamespace", className)); 12 | } 13 | } 14 | 15 | FormattableString GenerateClass(string ns, string className) => $$""" 16 | namespace {{ns}} 17 | { 18 | partial class {{className}} 19 | { 20 | public void Initialize() 21 | { 22 | // This method is generated on the fly! 23 | } 24 | } 25 | } 26 | """; 27 | } 28 | -------------------------------------------------------------------------------- /Samples/MSBuild2/Template3.csx: -------------------------------------------------------------------------------- 1 | // Sample template that writes programmatically to multiple files 2 | 3 | class Template3 4 | { 5 | void Main(ICodegenContext context) 6 | { 7 | var classes = new string[] { "Class1", "Class2", "Class3" }; 8 | 9 | foreach (var className in classes) 10 | { 11 | context[$"{className}.g.cs"].Write(GenerateClass("MyNamespace", className)); 12 | } 13 | } 14 | 15 | FormattableString GenerateClass(string ns, string className) => $$""" 16 | namespace {{ns}} 17 | { 18 | partial class {{className}} 19 | { 20 | public void Initialize() 21 | { 22 | // This method is generated on the fly! 23 | } 24 | } 25 | } 26 | """; 27 | } 28 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0091-EmbeddedReferences.cs: -------------------------------------------------------------------------------- 1 | // The following #r references will be parsed by RoslynCompiler and the referenced assemblies will be automatically added to the compilation 2 | // Those assemblies can be absolute paths, can be relative to the template, or (most common) can just be looked up inside dotnet assemblies folder 3 | #r "System.Xml.dll" 4 | #r "System.Xml.ReaderWriter.dll" 5 | #r "System.Private.Xml.dll" // only for net5+ (for old .net framework <=net472 comment-out this line) 6 | using System.IO; 7 | using System.Xml; 8 | using System; 9 | 10 | class MyTemplate 11 | { 12 | async Task Main(ILogger logger) 13 | { 14 | XmlDocument doc = new XmlDocument(); 15 | await logger.WriteLineAsync($"Generating MyTemplate..."); 16 | return $"My template worked"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Tools/dotnet-codegencs/ErrorResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.CommandLine.Invocation; 3 | using Console = InterpolatedColorConsole.ColoredConsole; 4 | 5 | namespace CodegenCS.DotNetTool 6 | { 7 | public class ErrorResult : IInvocationResult 8 | { 9 | private readonly string _errorMessage; 10 | private readonly int _errorExitCode; 11 | 12 | public ErrorResult(string errorMessage, int errorExitCode = 1) 13 | { 14 | _errorMessage = errorMessage; 15 | _errorExitCode = errorExitCode; 16 | } 17 | 18 | public void Apply(InvocationContext context) 19 | { 20 | //context.Console.Error.WriteLine(_errorMessage); 21 | Console.WriteLineError(ConsoleColor.Red, "ERROR: " + _errorMessage); 22 | context.ExitCode = _errorExitCode; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0025-SubtemplateProgrammaticToFSFunc.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | void Main(ICodegenOutputFile writer) 4 | { 5 | writer.WriteLine($$""" 6 | namespace MyNamespace 7 | { 8 | {{GenerateClass("MyFirstClass", "Rick")}} 9 | } 10 | """); 11 | } 12 | 13 | // Subtemplates should ideally be a METHOD that returns the type you need. 14 | // (in this case the method returns another interpolated string) 15 | FormattableString GenerateClass(string className, string name) => $$""" 16 | public class {{className}} 17 | { 18 | public {{className}}() 19 | { 20 | } 21 | public void Hello{{name}}() 22 | { 23 | Console.WriteLine("Hello, {{name}}") 24 | } 25 | } 26 | """; 27 | } -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0073-IEnumerable-Nested-Lists.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | FormattableString RenderTable(Table table) => $$""" 4 | /// 5 | /// POCO for {{table.TableName}} 6 | /// 7 | public class {{table.TableName}} 8 | { 9 | // class members... 10 | {{table.Columns.Select(column => (FormattableString)$$"""public {{column.ClrType}} {{column.ColumnName}} { get; set; }""").Render()}} 11 | } 12 | """; 13 | 14 | void Main(ICodegenOutputFile w, IModelFactory factory) 15 | { 16 | var schema = factory.LoadModelFromFile(@"Models\AdventureWorks.json"); 17 | 18 | w.WriteLine($$""" 19 | namespace MyNamespace 20 | { 21 | {{schema.Tables.Select(t => RenderTable(t)).Render()}} 22 | } 23 | """); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [Drizin] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 15 | -------------------------------------------------------------------------------- /Samples/PrebuildEvent/PrebuildEvent.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0040-ImplicitIndent.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | string myNamespace = "CodegenCS.Sample"; 4 | string className = "MyAutogeneratedClass"; 5 | string methodName = "HelloCodeGenerationWorld"; 6 | 7 | FormattableString Main() => $$""" 8 | namespace {{myNamespace}} 9 | { 10 | {{myClass}} 11 | } 12 | """; 13 | 14 | FormattableString myClass() => $$""" 15 | public class {{className}} 16 | { 17 | {{myMethod}} 18 | } 19 | """; 20 | 21 | FormattableString myMethod() => $$""" 22 | public void {{methodName}}() 23 | { 24 | Console.WriteLine("Hello World"); 25 | } 26 | """; 27 | 28 | // this example uses a "markup" approach (most methods are just returning text blocks) 29 | // but it would work similarly if you were manually calling CodegenTextWriter Write() or WriteLine() 30 | } 31 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0061-Symbols-IF-ELSE.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | void Main(ICodegenOutputFile writer) 4 | { 5 | var settings = new MySettings() { SwallowExceptions = true }; 6 | RenderMyApiClient(writer, settings); 7 | } 8 | class MySettings 9 | { 10 | public bool SwallowExceptions; 11 | } 12 | void RenderMyApiClient(ICodegenOutputFile w, MySettings settings) 13 | { 14 | w.WriteLine($$""" 15 | public class MyApiClient 16 | { 17 | public void InvokeApi() 18 | { 19 | try 20 | { 21 | restApi.Invoke(); 22 | } 23 | catch (Exception ex) 24 | { {{IF(settings.SwallowExceptions)}} 25 | Log.Error(ex); {{ELSE}} 26 | throw; {{ENDIF}} 27 | } 28 | } 29 | } 30 | """); 31 | } 32 | } -------------------------------------------------------------------------------- /src/Core/CodegenCS.Runtime/Logging/DebugOutputLogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | using System.Threading.Tasks; 4 | 5 | namespace CodegenCS.Runtime 6 | { 7 | public class DebugOutputLogger : AbstractLogger, ILogger 8 | { 9 | protected override Task InnerWriteAsync(string message) 10 | { 11 | System.Diagnostics.Debug.Write(message); 12 | return Task.CompletedTask; 13 | } 14 | 15 | protected override Task InnerWriteNewLineAsync() 16 | { 17 | System.Diagnostics.Debug.WriteLine(""); 18 | return Task.CompletedTask; 19 | } 20 | 21 | protected override Task RefreshUIAsync() => Task.CompletedTask; 22 | 23 | protected override Task SetBackgroundColorAsync(ConsoleColor color) => Task.CompletedTask; 24 | 25 | protected override Task SetForegroundColorAsync(ConsoleColor color) => Task.CompletedTask; 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Samples/SourceGenerator1/SourceGenerator1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Models/IJsonInputModel.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace CodegenCS.Models 4 | { 5 | /// 6 | /// JSON-based Input Models that are loaded by Command-line tool (dotnet-codegencs) (deserialized from a JSON file) 7 | /// and will be automatically injected into template constructors or entrypoints. 8 | /// 9 | public interface IJsonInputModel : IInputModel 10 | { 11 | } 12 | 13 | /// 14 | /// JSON-based Input Models that have a Schema definition in a public URL and therefore can be validated. 15 | /// 16 | public interface IValidatableJsonInputModel : IJsonInputModel 17 | { 18 | /// 19 | /// Json Schema which uniquely identifies this model. 20 | /// Should follow https://json-schema.org/ specs. 21 | /// Can be a url, can have a version in the url. 22 | /// E.g. "http://codegencs.com/schemas/dbschema/2021-07/dbschema.json" 23 | /// 24 | [JsonProperty("$schema")] 25 | string Schema { get; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Models/JsonInputModelParser.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using NJsonSchema; 3 | using NJsonSchema.Validation; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace CodegenCS.Models 9 | { 10 | /// 11 | /// Parser for JsonInputModels 12 | /// 13 | public class JsonInputModelParser 14 | { 15 | /// 16 | /// Returns if a given model is valid according to Json Schema 17 | /// 18 | public async Task> ValidateSchemaAsync(string jsonSchema, string input) 19 | { 20 | JsonSchema schema = await JsonSchema.FromJsonAsync(jsonSchema); 21 | JObject jObject = JObject.Parse(input); 22 | List errors = new JsonSchemaValidator().Validate(input, schema).ToList(); 23 | 24 | errors.ForEach(error => System.Diagnostics.Debug.WriteLine($"Error {error.Kind} on line {error.LineNumber}")); 25 | 26 | return errors; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Models/CodegenCS.Models.NSwagAdapter/CodegenCS.Models.NSwagAdapter.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CodegenCS.Models.NSwagAdapter 5 | CodegenCS.Models.NSwagAdapter 6 | Rick Drizin 7 | Rick Drizin 8 | MIT 9 | https://github.com/Drizin/CodegenCS/tree/master/src/Models/CodegenCS.Models.NSwagAdapter 10 | false 11 | This is a Model Adapter that allow CodegenCS templates to read OpenAPI models (JSON or YAML format) using NSWag 12 | Copyright Rick Drizin 2019 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Rick Drizin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Samples/SourceGenerator2/SourceGenerator2.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | Exe 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Samples/MSBuild2/Web.config: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0051-Subtemplates-Looping.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | void Main(IModelFactory factory, ICodegenOutputFile writer) 4 | { 5 | // Hold on, we'll explain this shortly 6 | var model = factory.LoadModelFromFile(@"Models\AdventureWorks.json"); 7 | 8 | foreach (var table in model.Tables) 9 | { 10 | writer.WriteLine($$""" 11 | /// 12 | /// POCO for {{table.TableName}} 13 | /// 14 | public class {{table.TableName}} 15 | { 16 | {{RenderColumns.WithArguments(table, null)}}{{Symbols.TLW}} 17 | } 18 | """); 19 | } 20 | } 21 | 22 | // This delegate can't be interpolated directly because it depends on Table type which is not registered 23 | // That's why it's "enriched" with WithArguments that specify that "table" variable should be passed as the first argument 24 | Action RenderColumns = (table, writer) => 25 | { 26 | foreach (var column in table.Columns) 27 | writer.WriteLine($$""" 28 | public {{column.ClrType}} {{column.ColumnName}} { get; set; } 29 | """); 30 | }; 31 | } -------------------------------------------------------------------------------- /Samples/SourceGenerator2/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dapper; 3 | using MyProject.POCOs; // POCOs will be generated (on-the-fly!) under this namespace 4 | 5 | namespace SampleSourceGenerator.Demo 6 | { 7 | partial class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | // If you use CodegenCSOutput="Memory" then it looks like magic: POCOs are just generated on the fly! 12 | // (unfortunately IDE has some bugs and might show errors, but it builds and runs fine! using CodegenCSOutput="File" usually provides better experience) 13 | // If you debug and step-into the next line you'll see the generated POCOs. 14 | 15 | Product product = new Product() { Name = "Tesla Model S", ListPrice = 79990 }; 16 | 17 | using (var cn = IDbConnectionFactory.CreateConnection()) 18 | { 19 | var products = cn.Query("SELECT * FROM Production.Product"); 20 | foreach (var p in products) 21 | Console.WriteLine($"I'll buy a {p.Name} for {p.ListPrice:C}"); 22 | } 23 | 24 | Console.WriteLine("Press enter to exit..."); 25 | Console.ReadLine(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0090-Debugging.cs: -------------------------------------------------------------------------------- 1 | // If you run TemplateBuildTests this is the only unit test that should break into the debugger 2 | // It's possible to break both inside MARKUP mode (interpolating a symbol) or in PROGRAMMATIC mode 3 | class MyTemplate 4 | { 5 | string[] groceries = new string[] { "Milk", "Eggs", "Diet Coke" }; 6 | 7 | // If you run this template using Visual Studio Unit Tests 8 | // it will break into the debugger when it reaches the BREAKIF(true) 9 | FormattableString Main() => $$""" 10 | I have to buy: 11 | {{BREAKIF(true)}}{{groceries}} 12 | Will write some more stuff 13 | {{MethodWithBreak}} 14 | """; 15 | 16 | // If you want to break from inside a method in your template (programmatic mode) 17 | // then you can just use System.Diagnostics.Debugger.Break() and make sure you 18 | // disable "Tools - Debugging - General - Enable Just My Code", in order to break and see the template source code (because it's invoked using reflection so it's considered external code) 19 | void MethodWithBreak(ICodegenOutputFile file) 20 | { 21 | file.WriteLine("writing something here"); 22 | System.Diagnostics.Debugger.Break(); 23 | file.WriteLine("last part"); 24 | } 25 | } -------------------------------------------------------------------------------- /src/Tools/dotnet-codegencs/dotnet-codegencs.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CodegenCS 5 | CodegenCS 6 | Rick Drizin 7 | Rick Drizin 8 | MIT 9 | https://github.com/Drizin/CodegenCS 10 | false 11 | CodegenCS command-line tool to build/run templates, or create dbschema models (extract schema from MSSQL/PostgreSQL database into json files) 12 | Copyright Rick Drizin 2019 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Tests/TemplateTests/3-ICodegenStringTemplate-TestsOutput/Test32/MyDatabase.cs: -------------------------------------------------------------------------------- 1 | /// Auto-Generated by CodegenCS (https://github.com/Drizin/CodegenCS) 2 | /// Copyright Rick Drizin (just kidding - this is MIT license - use however you like it!) 3 | 4 | namespace MyNamespace 5 | { 6 | /// 7 | /// POCO for Users 8 | /// 9 | public class Users 10 | { 11 | /// 12 | /// [dbo].[Users][UserId] (int) 13 | /// 14 | public int UserId { get; set; } 15 | 16 | /// 17 | /// [dbo].[Users][FirstName] (nvarchar) 18 | /// 19 | public string FirstName { get; set; } 20 | 21 | /// 22 | /// [dbo].[Users][LastName] (nvarchar) 23 | /// 24 | public string LastName { get; set; } 25 | } 26 | 27 | /// 28 | /// POCO for Users 29 | /// 30 | public class Products 31 | { 32 | /// 33 | /// [dbo].[Products][Description] (int) 34 | /// 35 | public int Description { get; set; } 36 | 37 | /// 38 | /// [dbo].[Products][ProductId] (nvarchar) 39 | /// 40 | public string ProductId { get; set; } 41 | } 42 | } -------------------------------------------------------------------------------- /src/Models/CodegenCS.Models.DbSchema/CodegenCS.Models.DbSchema.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CodegenCS.Models.DbSchema 5 | CodegenCS.Models.DbSchema 6 | Rick Drizin 7 | Rick Drizin 8 | MIT 9 | https://github.com/Drizin/CodegenCS/tree/master/src/Models/CodegenCS.Models.DbSchema 10 | false 11 | This is a Plugin (Datasource Provider) to be used with CodegenCS code generator, which allows CodegenCS to generate code based on a Database Schema. Repository (Github) contains Code and Scripts to extract schema from SQL database into json files, and this schema can be used by any application. 12 | Copyright Rick Drizin 2019 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Models/CodegenCS.Models.DbSchema/DbSchema/Table.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace CodegenCS.Models.DbSchema 4 | { 5 | public class Table 6 | { 7 | public string Database { get; set; } 8 | public string TableSchema { get; set; } 9 | public string TableName { get; set; } 10 | 11 | /// 12 | /// Can be "TABLE" or "VIEW" 13 | /// 14 | public string TableType { get; set; } 15 | 16 | public string TableDescription { get; set; } 17 | 18 | public List Columns { get; set; } = new List(); 19 | 20 | /// 21 | /// FKs which point from THIS (Child) table to the primary key of OTHER (Parent) tables 22 | /// 23 | public List ForeignKeys { get; set; } = new List(); 24 | 25 | /// 26 | /// FKs which point from OTHER (Child) tables to the primary key of THIS (Parent) table 27 | /// 28 | public List ChildForeignKeys { get; set; } = new List(); 29 | 30 | public string PrimaryKeyName { get; set; } 31 | 32 | public bool PrimaryKeyIsClustered { get; set; } 33 | 34 | public List Indexes { get; set; } = new List(); 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Runtime/DependencyContainerExtensions.cs: -------------------------------------------------------------------------------- 1 | using DependencyContainer = CodegenCS.Utils.DependencyContainer; 2 | 3 | namespace CodegenCS.Runtime 4 | { 5 | public static class DependencyContainerExtensions 6 | { 7 | public static DependencyContainer AddConsole(this DependencyContainer dependencyContainer, string[] args = null) 8 | { 9 | dependencyContainer.RegisterCustomTypeResolver(new AutoBindCommandLineArgsTypeResolver()); // break into AddAutoBindCommandLineArgs ? 10 | dependencyContainer.RegisterSingleton(new ColoredConsoleLogger()); 11 | if (args != null) 12 | dependencyContainer.RegisterSingleton(new CommandLineArgs(args)); 13 | return dependencyContainer; 14 | } 15 | internal static DependencyContainer AddTestsConsole(this DependencyContainer dependencyContainer, string[] args = null) 16 | { 17 | dependencyContainer.RegisterCustomTypeResolver(new AutoBindCommandLineArgsTypeResolver()); 18 | dependencyContainer.RegisterSingleton(new DebugOutputLogger()); 19 | if (args != null) 20 | dependencyContainer.RegisterSingleton(new CommandLineArgs(args)); 21 | return dependencyContainer; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Samples/MSBuild2/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /src/Core/CodegenCS/Utils/IOUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace CodegenCS.Utils 5 | { 6 | public class IOUtils 7 | { 8 | 9 | //https://stackoverflow.com/a/340454/3606250 10 | public static String MakeRelativePath(String fromPath, String toPath) 11 | { 12 | if (String.IsNullOrEmpty(fromPath)) throw new ArgumentNullException("fromPath"); 13 | if (String.IsNullOrEmpty(toPath)) throw new ArgumentNullException("toPath"); 14 | 15 | Uri fromUri = new Uri(fromPath); 16 | Uri toUri = new Uri(toPath); 17 | 18 | if (fromUri.Scheme != toUri.Scheme) { return toPath; } // path can't be made relative. 19 | 20 | Uri relativeUri = fromUri.MakeRelativeUri(toUri); 21 | String relativePath = Uri.UnescapeDataString(relativeUri.ToString()); 22 | 23 | if (toUri.Scheme.Equals("file", StringComparison.InvariantCultureIgnoreCase)) 24 | { 25 | relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); 26 | } 27 | 28 | return relativePath; 29 | } 30 | public static String MakeRelativePath(String toPath) 31 | { 32 | string fromPath = Directory.GetCurrentDirectory() + "\\"; 33 | return MakeRelativePath(fromPath, toPath); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/VisualStudio/reset-experimental-visualstudio.ps1: -------------------------------------------------------------------------------- 1 | # How to Reset the Visual Studio 2022 Experimental Instance: 2 | & "C:\Program Files\Microsoft Visual Studio\2022\Professional\VSSDK\VisualStudioIntegration\Tools\Bin\CreateExpInstance.exe" /Reset /VSInstance=17.0_defe2a84 /RootSuffix=Exp 3 | & "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VSSDK\VisualStudioIntegration\Tools\Bin\CreateExpInstance.exe" /Reset /VSInstance=16.0_8ff8e53a /RootSuffix=Exp 4 | 5 | # delete extensions from %LOCALAPPDATA%\Microsoft\VisualStudio\ 6 | # C:\Users\drizi\AppData\Local\Microsoft\VisualStudio\16.0_8ff8e53aExp\Extensions\Rick Drizin 7 | # C:\Users\drizi\AppData\Local\Microsoft\VisualStudio\17.0_defe2a84Exp\Extensions\Rick Drizin 8 | Get-ChildItem ${env:LOCALAPPDATA}\Microsoft\VisualStudio -Recurse | Where{$_.FullName -Match ".*\\Rick Drizin$"} | Remove-Item -Force 9 | 10 | # How to install VSIX extension (not in the experimental instance!): 11 | #$vsixinstaller = "C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\VSIXInstaller.exe" 12 | $vsixinstaller = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\VSIXInstaller.exe" 13 | $configuration="Debug" 14 | # & $vsixinstaller /quiet "VisualStudio\VS2019Extension\bin\$configuration\CodegenCS-VS2019Extension.vsix" 15 | # & $vsixinstaller /quiet "VisualStudio\VS2022Extension\bin\$configuration\CodegenCS-VS2022Extension.vsix" 16 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Tests/DotNet/DotNetCodegenContextTests.cs: -------------------------------------------------------------------------------- 1 | using CodegenCS; 2 | using CodegenCS.DotNet; 3 | using NUnit.Framework; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace CodegenCS.Tests.DotNet 9 | { 10 | public class DotNetCodegenContextTests 11 | { 12 | DotNetCodegenContext _ctx = null; 13 | 14 | [SetUp] 15 | public void Setup() 16 | { 17 | _ctx = new DotNetCodegenContext(); 18 | } 19 | 20 | 21 | [Test] 22 | public void TestMultipleFiles() 23 | { 24 | // DotNetCodegenContext will automatically set the FileType (BuildActionType) based on the extension 25 | 26 | var f1 = _ctx["File1.cs"]; 27 | var f2 = _ctx["README.TXT"]; 28 | var f3 = _ctx["Transaltions.RESX"]; 29 | 30 | CodegenContext context = (CodegenContext)_ctx; 31 | 32 | Assert.That(_ctx.OutputFiles.Count == 3); 33 | Assert.That(context.OutputFiles.Count == 3); 34 | 35 | f1.WriteLine("Test"); 36 | Assert.That(context["File1.cs"].GetContents().Length > 0); 37 | 38 | Assert.That(f1.FileType == BuildActionType.Compile); 39 | Assert.That(f2.FileType == BuildActionType.None); 40 | Assert.That(f3.FileType == BuildActionType.EmbeddedResource); 41 | } 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Samples/MSBuild2/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /src/build-external.ps1: -------------------------------------------------------------------------------- 1 | [cmdletbinding()] 2 | param( 3 | [Parameter(Mandatory=$False)][ValidateSet('Release','Debug')][string]$configuration 4 | ) 5 | 6 | # How to run: .\build.ps1 or .\build.ps1 -configuration Debug 7 | 8 | 9 | $scriptpath = $MyInvocation.MyCommand.Path 10 | $dir = Split-Path $scriptpath 11 | Push-Location $dir 12 | 13 | if (-not $PSBoundParameters.ContainsKey('configuration')) 14 | { 15 | if (Test-Path Release.snk) { $configuration = "Release"; } else { $configuration = "Debug"; } 16 | } 17 | 18 | 19 | New-Item -ItemType Directory -Force -Path ".\packages-local" 20 | 21 | git submodule init 22 | git pull --recurse-submodules 23 | git submodule update --remote --recursive 24 | 25 | cd External\command-line-api\ 26 | git checkout main 27 | Remove-Item -Recurse ~\.nuget\packages\System.CommandLine* -Force 28 | dotnet clean 29 | 30 | dotnet pack /p:PackageVersion=2.0.0-codegencs -c $configuration 31 | if (! $?) { throw "msbuild failed" } 32 | 33 | copy artifacts\packages\$configuration\Shipping\System.CommandLine.2.0.0-codegencs.nupkg ..\..\packages-local\ 34 | copy artifacts\packages\$configuration\Shipping\System.CommandLine.2.0.0-codegencs.snupkg ..\..\packages-local\ 35 | copy artifacts\packages\$configuration\Shipping\System.CommandLine.NamingConventionBinder.2.0.0-codegencs.nupkg ..\..\packages-local\ 36 | copy artifacts\packages\$configuration\Shipping\System.CommandLine.NamingConventionBinder.2.0.0-codegencs.snupkg ..\..\packages-local\ 37 | 38 | 39 | 40 | Pop-Location 41 | -------------------------------------------------------------------------------- /src/Core/CodegenCS/Templating/InlineTemplateLoader.cs: -------------------------------------------------------------------------------- 1 | using CodegenCS.___InternalInterfaces___; 2 | 3 | namespace CodegenCS 4 | { 5 | /// 6 | /// This is used as context (TContext) of , 7 | /// allowing to have extensions according to the context (, or ). 8 | /// 9 | public class InlineTemplateLoader 10 | { 11 | } 12 | 13 | /// 14 | /// Inside the interpolated strings of any template we can just call Template.Load{TTemplate}().Render(model). 15 | /// Requires "using CodegenCS;" 16 | /// 17 | public partial class Template 18 | { 19 | /// 20 | /// Loads a template by the Type (class name). Allow to pass dependencies required by the template. 21 | /// 22 | /// Template type 23 | /// Optional dependencies that will be injected if the template constructor requires it 24 | public static IContextedTemplateWrapper Load(params object[] dependencies) where TTemplate : IBaseTemplate 25 | { 26 | return new ContextedTemplateWrapper(typeof(TTemplate), dependencies); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/MSBuild/README.md: -------------------------------------------------------------------------------- 1 | **CodegenCS is a Toolkit for doing Code Generation using plain C#**. 2 | 3 | Before anything else, don't forget to read the [Main Project Page](https://github.com/Drizin/CodegenCS/) to learn the basics (basic idea, basic features, and major components). 4 | 5 | This page is only about **CodegenCS Source Generator**: 6 | 7 | 8 | # CodegenCS MSBuild Task 9 | 10 | Our [MSBuild Task](https://nuget.org/packages/CodegenCS.MSBuild) allows running templates on-the-fly during compilation. 11 | 12 | MSBuild Task `CodegenBuildTask` is automatically invoked during `BeforeCompile` target, will search for `*.csx` files in the project folder and will run each one. 13 | Files are physically saved to disk and will be automatically added to your compilation. 14 | 15 | 16 | ## Quickstart 17 | 18 | 1. Install nuget `CodegenCS.MSBuild` to your project 19 | ```xml 20 | 21 | 22 | 23 | ``` 24 | 25 | 1. Create a CodegenCS template in your project (name it with `CSX` extension). Example: 26 | ```cs 27 | class Template 28 | { 29 | void Main(ICodegenContext context) 30 | { 31 | context[$"MyClass1.g.cs"].Write($$""" 32 | public class MyClas1 33 | { 34 | } 35 | """); 36 | } 37 | } 38 | ``` 39 | See full examples: [SDK-project](/Samples/MSBuild1/) and [non-SDK-project](/Samples/MSBuild2/). 40 | -------------------------------------------------------------------------------- /Samples/MSBuild2/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WebApplication2")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WebApplication2")] 13 | [assembly: AssemblyCopyright("Copyright © 2024")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("627fee9e-d108-4480-a8a3-a4f5ca0b05ed")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /src/build-clean.ps1: -------------------------------------------------------------------------------- 1 | $scriptpath = $MyInvocation.MyCommand.Path 2 | $dir = Split-Path $scriptpath 3 | Push-Location $dir 4 | 5 | 6 | try { 7 | 8 | Remove-Item -Recurse -Force -ErrorAction Ignore ".\packages-local" 9 | Remove-Item -Recurse -Force -ErrorAction Ignore "$env:HOMEDRIVE$env:HOMEPATH\.nuget\packages\codegencs" 10 | Remove-Item -Recurse -Force -ErrorAction Ignore "$env:HOMEDRIVE$env:HOMEPATH\.nuget\packages\codegencs.*" 11 | 12 | #Remove-Item -Recurse -Force -ErrorAction Ignore ".\External\command-line-api\artifacts\packages\Debug\Shipping\" 13 | #Remove-Item -Recurse -Force -ErrorAction Ignore ".\External\command-line-api\artifacts\packages\Release\Shipping\" 14 | 15 | 16 | # when target frameworks are added/modified dotnet clean might fail and we may need to cleanup the old dependency tree 17 | Remove-Item -Recurse -Force -ErrorAction Ignore ".\vs" 18 | Get-ChildItem .\ -Recurse | Where{$_.FullName -CMatch ".*\\bin$" -and $_.PSIsContainer} | Remove-Item -Recurse -Force -ErrorAction Ignore 19 | Get-ChildItem .\ -Recurse | Where{$_.FullName -CMatch ".*\\obj$" -and $_.PSIsContainer} | Remove-Item -Recurse -Force -ErrorAction Ignore 20 | Get-ChildItem .\ -Recurse | Where{$_.FullName -Match ".*\\obj\\.*project.assets.json$"} | Remove-Item 21 | #Get-ChildItem .\ -Recurse | Where{$_.FullName -Match ".*\.csproj$" -and $_.FullName -NotMatch ".*\\VSExtensions\\" } | ForEach { dotnet clean $_.FullName } 22 | #dotnet clean .\CodegenCS.sln 23 | New-Item -ItemType Directory -Force -Path ".\packages-local" 24 | 25 | } finally { 26 | Pop-Location 27 | } 28 | -------------------------------------------------------------------------------- /src/build-include.ps1: -------------------------------------------------------------------------------- 1 | 2 | $msbuild = ( 3 | "$Env:programfiles\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\msbuild.exe", 4 | "$Env:programfiles\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\msbuild.exe", 5 | "$Env:programfiles\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\msbuild.exe", 6 | "$Env:programfiles (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe", 7 | "$Env:programfiles (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin\msbuild.exe", 8 | "$Env:programfiles (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\msbuild.exe", 9 | "$Env:programfiles (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\msbuild.exe", 10 | "$Env:programfiles (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\msbuild.exe", 11 | "$Env:programfiles (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\msbuild.exe", 12 | "$Env:programfiles (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\msbuild.exe", 13 | "${Env:ProgramFiles(x86)}\MSBuild\14.0\Bin\MSBuild.exe", 14 | "${Env:ProgramFiles(x86)}\MSBuild\13.0\Bin\MSBuild.exe", 15 | "${Env:ProgramFiles(x86)}\MSBuild\12.0\Bin\MSBuild.exe" 16 | ) | Where-Object { Test-Path $_ } | Select-Object -first 1 17 | 18 | 19 | $targetNugetExe = "$PSScriptRoot\nuget.exe" 20 | if (-not (Test-Path $targetNugetExe)) { 21 | $sourceNugetExe = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" 22 | Invoke-WebRequest $sourceNugetExe -OutFile $targetNugetExe 23 | Set-Alias nuget $targetNugetExe -Scope Global -Verbose 24 | } 25 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Tests/TemplateTests/1-ICodegenTemplate/ICodegenTemplateTests.cs: -------------------------------------------------------------------------------- 1 | using CodegenCS.Models.DbSchema; 2 | using NUnit.Framework; 3 | 4 | namespace CodegenCS.Tests.TemplateTests; 5 | 6 | /************************************************************************************************************************************************************************/ 7 | /// 8 | /// Simple template: takes a single model, writes to a single file (using the Fluent API), and doesn't include any other template. 9 | /// 10 | class MyPocoTemplate : ICodegenTemplate 11 | { 12 | public void Render(ICodegenTextWriter writer, Table model) 13 | { 14 | writer.Write($$""" 15 | /// 16 | /// POCO for {{model.TableName}} 17 | /// 18 | """); 19 | writer.WithCurlyBraces($$"""public class {{model.TableName}}""", (w) => 20 | { 21 | foreach (var column in model.Columns) 22 | { 23 | w.WriteLine($"public {column.ClrType} {column.ColumnName} {{ get; set; }}"); 24 | } 25 | }); 26 | } 27 | } 28 | 29 | partial class ICodegenTemplateTests : BaseTest 30 | { 31 | [Test] 32 | public void Test01() 33 | { 34 | var model = base.MyDbSchema; 35 | 36 | var writer = new CodegenTextWriter(); // or you can use: var ctx = new CodegenContext(); var writer = ctx["YourFile.cs"]; 37 | writer.LoadTemplate().Render(model.Tables[0]); 38 | 39 | Assert_That_Content_IsEqual_To_File(writer, @"Users.cs"); 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.DotNet/ProjectType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace CodegenCS.DotNet 10 | { 11 | /// 12 | /// There are basically 2 types of .NET Projects: SDK-Style, Non-SDK-Style (or Legacy)
13 | /// Those types do not have a special extension - they can be csproj, vbproj, etc.
14 | /// The Non-SDK style was the most popular until Visual Studio 2015, and is more complex because it describes all files.
15 | /// The SDK style started with MSBuild 15 (Visual Studio 2017), and is more modern and more concise since it doesn't require to describe all files in the project.
16 | /// The SDK style also replaces the old XPROJ/Project.JSON format which was introduced with NETCORE but is barely used now. 17 | ///
18 | public enum ProjectType 19 | { 20 | /// 21 | /// MSBuild SDK-Style is the new .NET Standard - these project files auto-include files with certain extensions automatically from the project folder.
22 | /// This change has been introduced with MSBuld 15 (Visual Studio 2017 /NetStandard /.NET Core) and makes it much easier to maintain project files.
23 | ///
24 | SDKStyle, 25 | 26 | /// 27 | /// MSBuild Non-SDK-Style is the traditional project format, now considered legacy. It's more verbose than the new SDK-Style. 28 | /// 29 | NonSDKStyle, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Models/CodegenCS.Models.DbSchema/DbSchema/Index.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace CodegenCS.Models.DbSchema 5 | { 6 | public class Index 7 | { 8 | public string IndexName { get; set; } 9 | 10 | public int IndexId { get; set; } 11 | 12 | /// 13 | /// CLUSTERED 14 | /// NONCLUSTERED 15 | /// XML 16 | /// HEAP 17 | /// SPATIAL 18 | /// CLUSTERED COLUMNSTORE (SQL Server 2014 (12.x) and later) 19 | /// NONCLUSTERED COLUMNSTORE (SQL Server 2012 (11.x) and later) 20 | /// NONCLUSTERED HASH (SQL Server 2014 (12.x) and later) 21 | /// 22 | public string PhysicalType { get; set; } 23 | 24 | /// 25 | /// PRIMARY_KEY 26 | /// UNIQUE_INDEX 27 | /// UNIQUE_CONSTRAINT 28 | /// NON_UNIQUE_INDEX 29 | /// 30 | public string LogicalType { get; set; } 31 | 32 | 33 | [Obsolete("Please prefer using LogicalType property")] 34 | public bool IsPrimaryKey { get; set; } 35 | 36 | [Obsolete("Please prefer using LogicalType property")] 37 | public bool IsUnique { get; set; } 38 | 39 | [Obsolete("Please prefer using LogicalType property. Unique Constraints are maintained through a unique Index (IsUnique is also true)")] 40 | public bool IsUniqueConstraint { get; set; } 41 | 42 | public string IndexDescription { get; set; } 43 | 44 | public List Columns { get; set; } 45 | 46 | public override string ToString() => IndexName; // If someone renders the object (index) instead of using the right property 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Runtime/CommandLine/CommandLineArgs.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | 6 | namespace CodegenCS.Runtime 7 | { 8 | /// 9 | /// CommandLineArgs class can be injected in Templates (or any other class) and provide an array of strings all other arguments/options that were not recognized/captured by dotnet-codegencs. 10 | /// Template constructor can validate those arguments and throw ArgumentException for invalid arguments, so that dotnet-codegencs shows the error message. 11 | /// If besides the error message (exception message shown in red) you want to show a custom help message (e.g. show all command-line options, use colors, etc) 12 | /// you can use 13 | /// 14 | /// Other options for passing command-line arguments to templates are (see ) 15 | /// or specifying a "public static void ConfigureCommand(Command command)" (see TemplateLauncher) 16 | /// 17 | public class CommandLineArgs : IReadOnlyList 18 | { 19 | private readonly ReadOnlyCollection _args; 20 | public CommandLineArgs(IEnumerable args) 21 | { 22 | _args = new ReadOnlyCollection(args.ToList()); 23 | } 24 | public string this[int index] => _args[index]; 25 | 26 | public int Count => _args.Count; 27 | 28 | public IEnumerator GetEnumerator() => _args.GetEnumerator(); 29 | 30 | IEnumerator IEnumerable.GetEnumerator() => _args.GetEnumerator(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Samples/SourceGenerator2/SampleSourceGenerator.SimplePocos.DemoProject.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 22 | 23 | all 24 | runtime; build; native; contentfiles; analyzers; buildtransitive 25 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0050-Subtemplates-Delegates.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | FormattableString Main() => $$""" 4 | public class MyClass 5 | { 6 | {{Subtemplate1}} 7 | {{Subtemplate2}} 8 | {{Subtemplate3}}{{Subtemplate4}} 9 | } 10 | """; 11 | 12 | void Subtemplate1(ICodegenOutputFile writer) 13 | { 14 | // Write instead of WriteLine since the outer template already adds linebreak after this 15 | writer.Write("This goes to stdout, same stream started by Main()"); 16 | } 17 | 18 | // Same effect as previous, but using explicit delegate (Func) instead of inferring from a regular void 19 | Func Subtemplate2 = (writer) => 20 | { 21 | writer.WriteLine("This also goes to stdout, same stream started by Main()"); 22 | return $"This will also go to stdout"; 23 | }; 24 | 25 | // Same effect, but returning a FormattableString directly so it goes directly into the same output stream 26 | Func Subtemplate3 = () => $$""" 27 | This goes to stdout, same stream started by Main() 28 | """; 29 | 30 | void Subtemplate4(ICodegenContext context) 31 | { 32 | context["Class1.cs"].WriteLine($$""" 33 | // Class1 is a new stream (different file) 34 | {{Subtemplate5}} 35 | """); 36 | } 37 | 38 | // ICodegenOutputFile (stdout) will be "Class1.cs" since Subtemplate5 was embedded in Subtemplate4 39 | // (in other words ICodegenOutputFile depends on the current context) 40 | Action Subtemplate5 = (writer) => writer.Write($$""" 41 | public class Class1() 42 | { 43 | // ... 44 | } 45 | """); 46 | } 47 | -------------------------------------------------------------------------------- /src/VisualStudio/CodegenCS.Runtime.VisualStudio/ExecutionContext/VSExecutionContext.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using IOUtils = CodegenCS.Utils.IOUtils; 3 | 4 | namespace CodegenCS.Runtime 5 | { 6 | /// 7 | /// Provides information about the template being executed in Visual Studio 8 | /// 9 | public class VSExecutionContext : ExecutionContext 10 | { 11 | /// 12 | /// Full path of the Visual Studio Project that contains the template being executed 13 | /// 14 | public string ProjectPath { get; set; } 15 | 16 | /// 17 | /// Full path of the Visual Studio Solution that contains the template being executed 18 | /// 19 | public string SolutionPath { get; set; } 20 | 21 | public string TemplateRelativePath { get; set; } 22 | 23 | //TODO: ProjectNamespace: 24 | // first try Properties.Item("DefaultNamespace") - https://github.com/dotnet/roslyn/blob/afd10305a37c0ffb2cfb2c2d8446154c68cfa87a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioProjectManagementService.cs#L50 25 | // else $(MSBuildProjectName.Replace(" ", "_")) 26 | 27 | // TODO: TemplateCalculatedNamespace - based on ProjectNamespace and TemplateRelativePath 28 | 29 | public VSExecutionContext(string templatePath, string projectPath, string solutionPath) : base(templatePath, null) // no point in passing Directory.GetCurrentDirectory() from VS Extension 30 | { 31 | ProjectPath = projectPath; 32 | SolutionPath = solutionPath; 33 | TemplateRelativePath = IOUtils.MakeRelativePath(new FileInfo(this.ProjectPath).Directory.FullName + Path.DirectorySeparatorChar, this.TemplatePath); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Models/CodegenCS.Models.DbSchema/DbSchema/Column.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Reflection; 3 | 4 | namespace CodegenCS.Models.DbSchema 5 | { 6 | public class Column 7 | { 8 | public string ColumnName { get; set; } 9 | 10 | public int OrdinalPosition { get; set; } 11 | 12 | public string DefaultSetting { get; set; } 13 | 14 | public bool IsNullable { get; set; } 15 | 16 | public string SqlDataType { get; set; } 17 | 18 | /// 19 | /// CLR Type which is equivalent to the SqlDataType 20 | /// 21 | public string ClrType { get; set; } 22 | 23 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 24 | public int? MaxLength { get; set; } 25 | 26 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 27 | public int? DateTimePrecision { get; set; } 28 | 29 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 30 | public int? NumericScale { get; set; } 31 | 32 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 33 | public int? NumericPrecision { get; set; } 34 | 35 | public bool IsIdentity { get; set; } 36 | 37 | public bool IsComputed { get; set; } 38 | 39 | public bool IsRowGuid { get; set; } 40 | 41 | public bool IsPrimaryKeyMember { get; set; } 42 | 43 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 44 | public int? PrimaryKeyOrdinalPosition { get; set; } 45 | 46 | public bool IsForeignKeyMember { get; set; } 47 | 48 | public string ColumnDescription { get; set; } 49 | 50 | public override string ToString() => ColumnName; // If someone renders the column object instead of using the right property 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Runtime/Logging/ILogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace CodegenCS.Runtime 5 | { 6 | /// 7 | /// Reusable tools should write all output to this interface. 8 | /// Templates can also use this to write to output. 9 | /// For CLI (dotnet-codegencs) this is implemented by an adapter that writes to InterpolatedColorConsole.ColoredConsole. 10 | /// For VS Extensions this is implemented by an adapter that writes to custom IVsOutputWindowPane. 11 | /// The implementations should handle embedded (interpolated) colors (e.g. ColoredConsole supports colors) or discard embedded colors. 12 | /// 13 | public interface ILogger 14 | { 15 | Task WriteLineAsync(); 16 | Task WriteLineAsync(FormattableString value); 17 | Task WriteLineAsync(RawString value); 18 | Task WriteLineAsync(ConsoleColor foregroundColor, FormattableString value); 19 | Task WriteLineAsync(ConsoleColor foregroundColor, ConsoleColor backgroundColor, FormattableString value); 20 | Task WriteLineAsync(ConsoleColor foregroundColor, RawString value); 21 | Task WriteLineAsync(ConsoleColor foregroundColor, ConsoleColor backgroundColor, RawString value); 22 | 23 | Task WriteLineErrorAsync(); 24 | Task WriteLineErrorAsync(FormattableString value); 25 | Task WriteLineErrorAsync(RawString value); 26 | Task WriteLineErrorAsync(ConsoleColor foregroundColor, FormattableString value); 27 | Task WriteLineErrorAsync(ConsoleColor foregroundColor, ConsoleColor backgroundColor, FormattableString value); 28 | Task WriteLineErrorAsync(ConsoleColor foregroundColor, RawString value); 29 | Task WriteLineErrorAsync(ConsoleColor foregroundColor, ConsoleColor backgroundColor, RawString value); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/VisualStudio/CodegenCS.Runtime.VisualStudio/Logging/VsOutputWindowPaneOutputLogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Task = System.Threading.Tasks.Task; 3 | using Microsoft.VisualStudio.Shell.Interop; 4 | using Microsoft.VisualStudio.Threading; 5 | 6 | namespace CodegenCS.Runtime 7 | { 8 | public class VsOutputWindowPaneOutputLogger : AbstractLogger, ILogger 9 | { 10 | protected readonly IVsOutputWindowPane _windowPane; 11 | protected readonly JoinableTaskFactory _joinableTaskFactory; 12 | 13 | public VsOutputWindowPaneOutputLogger(IVsOutputWindowPane windowPane, JoinableTaskFactory joinableTaskFactory) 14 | { 15 | this._windowPane = windowPane; 16 | this._joinableTaskFactory = joinableTaskFactory; 17 | } 18 | public VsOutputWindowPaneOutputLogger(IVsOutputWindowPane windowPane) : this(windowPane, null) 19 | { 20 | this._windowPane = windowPane; 21 | } 22 | 23 | protected override async Task InnerWriteAsync(string message) 24 | { 25 | if (this._joinableTaskFactory != null) 26 | await this._joinableTaskFactory.SwitchToMainThreadAsync(); 27 | this._windowPane.OutputStringThreadSafe(message); 28 | } 29 | 30 | protected override async Task InnerWriteNewLineAsync() 31 | { 32 | if (this._joinableTaskFactory != null) 33 | await this._joinableTaskFactory.SwitchToMainThreadAsync(); 34 | this._windowPane.OutputStringThreadSafe(Environment.NewLine); 35 | } 36 | 37 | protected override async Task RefreshUIAsync() => await Task.Delay(1); 38 | 39 | protected override Task SetBackgroundColorAsync(ConsoleColor color) => Task.CompletedTask; 40 | 41 | protected override Task SetForegroundColorAsync(ConsoleColor color) => Task.CompletedTask; 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Runtime/CommandLine/AutoBindCommandLineArgsTypeResolver.cs: -------------------------------------------------------------------------------- 1 | using DependencyContainer = CodegenCS.Utils.DependencyContainer; 2 | using System; 3 | using System.CommandLine.Binding; 4 | using System.CommandLine.NamingConventionBinder; 5 | using static CodegenCS.Utils.DependencyContainer; 6 | 7 | namespace CodegenCS.Runtime 8 | { 9 | /// 10 | /// Any class implementing IModelBinderArgs will be automatically resolved using ModelBinder, 11 | /// which binds (by matching their names) all class properties to the command-line Arguments and Options. 12 | /// Example: Templates may expect a TemplateArgs class, and those properties can be passed using command-line arguments. 13 | /// 14 | /// Other options for passing command-line arguments to templates are 15 | /// or specifying a "public static void ConfigureCommand(Command command)" (see TemplateLauncher) 16 | /// 17 | public class AutoBindCommandLineArgsTypeResolver : ITypeResolver 18 | { 19 | public bool CanResolveType(Type targetType) 20 | { 21 | return typeof(IAutoBindCommandLineArgs).IsAssignableFrom(targetType); 22 | } 23 | 24 | public bool TryResolveType(Type targetType, DependencyContainer dependencyContainer, out object value) 25 | { 26 | var binder = new ModelBinder(targetType); 27 | try 28 | { 29 | BindingContext bindingContext = (BindingContext)dependencyContainer.Resolve(typeof(BindingContext)); 30 | // create an instance of MyTemplateArgs based on the parsed command line 31 | value = binder.CreateInstance(bindingContext); 32 | return true; 33 | } 34 | catch 35 | { 36 | value = null; 37 | return false; 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Core/CodegenCS.Tests/CoreTests/60-FormattingTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Linq; 4 | using Assert = NUnit.Framework.Legacy.ClassicAssert; 5 | 6 | namespace CodegenCS.Tests.CoreTests 7 | { 8 | public class FormattingTests 9 | { 10 | CodegenTextWriter _w = null; 11 | 12 | #region Setup 13 | [SetUp] 14 | public void Setup() 15 | { 16 | _w = new CodegenTextWriter(); 17 | } 18 | #endregion 19 | 20 | #region IFormattable 21 | 22 | [Test] 23 | public void TestFormat1() 24 | { 25 | decimal amount = 100.00m; 26 | _w.Write($"Price: {amount:000}"); 27 | Assert.AreEqual("Price: 100", _w.GetContents()); 28 | } 29 | 30 | [Test] 31 | public void TestFormat2() 32 | { 33 | decimal amount = .34m; 34 | _w.Write($"Price: {amount:000.00}"); 35 | Assert.AreEqual("Price: 000.34", _w.GetContents()); 36 | } 37 | 38 | [Test] 39 | public void TestFormat3() 40 | { 41 | decimal[] prices = new decimal[] { .34m, .55m, 3.693m }; 42 | Action writeFn = (w) => prices.ToList().ForEach(p => w.WriteLine($"Price: {p:000.0000}")); 43 | _w.Write(writeFn); 44 | string expected = @" 45 | Price: 000.3400 46 | Price: 000.5500 47 | Price: 003.6930 48 | ".TrimStart(Environment.NewLine.ToCharArray()); 49 | Assert.AreEqual(expected, _w.GetContents()); 50 | } 51 | 52 | [Test] 53 | public void TestFormat4() 54 | { 55 | int val = 1; 56 | _w.Write($"11 elements: {val}{val}{val}{val}{val}{val}{val}{val}{val}{val}{val}"); 57 | Assert.AreEqual("11 elements: 11111111111", _w.GetContents()); 58 | } 59 | 60 | 61 | 62 | #endregion 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/MSBuild/CodegenCS.MSBuild/build/CodegenCS.MSBuild.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Samples/PrebuildEvent/RunTemplates.ps1: -------------------------------------------------------------------------------- 1 | $expectedVersion="3.5.0" 2 | 3 | # How to install tool globally: 4 | # dotnet tool install --global dotnet-codegencs --version $expectedVersion 5 | 6 | # Let's check if it's already there 7 | #$alreadyInstalled = $(dotnet tool list -g dotnet-codegencs) | out-string -stream | select-string $expectedVersion 8 | $codegencs = "$($env:USERPROFILE)\.dotnet\tools\dotnet-codegencs.exe" 9 | 10 | # If not there install globally 11 | if (-not (Test-Path $codegencs)) { 12 | dotnet tool install --global dotnet-codegencs --version $expectedVersion 13 | $codegencs = "$($env:USERPROFILE)\.dotnet\tools\dotnet-codegencs.exe" 14 | } 15 | 16 | # Or if global installation failed install locally (in a manifest) 17 | if (-not (Test-Path $codegencs)) { 18 | dotnet new tool-manifest 19 | dotnet tool install dotnet-codegencs --version $expectedVersion 20 | $codegencs = "dotnet-codegencs" # all tools added to the manifest will be automatically available 21 | } 22 | 23 | if (-not (Test-Path $codegencs)) { throw "can't find dotnet-codegencs" } 24 | 25 | $ErrorActionPreference = "Stop" 26 | 27 | # Download template if not there 28 | if (-not (Test-Path "DapperExtensionPocos.cs")) { 29 | & $codegencs template clone https://raw.githubusercontent.com/CodegenCS/Templates/main/DatabaseSchema/DapperExtensionPocos/DapperExtensionPocos.cs 30 | # equivalent of & $codegencs template clone DapperExtensionPocos 31 | } 32 | 33 | Write-host "Refreshing DB SCHEMA..." -for yellow 34 | #& $codegencs model dbschema extract mssql 'Server=MYSERVER; Database=AdventureWorks; User Id=myUsername;Password=MyPassword' .\AdventureWorksSchema.json 35 | 36 | Write-host "Running DapperExtensionPocos.cs template..." -for yellow 37 | & $codegencs template run DapperExtensionPocos.cs .\AdventureWorksSchema.json "SampleProject.Core.Entities" -o .\GeneratedEntities\ -p:CrudNamespace="SampleProject.Core.Database" -p:CrudFile=".\DapperCrudExtensions.cs" -p:CrudClass="DapperCrudExtensions" -p:TrackPropertiesChange=true 38 | -------------------------------------------------------------------------------- /src/Models/CodegenCS.Models.DbSchema.Extractor/MSSQL/RefreshSqlServerSchema.csx: -------------------------------------------------------------------------------- 1 | /// 2 | /// This CSX Script will invoke SqlServerSchemaReader, which extracts the schema of SQL database and saves into a JSON file. 3 | /// The easiest way to launch csi.exe (which is shipped with Visual Studio) to run this script is by using PowerShell script RefreshDatabaseSchema.ps1 4 | /// You can do that from Visual Studio (see instructions in RefreshDatabaseSchema.ps1) or you can just execute "Powershell RefreshDatabaseSchema.ps1" 5 | /// 6 | 7 | // System libraries 8 | #r "System.Data.dll" 9 | 10 | // Load third-party libraries by their relative paths, relative to "$Env:userprofile\.nuget\packages\" 11 | #r "dapper\2.0.35\lib\netstandard2.0\Dapper.dll" 12 | #r "newtonsoft.json\13.0.1\lib\netstandard2.0\Newtonsoft.Json.dll" 13 | #r "codegencs.models.dbschema\3.0.1\lib\netstandard2.0\CodegenCS.Models.DbSchema.dll" 14 | 15 | // CS files are better than CSX because Intellisense and Compile-time checks works better. 16 | 17 | using System; 18 | using System.IO; 19 | using System.Runtime.CompilerServices; 20 | using System.Data; 21 | using System.Data.SqlClient; 22 | using CodegenCS.DbSchema.SqlServer; 23 | 24 | // Helpers to get the location of the current CSX script 25 | public static string GetScriptPath([CallerFilePath] string path = null) => path; 26 | public static string GetScriptFolder([CallerFilePath] string path = null) => Path.GetDirectoryName(path); 27 | 28 | 29 | // location relative to the CSX script 30 | string outputJsonSchema = Path.GetFullPath(Path.Combine(GetScriptFolder(), @".\AdventureWorksSchema.json")); 31 | string connectionString = @"Data Source=WIN10VM2021\SQLEXPRESS; 32 | Initial Catalog=AdventureWorks2019; 33 | Integrated Security=True;"; 34 | 35 | Func connectionFactory = () => new SqlConnection(connectionString); 36 | var reader = new SqlServerSchemaReader(connectionFactory); // CodegenCS.Models.DbSchema.dll 37 | reader.ExportSchemaToJSON(outputJsonSchema); 38 | -------------------------------------------------------------------------------- /src/Tools/Tests/Templates/0074-IEnumerable-With-Delegates.cs: -------------------------------------------------------------------------------- 1 | class MyTemplate 2 | { 3 | 4 | void Main(ICodegenOutputFile w, IModelFactory factory) 5 | { 6 | var schema = factory.LoadModelFromFile(@"Models\AdventureWorks.json"); 7 | 8 | w.Write($$""" 9 | namespace MyNamespace 10 | { 11 | {{GenerateTables(schema)}} 12 | } 13 | """); 14 | } 15 | 16 | // THIS! This Func gets a DatabaseSchema and returns an IEnumerable of delegates (GenerateTable), 17 | // but the delegate is enriched with the "this is the table you need, and auto-inject any other arguments" 18 | static Func GenerateTables = (DatabaseSchema schema) => 19 | schema.Tables.Select(table => GenerateTable.WithArguments(null, table)) 20 | .Render(tableSeparatorOptions); 21 | 22 | // This Func requires 2 arguments, and the first one (ILogger) 23 | // will be automatically injected (because WithArguments with null) 24 | static Func GenerateTable = (logger, table) => 25 | { 26 | logger.WriteLineAsync($"Generating {table.TableName}..."); 27 | return (FormattableString)$$""" 28 | /// 29 | /// POCO for {{table.TableName}} 30 | /// 31 | public class {{table.TableName}} 32 | { 33 | {{GenerateColumns(table)}} 34 | } 35 | """; 36 | }; 37 | 38 | // return type is IEnumerable, but for simplicity let's define as object. 39 | static Func GenerateColumns = (table) => 40 | table.Columns.Select(column => (FormattableString)$$""" 41 | public {{column.ClrType}} {{column.ColumnName}} { get; set; } 42 | """); 43 | 44 | // Since tables render into many lines let's ensure an empty line between each table, improving readability 45 | static RenderEnumerableOptions tableSeparatorOptions = new RenderEnumerableOptions() 46 | { 47 | BetweenItemsBehavior = ItemsSeparatorBehavior.EnsureFullEmptyLine 48 | }; 49 | } -------------------------------------------------------------------------------- /src/Models/CodegenCS.Models.DbSchema/DbSchema/ForeignKey.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace CodegenCS.Models.DbSchema 5 | { 6 | public class ForeignKey 7 | { 8 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] // when constraint is serialized under parent table we don't need to serialize redundant attributes 9 | public string PrimaryKeyName { get; set; } 10 | 11 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] // when constraint is serialized under parent table we don't need to serialize redundant attributes 12 | public string PKTableSchema { get; set; } 13 | 14 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] // when constraint is serialized under parent table we don't need to serialize redundant attributes 15 | public string PKTableName { get; set; } 16 | 17 | 18 | public string ForeignKeyConstraintName { get; set; } 19 | 20 | public string ForeignKeyDescription { get; set; } 21 | 22 | 23 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] // when constraint is serialized under parent table we don't need to serialize redundant attributes 24 | public string FKTableSchema { get; set; } 25 | 26 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] // when constraint is serialized under parent table we don't need to serialize redundant attributes 27 | public string FKTableName { get; set; } 28 | 29 | 30 | /// 31 | /// NO_ACTION, CASCADE, SET_NULL, SET_DEFAULT 32 | /// 33 | public string OnDeleteCascade { get; set; } 34 | 35 | /// 36 | /// NO_ACTION, CASCADE, SET_NULL, SET_DEFAULT 37 | /// 38 | public string OnUpdateCascade { get; set; } 39 | 40 | public bool IsSystemNamed { get; set; } 41 | 42 | public bool IsNotEnforced { get; set; } 43 | 44 | public List Columns { get; set; } 45 | 46 | public override string ToString() => ForeignKeyConstraintName; // If someone renders the object (FK) instead of using the right property 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Models/README.md: -------------------------------------------------------------------------------- 1 | **CodegenCS is a Toolkit for doing Code Generation using plain C#**. 2 | 3 | Before anything else, don't forget to read the [Main Project Page](https://github.com/Drizin/CodegenCS/) to learn the basics (basic idea, basic features, and major components). 4 | 5 | # Models 6 | 7 | Templates can read from any data source (a file or a database or anything else) but **Models** are our built-in mechanism for easily providing inputs to templates. 8 | 9 | Both Visual Studio Extension and Command-line tool can load models using `IModelFactory`: 10 | 11 | ```cs 12 | void Main(ICodegenTextWriter writer, IModelFactory factory) 13 | { 14 | MyModel model = factory.LoadModelFromFile("MyModel.json"); 15 | // ... 16 | } 17 | ``` 18 | 19 | Command-line tool can also receive models as arguments - like `dotnet-codegencs template run