├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── question---discussion.md ├── MAINTAINING.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── EntityFrameworkCore.Scaffolding.Handlebars.sln ├── LICENSE ├── README.md ├── global.json ├── nuget ├── icon │ └── handlebars.png └── signing │ └── key.snk ├── sample ├── ScaffoldingSample.Api │ ├── Controllers │ │ └── EmployeeController.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── ScaffoldingSample.Api.csproj │ ├── ScaffoldingSample.Api.http │ ├── ScaffoldingSample.Api.sln │ ├── appsettings.Development.json │ └── appsettings.json ├── ScaffoldingSample.Embedded │ ├── Contexts │ │ └── NorthwindSlimContext.cs │ ├── Models │ │ ├── Category.cs │ │ ├── Customer.cs │ │ ├── CustomerSetting.cs │ │ ├── Employee.cs │ │ ├── EmployeeTerritories.cs │ │ ├── EmployeeTerritory.cs │ │ ├── Order.cs │ │ ├── OrderDetail.cs │ │ ├── Product.cs │ │ └── Territory.cs │ ├── ScaffoldingDesignTimeServices.cs │ └── ScaffoldingSample.Embedded.csproj ├── ScaffoldingSample.TypeScript │ ├── CodeTemplates │ │ ├── TypeScriptDbContext │ │ │ └── Partials │ │ │ │ ├── DbConstructor.hbs │ │ │ │ ├── DbImports.hbs │ │ │ │ ├── DbOnConfiguring.hbs │ │ │ │ └── DbSets.hbs │ │ └── TypeScriptEntityType │ │ │ ├── Class.hbs │ │ │ └── Partials │ │ │ ├── Constructor.hbs │ │ │ ├── Imports.hbs │ │ │ └── Properties.hbs │ ├── Models │ │ ├── Category.ts │ │ ├── Customer.ts │ │ ├── CustomerSetting.ts │ │ ├── Employee.ts │ │ ├── EmployeeTerritory.ts │ │ ├── Order.ts │ │ ├── OrderDetail.ts │ │ ├── Product.ts │ │ └── Territory.ts │ ├── ScaffoldingDesignTimeServices.cs │ └── ScaffoldingSample.TypeScript.csproj ├── ScaffoldingSample │ ├── CodeTemplates │ │ ├── CSharpDbContext │ │ │ ├── DbContext.hbs │ │ │ └── Partials │ │ │ │ ├── DbConstructor.hbs │ │ │ │ ├── DbImports.hbs │ │ │ │ ├── DbOnConfiguring.hbs │ │ │ │ └── DbSets.hbs │ │ └── CSharpEntityType │ │ │ ├── Class.hbs │ │ │ └── Partials │ │ │ ├── Constructor.hbs │ │ │ ├── Imports.hbs │ │ │ └── Properties.hbs │ ├── Contexts │ │ ├── NorthwindSlimContext.cs │ │ └── NorthwindSlimContextPartial.cs │ ├── Helpers │ │ └── DebuggingHelper.cs │ ├── Models │ │ ├── Country.cs │ │ ├── EntityBase.cs │ │ └── dbo │ │ │ ├── Category.cs │ │ │ ├── Customer.cs │ │ │ ├── CustomerSetting.cs │ │ │ ├── Employee.cs │ │ │ ├── Order.cs │ │ │ ├── OrderDetail.cs │ │ │ ├── Product.cs │ │ │ └── Territory.cs │ ├── Sample.ReadMe.md │ ├── ScaffoldingDesignTimeServices.cs │ └── ScaffoldingSample.csproj └── TemplatesAssembly │ ├── CodeTemplates │ ├── CSharpDbContext │ │ ├── DbContext.hbs │ │ └── Partials │ │ │ ├── DbConstructor.hbs │ │ │ ├── DbImports.hbs │ │ │ ├── DbOnConfiguring.hbs │ │ │ └── DbSets.hbs │ ├── CSharpEntityType │ │ ├── Class.hbs │ │ └── Partials │ │ │ ├── Constructor.hbs │ │ │ ├── Imports.hbs │ │ │ └── Properties.hbs │ ├── TypeScriptDbContext │ │ ├── DbContext.hbs │ │ └── Partials │ │ │ ├── DbConstructor.hbs │ │ │ ├── DbImports.hbs │ │ │ ├── DbOnConfiguring.hbs │ │ │ └── DbSets.hbs │ └── TypeScriptEntityType │ │ ├── Class.hbs │ │ └── Partials │ │ ├── Constructor.hbs │ │ ├── Imports.hbs │ │ └── Properties.hbs │ └── TemplatesAssembly.csproj ├── src └── EntityFrameworkCore.Scaffolding.Handlebars │ ├── CSharpTemplateLanguageService.cs │ ├── CodeTemplates │ ├── CSharpDbContext │ │ ├── DbContext.hbs │ │ └── Partials │ │ │ ├── DbConstructor.hbs │ │ │ ├── DbImports.hbs │ │ │ ├── DbOnConfiguring.hbs │ │ │ └── DbSets.hbs │ ├── CSharpEntityType │ │ ├── Class.hbs │ │ └── Partials │ │ │ ├── Constructor.hbs │ │ │ ├── Imports.hbs │ │ │ └── Properties.hbs │ ├── TypeScriptDbContext │ │ ├── DbContext.hbs │ │ └── Partials │ │ │ ├── DbConstructor.hbs │ │ │ ├── DbImports.hbs │ │ │ ├── DbOnConfiguring.hbs │ │ │ └── DbSets.hbs │ └── TypeScriptEntityType │ │ ├── Class.hbs │ │ └── Partials │ │ ├── Constructor.hbs │ │ ├── Imports.hbs │ │ └── Properties.hbs │ ├── EmbeddedResourceTemplateFileService.cs │ ├── EntityFrameworkCore.Scaffolding.Handlebars.csproj │ ├── EntityFrameworkCore.Scaffolding.Handlebars.targets │ ├── EntityPropertyInfo.cs │ ├── FileSystemTemplateFileService.cs │ ├── GlobalSuppressions.cs │ ├── HandlebarsScaffoldingOptions.cs │ ├── HbsBlockHelperService.cs │ ├── HbsCSharpDbContextGenerator.cs │ ├── HbsCSharpEntityTypeGenerator.cs │ ├── HbsCSharpModelGenerator.cs │ ├── HbsContextTransformationService.cs │ ├── HbsDbContextTemplateService.cs │ ├── HbsEntityTypeTemplateService.cs │ ├── HbsEntityTypeTransformationService.cs │ ├── HbsEntityTypeTransformationService2.cs │ ├── HbsEntityTypeTransformationServiceBase.cs │ ├── HbsHelperService.cs │ ├── HbsReverseEngineerScaffolder.cs │ ├── HbsTemplateService.cs │ ├── HbsTypeScriptEntityTypeGenerator.cs │ ├── HbsTypeScriptModelGenerator.cs │ ├── Helpers │ ├── Constants.cs │ └── HandlebarsHelpers.cs │ ├── IContextTransformationService.cs │ ├── IDbContextTemplateService.cs │ ├── IEntityTypeExtensions.cs │ ├── IEntityTypeTemplateService.cs │ ├── IEntityTypeTransformationService.cs │ ├── IHbsBlockHelperService.cs │ ├── IHbsHelperService.cs │ ├── IHbsTemplateService.cs │ ├── IModelExtensions.cs │ ├── ITemplateFileService.cs │ ├── ITemplateLanguageService.cs │ ├── ITypeScriptHelper.cs │ ├── InMemoryTemplateFileService.cs │ ├── InputFile.cs │ ├── Internal │ ├── Check.cs │ ├── EntityTypeExtensions.cs │ ├── FileSystemFileService.cs │ ├── ICSharpDbContextGenerator.cs │ ├── ICSharpEntityTypeGenerator.cs │ ├── IFileService.cs │ ├── InMemoryFileService.cs │ ├── NamespaceComparer.cs │ ├── RelationalAnnotationNames.cs │ ├── SharedTypeExtensions.cs │ └── TableAndSchema.cs │ ├── LICENSE │ ├── LanguageOptions.cs │ ├── NullCSharpDbContextGenerator.cs │ ├── NullCSharpEntityTypeGenerator.cs │ ├── ReverseEngineerOptions.cs │ ├── ScaffoldingDesignTimeServices.cs │ ├── ServiceCollectionExtensions.cs │ ├── TemplateFileInfo.cs │ ├── TypeScriptHelper.cs │ ├── TypeScriptTemplateLanguageService.cs │ ├── icon.png │ └── key.snk └── test └── Scaffolding.Handlebars.Tests ├── CSharpEntityTypeAlt ├── Class.hbs └── Partials │ ├── Constructor.hbs │ ├── Imports.hbs │ └── Properties.hbs ├── CodeTemplates ├── CSharpDbContext │ ├── DbContext.hbs │ └── Partials │ │ ├── DbConstructor.hbs │ │ ├── DbImports.hbs │ │ ├── DbOnConfiguring.hbs │ │ └── DbSets.hbs ├── CSharpEntityType │ ├── Class.hbs │ └── Partials │ │ ├── Constructor.hbs │ │ ├── Imports.hbs │ │ └── Properties.hbs ├── TypeScriptDbContext │ ├── DbContext.hbs │ └── Partials │ │ ├── DbConstructor.hbs │ │ ├── DbImports.hbs │ │ ├── DbOnConfiguring.hbs │ │ └── DbSets.hbs └── TypeScriptEntityType │ ├── Class.hbs │ └── Partials │ ├── Constructor.hbs │ ├── Imports.hbs │ └── Properties.hbs ├── CodeTemplatesAlt └── CSharpEntityType │ └── Class.hbs ├── Contexts └── NorthwindDbContext.cs ├── EmbeddedResourceTemplateFileServiceTests.ExpectedTemplates.cs ├── EmbeddedResourceTemplateFileServiceTests.cs ├── ExpectedContexts.cs ├── ExpectedEntities.cs ├── ExpectedTypeScriptContexts.cs ├── ExpectedTypeScriptInterfaces.cs ├── Fakes ├── FakeCSharpTemplateLanguageService.cs ├── FakeDatabaseModelFactory.cs ├── FakeHbsDbContextTemplateService.cs ├── FakeHbsEntityTypeTemplateService.cs ├── FakeScaffoldingModelFactory.cs ├── FakeTypeScriptTemplateLanguageService.cs └── TestProviderCodeGenerator.cs ├── FileSystemTemplateFileServiceTests.ExpectedTemplates.cs ├── FileSystemTemplateFileServiceTests.cs ├── GlobalSuppressions.cs ├── HbsCSharpScaffoldingGeneratorTests.cs ├── HbsTypeScriptScaffoldingGeneratorTests.cs ├── Helpers ├── Constants.cs ├── DatabaseCollection.cs ├── DatabaseFixture.cs ├── HandlebarsTransformers.cs ├── TempDirectory.cs └── TestRelationalLoggingDefinitions.cs ├── IModelExtensionsTests.cs ├── Models ├── Category.cs ├── Customer.cs └── Product.cs ├── ReverseEngineeringConfigurationTests.cs ├── Scaffolding.Handlebars.Tests.csproj ├── Tests.ReadMe.md └── appsettings.json /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[Bug] " 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Expected behavior** 14 | A clear and concise description of what you expected to happen. 15 | 16 | **To Reproduce** 17 | Steps to reproduce the behavior. 18 | 19 | **Make My Life Easier** 20 | If possible, create a pull request that contains a failing unit test. 21 | Otherwise, use the `sample/ScaffoldingSample` project to reproduce the bug. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[Feature] " 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question---discussion.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question / Discussion 3 | about: Describe this issue template's purpose here. 4 | title: "[Question] " 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/MAINTAINING.md: -------------------------------------------------------------------------------- 1 | ### Entity Framework Core Scaffolding with Handlebars 2 | 3 | # Maintaining 4 | 5 | _This document describes tasks for maintaining a GitHub repository and publishing updated packages to NuGet._ 6 | 7 | ### Pull Requests 8 | 9 | 1. Follow command-line instructions to pull contributor's branch. 10 | - Copy just the first two lines and paste them into a terminal. 11 | - This will create a local branch for the PR which you can inspect. 12 | 2. Run unit tests to make sure they all pass. 13 | 3. Run EF Core scaffolder on the sample project to see if any output files have changed. 14 | 4. Inspect proposed changes. If necessary, comment on lines of code in the PR and propose changes. 15 | 5. When the PR is ready to merge, you can do it locally or via the GitHub interface. 16 | 17 | ### Releases 18 | 19 | 1. Increment the package version number. 20 | - Append beta1 (or later) to indicate "pre-release" status. 21 | 2. Enter the matching version number in the release notes URL. 22 | 3. Commit and push the change to the master branch. 23 | 4. Create a new release in GitHub 24 | - Create a tag with "v" prepended to the version number (for example v8.2.1). 25 | - The title of the release should match the tag you just created. 26 | - Add release notes that include the issue and pull request numbers included in the release. 27 | - Paste a link to the NuGet package you will create next. 28 | - If it is a beta release, set as a pre-release. 29 | - Publish the release. 30 | 31 | ### NuGet 32 | 33 | 1. Set the build configuration to Release. 34 | 2. Build the project. 35 | 3. Navigate to the bin/release folder. 36 | 4. Log into NuGet. 37 | 5. Under your login name select Upload Package. 38 | 6. Drop the file into the Upload box (or select Browse to locate). 39 | 7. Review package details to verify their correctness. 40 | 8. Publish the package. 41 | 42 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Describe your proposed changes** 2 | Write a general description of what you would like to fix or improve. 3 | 4 | **Put `Closes #XXXX` in your comment** 5 | This will auto-close the issue that your PR fixes. 6 | 7 | **Additional Resources** 8 | Refer to the [Contributing Guidelines](https://github.com/TrackableEntities/EntityFrameworkCore.Scaffolding.Handlebars/blob/master/.github/CONTRIBUTING.md) for this project. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Trackable Entities 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 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "8.0.0", 4 | "rollForward": "latestMajor", 5 | "allowPrerelease": true 6 | } 7 | } -------------------------------------------------------------------------------- /nuget/icon/handlebars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrackableEntities/EntityFrameworkCore.Scaffolding.Handlebars/2f6ff4dd956501c0f8fdec8b7c6f04dc4b928c1f/nuget/icon/handlebars.png -------------------------------------------------------------------------------- /nuget/signing/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrackableEntities/EntityFrameworkCore.Scaffolding.Handlebars/2f6ff4dd956501c0f8fdec8b7c6f04dc4b928c1f/nuget/signing/key.snk -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Api/Controllers/EmployeeController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.EntityFrameworkCore; 3 | using ScaffoldingSample.Contexts; 4 | 5 | namespace ScaffoldingSample.Api.Controllers; 6 | 7 | [Route("api/[controller]")] 8 | [ApiController] 9 | public class EmployeeController(NorthwindSlimContext context) : ControllerBase 10 | { 11 | // GET api/employee 12 | [HttpGet] 13 | public async Task Get() 14 | { 15 | var employees = await context.Employees 16 | .OrderBy(e => e.LastName).ThenBy(e => e.FirstName) 17 | .Select(e => new 18 | { 19 | e.EmployeeId, 20 | e.LastName, 21 | e.FirstName, 22 | BirthDate = e.BirthDate.GetValueOrDefault().ToShortDateString(), 23 | HireDate = e.HireDate.GetValueOrDefault().ToShortDateString(), 24 | Country = e.Country.ToString() 25 | }) 26 | .ToListAsync(); 27 | return Ok(employees); 28 | } 29 | } -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Api/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using ScaffoldingSample.Contexts; 3 | 4 | var builder = WebApplication.CreateBuilder(args); 5 | 6 | // Add services to the container. 7 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle 8 | builder.Services.AddEndpointsApiExplorer(); 9 | builder.Services.AddSwaggerGen(); 10 | builder.Services.AddControllers(); 11 | builder.Services.AddDbContext(options => 12 | { 13 | var connectionString = builder.Configuration.GetConnectionString(nameof(NorthwindSlimContext)); 14 | options.UseSqlServer(connectionString); 15 | }); 16 | 17 | var app = builder.Build(); 18 | 19 | // Configure the HTTP request pipeline. 20 | if (app.Environment.IsDevelopment()) 21 | { 22 | app.UseSwagger(); 23 | app.UseSwaggerUI(); 24 | } 25 | 26 | app.UseHttpsRedirection(); 27 | 28 | app.MapControllers(); 29 | 30 | app.Run(); -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Api/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "http": { 5 | "commandName": "Project", 6 | "dotnetRunMessages": true, 7 | "launchBrowser": true, 8 | "launchUrl": "swagger", 9 | "applicationUrl": "http://localhost:5041", 10 | "environmentVariables": { 11 | "ASPNETCORE_ENVIRONMENT": "Development" 12 | } 13 | }, 14 | "https": { 15 | "commandName": "Project", 16 | "dotnetRunMessages": true, 17 | "launchBrowser": true, 18 | "launchUrl": "swagger", 19 | "applicationUrl": "https://localhost:7208;http://localhost:5041", 20 | "environmentVariables": { 21 | "ASPNETCORE_ENVIRONMENT": "Development" 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Api/ScaffoldingSample.Api.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | false 8 | 12811259-bfae-451f-9a72-050791c4ed4b 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Api/ScaffoldingSample.Api.http: -------------------------------------------------------------------------------- 1 | @SaffoldingSample.Api_HostAddress = http://localhost:5041 2 | 3 | GET {{SaffoldingSample.Api_HostAddress}}/weatherforecast/ 4 | Accept: application/json 5 | 6 | ### 7 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Api/ScaffoldingSample.Api.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScaffoldingSample.Api", "ScaffoldingSample.Api.csproj", "{E841BA04-0CB7-46A9-8CE5-02049F3A499C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {E841BA04-0CB7-46A9-8CE5-02049F3A499C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {E841BA04-0CB7-46A9-8CE5-02049F3A499C}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {E841BA04-0CB7-46A9-8CE5-02049F3A499C}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {E841BA04-0CB7-46A9-8CE5-02049F3A499C}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {DB5CBEB7-A02F-48C9-BD88-FC41367DDFB2} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Api/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Api/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "ConnectionStrings": { 10 | "NorthwindSlimContext": "Data Source=(localdb)\\MsSqlLocalDb;initial catalog=NorthwindSlim;Integrated Security=True; MultipleActiveResultSets=True" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Embedded/Models/Category.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ScaffoldingSample.Embedded.Models 5 | { 6 | /// 7 | /// hello table Customer 8 | /// 9 | public partial class Category 10 | { 11 | public Category() 12 | { 13 | Products = new HashSet(); 14 | } 15 | 16 | public int CategoryId { get; set; } 17 | /// 18 | /// hello CompanyName 19 | /// 20 | public string CategoryName { get; set; } 21 | 22 | public virtual ICollection Products { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Embedded/Models/Customer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ScaffoldingSample.Embedded.Models 5 | { 6 | public partial class Customer 7 | { 8 | public Customer() 9 | { 10 | Orders = new HashSet(); 11 | } 12 | 13 | public string CustomerId { get; set; } 14 | public string CompanyName { get; set; } 15 | public string ContactName { get; set; } 16 | public string City { get; set; } 17 | public string Country { get; set; } 18 | 19 | public virtual CustomerSetting CustomerSetting { get; set; } 20 | public virtual ICollection Orders { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Embedded/Models/CustomerSetting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ScaffoldingSample.Embedded.Models 5 | { 6 | public partial class CustomerSetting 7 | { 8 | public string CustomerId { get; set; } 9 | public string Setting { get; set; } 10 | 11 | public virtual Customer Customer { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Embedded/Models/Employee.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ScaffoldingSample.Embedded.Models 5 | { 6 | public partial class Employee 7 | { 8 | public Employee() 9 | { 10 | EmployeeTerritories = new HashSet(); 11 | } 12 | 13 | public int EmployeeId { get; set; } 14 | public string LastName { get; set; } 15 | public string FirstName { get; set; } 16 | public DateTime? BirthDate { get; set; } 17 | public DateTime? HireDate { get; set; } 18 | public string City { get; set; } 19 | public string Country { get; set; } 20 | 21 | public virtual ICollection EmployeeTerritories { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Embedded/Models/EmployeeTerritories.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ScaffoldingSample.Embedded.Models 5 | { 6 | public partial class EmployeeTerritories 7 | { 8 | public int EmployeeId { get; set; } 9 | public string TerritoryId { get; set; } 10 | 11 | public virtual Employee Employee { get; set; } 12 | public virtual Territory Territory { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Embedded/Models/EmployeeTerritory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ScaffoldingSample.Embedded.Models 5 | { 6 | public partial class EmployeeTerritory 7 | { 8 | public int EmployeeId { get; set; } 9 | public string TerritoryId { get; set; } 10 | 11 | public virtual Employee Employee { get; set; } 12 | public virtual Territory Territory { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Embedded/Models/Order.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ScaffoldingSample.Embedded.Models 5 | { 6 | public partial class Order 7 | { 8 | public Order() 9 | { 10 | OrderDetails = new HashSet(); 11 | } 12 | 13 | public int OrderId { get; set; } 14 | public string CustomerId { get; set; } 15 | public DateTime? OrderDate { get; set; } 16 | public DateTime? ShippedDate { get; set; } 17 | public int? ShipVia { get; set; } 18 | public decimal? Freight { get; set; } 19 | 20 | public virtual Customer Customer { get; set; } 21 | public virtual ICollection OrderDetails { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Embedded/Models/OrderDetail.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ScaffoldingSample.Embedded.Models 5 | { 6 | public partial class OrderDetail 7 | { 8 | public int OrderDetailId { get; set; } 9 | public int OrderId { get; set; } 10 | public int ProductId { get; set; } 11 | public decimal UnitPrice { get; set; } 12 | public short Quantity { get; set; } 13 | public float Discount { get; set; } 14 | 15 | public virtual Order Order { get; set; } 16 | public virtual Product Product { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Embedded/Models/Product.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ScaffoldingSample.Embedded.Models 5 | { 6 | public partial class Product 7 | { 8 | public Product() 9 | { 10 | OrderDetails = new HashSet(); 11 | } 12 | 13 | public int ProductId { get; set; } 14 | public string ProductName { get; set; } 15 | public int? CategoryId { get; set; } 16 | public decimal? UnitPrice { get; set; } 17 | public bool Discontinued { get; set; } 18 | public byte[] RowVersion { get; set; } 19 | 20 | public virtual Category Category { get; set; } 21 | public virtual ICollection OrderDetails { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Embedded/Models/Territory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ScaffoldingSample.Embedded.Models 5 | { 6 | public partial class Territory 7 | { 8 | public Territory() 9 | { 10 | EmployeeTerritories = new HashSet(); 11 | } 12 | 13 | public string TerritoryId { get; set; } 14 | public string TerritoryDescription { get; set; } 15 | 16 | public virtual ICollection EmployeeTerritories { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Embedded/ScaffoldingDesignTimeServices.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Design; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using System.Diagnostics; 4 | using System.Reflection; 5 | 6 | /* 7 | Run a 'dotnet ef dbcontext scaffold' command to reverse engineer classes from an existing database. 8 | For example: 9 | dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB; Initial Catalog=NorthwindSlim; Integrated Security=True" Microsoft.EntityFrameworkCore.SqlServer -o Models -c NorthwindSlimContext -f --context-dir Contexts 10 | */ 11 | namespace ScaffoldingSample.Embedded 12 | { 13 | public class ScaffoldingDesignTimeServices : IDesignTimeServices 14 | { 15 | public void ConfigureDesignTimeServices(IServiceCollection services) 16 | { 17 | // Uncomment to launch JIT debugger and hit breakpoints 18 | //Debugger.Launch(); 19 | 20 | // Get templates assembly 21 | var templatesAssembly = Assembly.Load("TemplatesAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); 22 | 23 | // Add Handlebars scaffolding using embedded templates templates 24 | services.AddHandlebarsScaffolding(options => options.EmbeddedTemplatesAssembly = templatesAssembly); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.Embedded/ScaffoldingSample.Embedded.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | latest 6 | 7 | 8 | 9 | 10 | 11 | all 12 | runtime; build; native; contentfiles; analyzers; buildtransitive 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/CodeTemplates/TypeScriptDbContext/Partials/DbConstructor.hbs: -------------------------------------------------------------------------------- 1 |  public {{class}}(DbContextOptions<{{class}}> options) : base(options) 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/CodeTemplates/TypeScriptDbContext/Partials/DbImports.hbs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | {{#if model-namespace}} 6 | using {{model-namespace}}; 7 | {{/if}} 8 | {{#each model-imports}} 9 | using {{model-import}}; 10 | {{/each}} 11 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/CodeTemplates/TypeScriptDbContext/Partials/DbOnConfiguring.hbs: -------------------------------------------------------------------------------- 1 |  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 2 | { 3 | if (!optionsBuilder.IsConfigured) 4 | { 5 | {{#if connectionstring-warning}} 6 | {{connectionstring-warning}} 7 | {{/if}} 8 | optionsBuilder{{options-builder-provider}}; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/CodeTemplates/TypeScriptDbContext/Partials/DbSets.hbs: -------------------------------------------------------------------------------- 1 | {{#each dbsets}} 2 | public virtual DbSet<{{set-property-type}}> {{set-property-name}} { get; set; }{{#if nullable-reference-types }} = default!;{{/if}} 3 | {{/each}} 4 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/CodeTemplates/TypeScriptEntityType/Class.hbs: -------------------------------------------------------------------------------- 1 | {{> imports}} 2 | 3 | {{#if comment}} 4 | /** 5 | * {{comment}} 6 | */ 7 | {{/if}} 8 | export interface {{class}} { 9 | {{{> properties}}} 10 | } 11 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/CodeTemplates/TypeScriptEntityType/Partials/Constructor.hbs: -------------------------------------------------------------------------------- 1 |  constructor() { 2 | } 3 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/CodeTemplates/TypeScriptEntityType/Partials/Imports.hbs: -------------------------------------------------------------------------------- 1 | {{#each imports}} 2 | import { {{import}} } from './{{import}}'; 3 | {{/each}} 4 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/CodeTemplates/TypeScriptEntityType/Partials/Properties.hbs: -------------------------------------------------------------------------------- 1 | {{#each properties}} 2 | {{#if property-comment}} 3 | /** 4 | * {{property-comment}} 5 | */ 6 | {{/if}} 7 | {{property-name}}: {{property-type}}; 8 | {{/each}} 9 | {{#if nav-properties}} 10 | {{#each nav-properties}} 11 | {{#if nav-property-collection}} 12 | {{nav-property-name}}: {{nav-property-type}}[]; 13 | {{else}} 14 | {{nav-property-name}}: {{nav-property-type}}; 15 | {{/if}} 16 | {{/each}} 17 | {{/if}} -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/Models/Category.ts: -------------------------------------------------------------------------------- 1 | import { Product } from './Product'; 2 | 3 | export interface Category { 4 | categoryId: number; 5 | categoryName: string; 6 | products: Product[]; 7 | } 8 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/Models/Customer.ts: -------------------------------------------------------------------------------- 1 | import { CustomerSetting } from './CustomerSetting'; 2 | import { Order } from './Order'; 3 | 4 | export interface Customer { 5 | customerId: string; 6 | companyName: string; 7 | contactName: string; 8 | city: string; 9 | country: string; 10 | customerSetting: CustomerSetting; 11 | orders: Order[]; 12 | } 13 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/Models/CustomerSetting.ts: -------------------------------------------------------------------------------- 1 | import { Customer } from './Customer'; 2 | 3 | export interface CustomerSetting { 4 | customerId: string; 5 | setting: string; 6 | customer: Customer; 7 | } 8 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/Models/Employee.ts: -------------------------------------------------------------------------------- 1 | import { Territory } from './Territory'; 2 | 3 | export interface Employee { 4 | employeeId: number; 5 | lastName: string; 6 | firstName: string; 7 | birthDate: Date; 8 | hireDate: Date; 9 | city: string; 10 | country: string; 11 | territories: Territory[]; 12 | } 13 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/Models/EmployeeTerritory.ts: -------------------------------------------------------------------------------- 1 |  2 | export interface EmployeeTerritory { 3 | employeeId: number; 4 | territoryId: string; 5 | } 6 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/Models/Order.ts: -------------------------------------------------------------------------------- 1 | import { Customer } from './Customer'; 2 | import { OrderDetail } from './OrderDetail'; 3 | 4 | export interface Order { 5 | orderId: number; 6 | customerId: string; 7 | orderDate: Date; 8 | shippedDate: Date; 9 | shipVia: number; 10 | freight: number; 11 | customer: Customer; 12 | orderDetails: OrderDetail[]; 13 | } 14 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/Models/OrderDetail.ts: -------------------------------------------------------------------------------- 1 | import { Order } from './Order'; 2 | import { Product } from './Product'; 3 | 4 | export interface OrderDetail { 5 | orderDetailId: number; 6 | orderId: number; 7 | productId: number; 8 | unitPrice: number; 9 | quantity: number; 10 | discount: number; 11 | order: Order; 12 | product: Product; 13 | } 14 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/Models/Product.ts: -------------------------------------------------------------------------------- 1 | import { Category } from './Category'; 2 | import { OrderDetail } from './OrderDetail'; 3 | 4 | export interface Product { 5 | productId: number; 6 | productName: string; 7 | categoryId: number; 8 | unitPrice: number; 9 | discontinued: boolean; 10 | rowVersion: any; 11 | category: Category; 12 | orderDetails: OrderDetail[]; 13 | } 14 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/Models/Territory.ts: -------------------------------------------------------------------------------- 1 | import { Employee } from './Employee'; 2 | 3 | export interface Territory { 4 | territoryId: string; 5 | territoryDescription: string; 6 | employees: Employee[]; 7 | } 8 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/ScaffoldingDesignTimeServices.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Design; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | /* 5 | You may customize generated classes by modifying the Handlebars templates in the CodeTemplates folder. 6 | Then run a 'dotnet ef dbcontext scaffold' command to reverse engineer classes from an existing database. 7 | For example: 8 | dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB; Initial Catalog=NorthwindSlim; Integrated Security=True" Microsoft.EntityFrameworkCore.SqlServer -o Models -c NorthwindSlimContext -f --context-dir Contexts 9 | */ 10 | 11 | namespace ScaffoldingSample 12 | { 13 | public class ScaffoldingDesignTimeServices : IDesignTimeServices 14 | { 15 | public void ConfigureDesignTimeServices(IServiceCollection services) 16 | { 17 | // Uncomment to launch JIT debugger and hit breakpoints 18 | //System.Diagnostics.Debugger.Launch(); 19 | 20 | // Add Handlebars scaffolding templates 21 | services.AddHandlebarsScaffolding(ReverseEngineerOptions.EntitiesOnly, LanguageOptions.TypeScript); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample.TypeScript/ScaffoldingSample.TypeScript.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | latest 6 | 7 | 8 | 9 | 10 | 11 | all 12 | runtime; build; native; contentfiles; analyzers; buildtransitive 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/CodeTemplates/CSharpDbContext/DbContext.hbs: -------------------------------------------------------------------------------- 1 | {{> dbimports}} 2 | 3 | namespace {{namespace}} 4 | { // Comment 5 | public partial class {{class}} : DbContext 6 | { 7 | {{{> dbsets}}} 8 | 9 | {{{> dbconstructor}}} 10 | 11 | {{#unless suppress-on-configuring}} 12 | {{{> dbonconfiguring}}} 13 | 14 | {{/unless}} 15 | {{{on-model-creating}}} 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/CodeTemplates/CSharpDbContext/Partials/DbConstructor.hbs: -------------------------------------------------------------------------------- 1 |  public {{class}}() 2 | { 3 | } 4 | 5 | public {{class}}(DbContextOptions<{{class}}> options) : base(options) 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/CodeTemplates/CSharpDbContext/Partials/DbImports.hbs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Metadata; // Comment 5 | {{#if model-namespace}} 6 | using {{model-namespace}}; 7 | {{/if}} 8 | {{#each model-imports}} 9 | using {{model-import}}; 10 | {{/each}} 11 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/CodeTemplates/CSharpDbContext/Partials/DbOnConfiguring.hbs: -------------------------------------------------------------------------------- 1 |  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 2 | { 3 | if (!optionsBuilder.IsConfigured) 4 | { 5 | {{#if connectionstring-warning}} 6 | {{connectionstring-warning}} 7 | {{/if}} 8 | optionsBuilder{{options-builder-provider}}; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/CodeTemplates/CSharpDbContext/Partials/DbSets.hbs: -------------------------------------------------------------------------------- 1 | {{#each dbsets}} 2 | {{my-helper}} 3 | public virtual DbSet<{{set-property-type}}> {{set-property-name}} { get; set; }{{#if nullable-reference-types }} = null!;{{/if}} 4 | {{/each}} 5 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/CodeTemplates/CSharpEntityType/Class.hbs: -------------------------------------------------------------------------------- 1 | {{> imports}} 2 | 3 | namespace {{namespace}} 4 | { // Comment 5 | {{#if comment}} 6 | /// 7 | {{comment}} 8 | /// 9 | {{/if}} 10 | {{#each class-annotations}} 11 | {{{class-annotation}}} 12 | {{/each}} 13 | public partial class {{class}} : {{base-class}} {{my-helper}} 14 | { 15 | {{{> constructor}}} 16 | {{{> properties}}} 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/CodeTemplates/CSharpEntityType/Partials/Constructor.hbs: -------------------------------------------------------------------------------- 1 | {{#if lines}} 2 | public {{class}}() 3 | { 4 | {{#each lines}} 5 | {{property-name}} = new HashSet<{{property-type}}>(); 6 | {{/each}} 7 | } 8 | 9 | {{/if}} 10 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/CodeTemplates/CSharpEntityType/Partials/Imports.hbs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; // Comment 3 | {{#if use-data-annotations}} 4 | using System.ComponentModel.DataAnnotations; 5 | using System.ComponentModel.DataAnnotations.Schema; 6 | using Microsoft.EntityFrameworkCore; 7 | {{/if}} 8 | {{#each imports}} 9 | using {{import}}; 10 | {{/each}} 11 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/CodeTemplates/CSharpEntityType/Partials/Properties.hbs: -------------------------------------------------------------------------------- 1 | {{#each properties}} 2 | {{#if property-comment}} 3 | 4 | /// 5 | {{property-comment}} 6 | /// 7 | {{/if}} 8 | {{#each property-annotations}} 9 | {{{property-annotation}}} 10 | {{/each}} 11 | public {{property-type}} {{property-name}} { get; set; }{{#if nullable-reference-types }}{{#unless property-isnullable}} = null!;{{/unless}}{{/if}} 12 | {{/each}} 13 | {{#if nav-properties}} 14 | 15 | {{#each nav-properties}} 16 | {{#each nav-property-annotations}} 17 | {{{nav-property-annotation}}} 18 | {{/each}} 19 | {{#if nav-property-collection}} 20 | public virtual ICollection<{{nav-property-type}}> {{nav-property-name}} { get; set; } 21 | {{else}} 22 | public virtual {{nav-property-type}} {{nav-property-name}} { get; set; }{{#if nullable-reference-types}}{{#unless nav-property-isnullable}} = null!;{{/unless}}{{/if}} 23 | {{/if}} 24 | {{/each}} 25 | {{/if}} 26 | 27 | // My Handlebars Block Helper: {{#ifCond '1' '==' '1'}}True{{else}}False{{/ifCond}} 28 | // My Handlebars Block Helper: {{#ifCond '2' '==' '1'}}True{{else}}False{{/ifCond}} 29 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/Contexts/NorthwindSlimContextPartial.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | #pragma warning disable CS8981 // The type name only contains lower-cased ascii characters. Such names may become reserved for the language. 3 | using dbo = ScaffoldingSample.Models.dbo; 4 | #pragma warning restore CS8981 // The type name only contains lower-cased ascii characters. Such names may become reserved for the language. 5 | 6 | namespace ScaffoldingSample.Contexts 7 | { 8 | public partial class NorthwindSlimContext 9 | { 10 | partial void OnModelCreatingPartial(ModelBuilder modelBuilder) 11 | { 12 | modelBuilder.Entity() 13 | .Property(e => e.Country) 14 | .HasConversion(); 15 | modelBuilder.Entity() 16 | .Property(e => e.Country) 17 | .HasConversion(); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /sample/ScaffoldingSample/Helpers/DebuggingHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace ScaffoldingSample.Helpers; 7 | 8 | public class DebuggingHelper 9 | { 10 | public static async Task WaitForDebuggerAsync(TimeSpan? limit = null) 11 | { 12 | limit ??= TimeSpan.FromSeconds(30); 13 | var source = new CancellationTokenSource(limit.Value); 14 | 15 | Console.WriteLine($"◉ Waiting {limit.Value.TotalSeconds} secs for debugger (PID: {Environment.ProcessId})..."); 16 | 17 | try 18 | { 19 | await Task.Run(async () => { 20 | while (!Debugger.IsAttached) { 21 | await Task.Delay(TimeSpan.FromMilliseconds(100), source.Token); 22 | } 23 | }, source.Token); 24 | } 25 | catch (OperationCanceledException) 26 | { 27 | // it's ok 28 | } 29 | 30 | Console.WriteLine(Debugger.IsAttached 31 | ? "✔ Debugger attached" 32 | : "✕ Continuing without debugger"); 33 | 34 | return Debugger.IsAttached; 35 | } 36 | 37 | public static bool WaitForDebugger(TimeSpan? limit = null) 38 | { 39 | limit ??= TimeSpan.FromSeconds(30); 40 | 41 | Console.WriteLine($"◉ Waiting {limit.Value.TotalSeconds} secs for debugger (PID: {Environment.ProcessId})..."); 42 | 43 | try 44 | { 45 | while (!Debugger.IsAttached) { 46 | Thread.Sleep(TimeSpan.FromMilliseconds(100)); 47 | } 48 | } 49 | catch (OperationCanceledException) 50 | { 51 | // it's ok 52 | } 53 | 54 | Console.WriteLine(Debugger.IsAttached 55 | ? "✔ Debugger attached" 56 | : "✕ Continuing without debugger"); 57 | 58 | return Debugger.IsAttached; 59 | } 60 | } -------------------------------------------------------------------------------- /sample/ScaffoldingSample/Models/Country.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldingSample.Models 2 | { 3 | public enum Country 4 | { 5 | UK = 1, 6 | USA = 2 7 | } 8 | } -------------------------------------------------------------------------------- /sample/ScaffoldingSample/Models/EntityBase.cs: -------------------------------------------------------------------------------- 1 | namespace ScaffoldingSample.Models 2 | { 3 | public class EntityBase 4 | { 5 | public virtual string Foo() => "Foo"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/Models/dbo/Category.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; // Comment 3 | 4 | namespace ScaffoldingSample.Models.dbo 5 | { // Comment 6 | public partial class Category : EntityBase // My Handlebars Helper 7 | { 8 | public Category() 9 | { 10 | Products = new HashSet(); 11 | } 12 | 13 | public int CategoryId { get; set; } 14 | public string CategoryName { get; set; } = null!; 15 | 16 | public virtual ICollection Products { get; set; } 17 | 18 | // My Handlebars Block Helper: True 19 | // My Handlebars Block Helper: False 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/Models/dbo/Customer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; // Comment 3 | 4 | namespace ScaffoldingSample.Models.dbo 5 | { // Comment 6 | public partial class Customer : EntityBase // My Handlebars Helper 7 | { 8 | public Customer() 9 | { 10 | Orders = new HashSet(); 11 | } 12 | 13 | public string CustomerId { get; set; } = null!; 14 | public string CompanyName { get; set; } = null!; 15 | public string? ContactName { get; set; } 16 | public string? City { get; set; } 17 | public Country? Country { get; set; } = null!; 18 | 19 | public virtual CustomerSetting CustomerSetting { get; set; } = null!; 20 | public virtual ICollection Orders { get; set; } 21 | 22 | // My Handlebars Block Helper: True 23 | // My Handlebars Block Helper: False 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/Models/dbo/CustomerSetting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; // Comment 3 | 4 | namespace ScaffoldingSample.Models.dbo 5 | { // Comment 6 | public partial class CustomerSetting : EntityBase // My Handlebars Helper 7 | { 8 | public string CustomerId { get; set; } = null!; 9 | public string Setting { get; set; } = null!; 10 | 11 | public virtual Customer Customer { get; set; } = null!; 12 | 13 | // My Handlebars Block Helper: True 14 | // My Handlebars Block Helper: False 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/Models/dbo/Employee.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; // Comment 3 | 4 | namespace ScaffoldingSample.Models.dbo 5 | { // Comment 6 | public partial class Employee : EntityBase // My Handlebars Helper 7 | { 8 | public Employee() 9 | { 10 | Territories = new HashSet(); 11 | } 12 | 13 | public int EmployeeId { get; set; } 14 | public string LastName { get; set; } = null!; 15 | public string FirstName { get; set; } = null!; 16 | public DateTime? BirthDate { get; set; } 17 | public DateTime? HireDate { get; set; } 18 | public string? City { get; set; } 19 | public Country? Country { get; set; } = null!; 20 | 21 | public virtual ICollection Territories { get; set; } 22 | 23 | // My Handlebars Block Helper: True 24 | // My Handlebars Block Helper: False 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/Models/dbo/Order.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; // Comment 3 | 4 | namespace ScaffoldingSample.Models.dbo 5 | { // Comment 6 | public partial class Order : EntityBase // My Handlebars Helper 7 | { 8 | public Order() 9 | { 10 | OrderDetails = new HashSet(); 11 | } 12 | 13 | public int OrderId { get; set; } 14 | public string? CustomerId { get; set; } 15 | public DateTime? OrderDate { get; set; } 16 | public DateTime? ShippedDate { get; set; } 17 | public int? ShipVia { get; set; } 18 | public decimal? Freight { get; set; } 19 | 20 | public virtual Customer? Customer { get; set; } 21 | public virtual ICollection OrderDetails { get; set; } 22 | 23 | // My Handlebars Block Helper: True 24 | // My Handlebars Block Helper: False 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/Models/dbo/OrderDetail.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; // Comment 3 | 4 | namespace ScaffoldingSample.Models.dbo 5 | { // Comment 6 | public partial class OrderDetail : EntityBase // My Handlebars Helper 7 | { 8 | public int OrderDetailId { get; set; } 9 | public int OrderId { get; set; } 10 | public int ProductId { get; set; } 11 | public decimal UnitPrice { get; set; } 12 | public short Quantity { get; set; } 13 | public float Discount { get; set; } 14 | 15 | public virtual Order Order { get; set; } = null!; 16 | public virtual Product Product { get; set; } = null!; 17 | 18 | // My Handlebars Block Helper: True 19 | // My Handlebars Block Helper: False 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/Models/dbo/Product.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; // Comment 3 | 4 | namespace ScaffoldingSample.Models.dbo 5 | { // Comment 6 | public partial class Product : EntityBase // My Handlebars Helper 7 | { 8 | public Product() 9 | { 10 | OrderDetails = new HashSet(); 11 | } 12 | 13 | public int ProductId { get; set; } 14 | public string ProductName { get; set; } = null!; 15 | public int? CategoryId { get; set; } 16 | public decimal? UnitPrice { get; set; } 17 | public bool Discontinued { get; set; } 18 | public byte[]? RowVersion { get; set; } 19 | 20 | public virtual Category? Category { get; set; } 21 | public virtual ICollection OrderDetails { get; set; } 22 | 23 | // My Handlebars Block Helper: True 24 | // My Handlebars Block Helper: False 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/Models/dbo/Territory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; // Comment 3 | 4 | namespace ScaffoldingSample.Models.dbo 5 | { // Comment 6 | public partial class Territory : EntityBase // My Handlebars Helper 7 | { 8 | public Territory() 9 | { 10 | Employees = new HashSet(); 11 | } 12 | 13 | public string TerritoryId { get; set; } = null!; 14 | public string TerritoryDescription { get; set; } = null!; 15 | 16 | public virtual ICollection Employees { get; set; } 17 | 18 | // My Handlebars Block Helper: True 19 | // My Handlebars Block Helper: False 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sample/ScaffoldingSample/ScaffoldingSample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | latest 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/CSharpDbContext/DbContext.hbs: -------------------------------------------------------------------------------- 1 | {{> dbimports}} 2 | 3 | namespace {{namespace}} 4 | { 5 | public partial class {{class}} : DbContext 6 | { 7 | {{{> dbsets}}} 8 | 9 | {{{> dbconstructor}}} 10 | 11 | {{#unless suppress-on-configuring}} 12 | {{{> dbonconfiguring}}} 13 | 14 | {{/unless}} 15 | {{{on-model-creating}}} 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/CSharpDbContext/Partials/DbConstructor.hbs: -------------------------------------------------------------------------------- 1 |  public {{class}}(DbContextOptions<{{class}}> options) : base(options) 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/CSharpDbContext/Partials/DbImports.hbs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata; 4 | {{#if model-namespace}} 5 | using {{model-namespace}}; 6 | {{/if}} 7 | {{#each model-imports}} 8 | using {{model-import}}; 9 | {{/each}} 10 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/CSharpDbContext/Partials/DbOnConfiguring.hbs: -------------------------------------------------------------------------------- 1 |  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 2 | { 3 | if (!optionsBuilder.IsConfigured) 4 | { 5 | {{#if connectionstring-warning}} 6 | {{connectionstring-warning}} 7 | {{/if}} 8 | optionsBuilder{{options-builder-provider}}; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/CSharpDbContext/Partials/DbSets.hbs: -------------------------------------------------------------------------------- 1 | {{#each dbsets}} 2 | public virtual DbSet<{{set-property-type}}> {{set-property-name}} { get; set; }{{#if nullable-reference-types }} = null!;{{/if}} 3 | {{/each}} 4 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/CSharpEntityType/Class.hbs: -------------------------------------------------------------------------------- 1 | {{> imports}} 2 | 3 | namespace {{namespace}} 4 | { 5 | {{#if comment}} 6 | /// 7 | {{comment}} 8 | /// 9 | {{/if}} 10 | {{#each class-annotations}} 11 | {{{class-annotation}}} 12 | {{/each}} 13 | public partial class {{class}} 14 | { 15 | {{{> constructor}}} 16 | {{{> properties}}} 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/CSharpEntityType/Partials/Constructor.hbs: -------------------------------------------------------------------------------- 1 | {{#if lines}} 2 | public {{class}}() 3 | { 4 | {{#each lines}} 5 | {{property-name}} = new HashSet<{{property-type}}>(); 6 | {{/each}} 7 | } 8 | 9 | {{/if}} 10 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/CSharpEntityType/Partials/Imports.hbs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | {{#if use-data-annotations}} 4 | using System.ComponentModel.DataAnnotations; 5 | using System.ComponentModel.DataAnnotations.Schema; 6 | using Microsoft.EntityFrameworkCore; 7 | {{/if}} 8 | {{#each imports}} 9 | using {{import}}; 10 | {{/each}} 11 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/CSharpEntityType/Partials/Properties.hbs: -------------------------------------------------------------------------------- 1 | {{#each properties}} 2 | {{#if property-comment}} 3 | 4 | /// 5 | {{property-comment}} 6 | /// 7 | {{/if}} 8 | {{#each property-annotations}} 9 | {{{property-annotation}}} 10 | {{/each}} 11 | public {{property-type}} {{property-name}} { get; set; }{{#if nullable-reference-types }}{{#unless property-isnullable}} = null!;{{/unless}}{{/if}} 12 | {{/each}} 13 | {{#if nav-properties}} 14 | 15 | {{#each nav-properties}} 16 | {{#each nav-property-annotations}} 17 | {{{nav-property-annotation}}} 18 | {{/each}} 19 | {{#if nav-property-collection}} 20 | public virtual ICollection<{{nav-property-type}}> {{nav-property-name}} { get; set; } 21 | {{else}} 22 | public virtual {{nav-property-type}} {{nav-property-name}} { get; set; }{{#if nullable-reference-types}}{{#unless nav-property-isnullable}} = null!;{{/unless}}{{/if}} 23 | {{/if}} 24 | {{/each}} 25 | {{/if}} 26 | {{#if skip-nav-properties}} 27 | 28 | {{#each skip-nav-properties}} 29 | {{#each nav-property-annotations}} 30 | {{{nav-property-annotation}}} 31 | {{/each}} 32 | {{#if nav-property-collection}} 33 | public virtual ICollection<{{nav-property-type}}> {{nav-property-name}} { get; set; } 34 | {{else}} 35 | public virtual {{nav-property-type}} {{nav-property-name}} { get; set; }{{#if nullable-reference-types}}{{#unless nav-property-isnullable}} = null!;{{/unless}}{{/if}} 36 | {{/if}} 37 | {{/each}} 38 | {{/if}} -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/TypeScriptDbContext/DbContext.hbs: -------------------------------------------------------------------------------- 1 | {{> dbimports}} 2 | 3 | namespace {{namespace}} 4 | { 5 | public partial class {{class}} : DbContext 6 | { 7 | {{{> dbsets}}} 8 | 9 | {{{> dbconstructor}}} 10 | 11 | {{#unless suppress-on-configuring}} 12 | {{{> dbonconfiguring}}} 13 | 14 | {{/unless}} 15 | {{{on-model-creating}}} 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/TypeScriptDbContext/Partials/DbConstructor.hbs: -------------------------------------------------------------------------------- 1 |  public {{class}}(DbContextOptions<{{class}}> options) : base(options) 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/TypeScriptDbContext/Partials/DbImports.hbs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata; 4 | {{#if model-namespace}} 5 | using {{model-namespace}}; 6 | {{/if}} 7 | {{#each model-imports}} 8 | using {{model-import}}; 9 | {{/each}} 10 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/TypeScriptDbContext/Partials/DbOnConfiguring.hbs: -------------------------------------------------------------------------------- 1 |  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 2 | { 3 | if (!optionsBuilder.IsConfigured) 4 | { 5 | {{#if connectionstring-warning}} 6 | {{connectionstring-warning}} 7 | {{/if}} 8 | optionsBuilder{{options-builder-provider}}; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/TypeScriptDbContext/Partials/DbSets.hbs: -------------------------------------------------------------------------------- 1 | {{#each dbsets}} 2 | public virtual DbSet<{{set-property-type}}> {{set-property-name}} { get; set; }{{#if nullable-reference-types }} = default!;{{/if}} 3 | {{/each}} 4 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/TypeScriptEntityType/Class.hbs: -------------------------------------------------------------------------------- 1 | {{> imports}} 2 | 3 | {{#if comment}} 4 | /** 5 | * {{comment}} 6 | */ 7 | {{/if}} 8 | export interface {{class}} { 9 | {{{> properties}}} 10 | } 11 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/TypeScriptEntityType/Partials/Constructor.hbs: -------------------------------------------------------------------------------- 1 |  constructor() { 2 | } 3 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/TypeScriptEntityType/Partials/Imports.hbs: -------------------------------------------------------------------------------- 1 | {{#each imports}} 2 | import { {{import}} } from './{{import}}'; 3 | {{/each}} 4 | -------------------------------------------------------------------------------- /sample/TemplatesAssembly/CodeTemplates/TypeScriptEntityType/Partials/Properties.hbs: -------------------------------------------------------------------------------- 1 | {{#each properties}} 2 | {{#if property-comment}} 3 | /** 4 | * {{property-comment}} 5 | */ 6 | {{/if}} 7 | {{property-name}}: {{property-type}}; 8 | {{/each}} 9 | {{#if nav-properties}} 10 | {{#each nav-properties}} 11 | {{#if nav-property-collection}} 12 | {{nav-property-name}}: {{nav-property-type}}[]; 13 | {{else}} 14 | {{nav-property-name}}: {{nav-property-type}}; 15 | {{/if}} 16 | {{/each}} 17 | {{/if}} 18 | {{#if skip-nav-properties}} 19 | {{#each skip-nav-properties}} 20 | {{#if nav-property-collection}} 21 | {{nav-property-name}}: {{nav-property-type}}[]; 22 | {{else}} 23 | {{nav-property-name}}: {{nav-property-type}}; 24 | {{/if}} 25 | {{/each}} 26 | {{/if}} -------------------------------------------------------------------------------- /sample/TemplatesAssembly/TemplatesAssembly.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/CSharpDbContext/DbContext.hbs: -------------------------------------------------------------------------------- 1 | {{> dbimports}} 2 | 3 | namespace {{namespace}} 4 | { 5 | public partial class {{class}} : DbContext 6 | { 7 | {{{> dbsets}}} 8 | 9 | {{{> dbconstructor}}} 10 | 11 | {{#unless suppress-on-configuring}} 12 | {{{> dbonconfiguring}}} 13 | 14 | {{/unless}} 15 | {{{on-model-creating}}} 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/CSharpDbContext/Partials/DbConstructor.hbs: -------------------------------------------------------------------------------- 1 |  public {{class}}() 2 | { 3 | } 4 | 5 | public {{class}}(DbContextOptions<{{class}}> options) : base(options) 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/CSharpDbContext/Partials/DbImports.hbs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | {{#if model-namespace}} 6 | using {{model-namespace}}; 7 | {{/if}} 8 | {{#each model-imports}} 9 | using {{model-import}}; 10 | {{/each}} 11 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/CSharpDbContext/Partials/DbOnConfiguring.hbs: -------------------------------------------------------------------------------- 1 |  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 2 | { 3 | if (!optionsBuilder.IsConfigured) 4 | { 5 | {{#if connectionstring-warning}} 6 | {{connectionstring-warning}} 7 | {{/if}} 8 | optionsBuilder{{options-builder-provider}}; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/CSharpDbContext/Partials/DbSets.hbs: -------------------------------------------------------------------------------- 1 | {{#each dbsets}} 2 | public virtual DbSet<{{set-property-type}}> {{set-property-name}} { get; set; }{{#if nullable-reference-types }} = null!;{{/if}} 3 | {{/each}} 4 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/CSharpEntityType/Class.hbs: -------------------------------------------------------------------------------- 1 | {{> imports}} 2 | 3 | namespace {{namespace}} 4 | { 5 | {{#if comment}} 6 | /// 7 | {{comment}} 8 | /// 9 | {{/if}} 10 | {{#each class-annotations}} 11 | {{{class-annotation}}} 12 | {{/each}} 13 | public partial class {{class}} 14 | { 15 | {{{> constructor}}} 16 | {{{> properties}}} 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/CSharpEntityType/Partials/Constructor.hbs: -------------------------------------------------------------------------------- 1 | {{#if lines}} 2 | public {{class}}() 3 | { 4 | {{#each lines}} 5 | {{property-name}} = new HashSet<{{property-type}}>(); 6 | {{/each}} 7 | } 8 | 9 | {{/if}} 10 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/CSharpEntityType/Partials/Imports.hbs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | {{#if use-data-annotations}} 4 | using System.ComponentModel.DataAnnotations; 5 | using System.ComponentModel.DataAnnotations.Schema; 6 | using Microsoft.EntityFrameworkCore; 7 | {{/if}} 8 | {{#each imports}} 9 | using {{import}}; 10 | {{/each}} 11 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/CSharpEntityType/Partials/Properties.hbs: -------------------------------------------------------------------------------- 1 | {{#each properties}} 2 | {{#if property-comment}} 3 | 4 | /// 5 | {{property-comment}} 6 | /// 7 | {{/if}} 8 | {{#each property-annotations}} 9 | {{{property-annotation}}} 10 | {{/each}} 11 | public {{property-type}} {{property-name}} { get; set; }{{#if nullable-reference-types }}{{#unless property-isnullable}} = null!;{{/unless}}{{else}}{{#if property-default-enum}} = {{property-default-enum}};{{/if}}{{/if}} 12 | {{/each}} 13 | {{#if nav-properties}} 14 | 15 | {{#each nav-properties}} 16 | {{#each nav-property-annotations}} 17 | {{{nav-property-annotation}}} 18 | {{/each}} 19 | {{#if nav-property-collection}} 20 | public virtual ICollection<{{nav-property-type}}> {{nav-property-name}} { get; set; } 21 | {{else}} 22 | public virtual {{nav-property-type}} {{nav-property-name}} { get; set; }{{#if nullable-reference-types}}{{#unless nav-property-isnullable}} = null!;{{/unless}}{{/if}} 23 | {{/if}} 24 | {{/each}} 25 | {{/if}} -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/TypeScriptDbContext/DbContext.hbs: -------------------------------------------------------------------------------- 1 | {{> dbimports}} 2 | 3 | namespace {{namespace}} 4 | { 5 | public partial class {{class}} : DbContext 6 | { 7 | {{{> dbsets}}} 8 | 9 | {{{> dbconstructor}}} 10 | 11 | {{#unless suppress-on-configuring}} 12 | {{{> dbonconfiguring}}} 13 | 14 | {{/unless}} 15 | {{{on-model-creating}}} 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/TypeScriptDbContext/Partials/DbConstructor.hbs: -------------------------------------------------------------------------------- 1 |  public {{class}}(DbContextOptions<{{class}}> options) : base(options) 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/TypeScriptDbContext/Partials/DbImports.hbs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | {{#if model-namespace}} 6 | using {{model-namespace}}; 7 | {{/if}} 8 | {{#each model-imports}} 9 | using {{model-import}}; 10 | {{/each}} 11 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/TypeScriptDbContext/Partials/DbOnConfiguring.hbs: -------------------------------------------------------------------------------- 1 |  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 2 | { 3 | if (!optionsBuilder.IsConfigured) 4 | { 5 | {{#if connectionstring-warning}} 6 | {{connectionstring-warning}} 7 | {{/if}} 8 | optionsBuilder{{options-builder-provider}}; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/TypeScriptDbContext/Partials/DbSets.hbs: -------------------------------------------------------------------------------- 1 | {{#each dbsets}} 2 | public virtual DbSet<{{set-property-type}}> {{set-property-name}} { get; set; }{{#if nullable-reference-types }} = default!;{{/if}} 3 | {{/each}} 4 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/TypeScriptEntityType/Class.hbs: -------------------------------------------------------------------------------- 1 | {{> imports}} 2 | 3 | {{#if comment}} 4 | /** 5 | * {{comment}} 6 | */ 7 | {{/if}} 8 | export interface {{class}} { 9 | {{{> properties}}} 10 | } 11 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/TypeScriptEntityType/Partials/Constructor.hbs: -------------------------------------------------------------------------------- 1 |  constructor() { 2 | } 3 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/TypeScriptEntityType/Partials/Imports.hbs: -------------------------------------------------------------------------------- 1 | {{#each imports}} 2 | import { {{import}} } from './{{import}}'; 3 | {{/each}} 4 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/TypeScriptEntityType/Partials/Properties.hbs: -------------------------------------------------------------------------------- 1 | {{#each properties}} 2 | {{#if property-comment}} 3 | /** 4 | * {{property-comment}} 5 | */ 6 | {{/if}} 7 | {{property-name}}: {{property-type}}; 8 | {{/each}} 9 | {{#if nav-properties}} 10 | {{#each nav-properties}} 11 | {{#if nav-property-collection}} 12 | {{nav-property-name}}: {{nav-property-type}}[]; 13 | {{else}} 14 | {{nav-property-name}}: {{nav-property-type}}; 15 | {{/if}} 16 | {{/each}} 17 | {{/if}} -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/EmbeddedResourceTemplateFileService.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Reflection; 3 | 4 | namespace EntityFrameworkCore.Scaffolding.Handlebars 5 | { 6 | /// 7 | /// Provides files to the template service from resources embedded in an assembly. 8 | /// 9 | public class EmbeddedResourceTemplateFileService : InMemoryTemplateFileService 10 | { 11 | private readonly Assembly _assembly; 12 | private readonly string _namespace; 13 | 14 | /// 15 | /// Constructor for the template file service. 16 | /// 17 | /// Assembly to get embedded resources from. 18 | /// Namespace of the resource files; this is generally the default namespace of the assembly. 19 | public EmbeddedResourceTemplateFileService(Assembly assembly, string @namespace) 20 | { 21 | _assembly = assembly; 22 | _namespace = @namespace; 23 | if (string.IsNullOrWhiteSpace(_namespace)) _namespace = _assembly.GetName().Name; 24 | } 25 | 26 | /// 27 | public override string RetrieveTemplateFileContents(string relativeDirectory, string fileName, string altRelativeDirectory = null) 28 | { 29 | string content; 30 | string resourceLocation = $"{_namespace}.{relativeDirectory.Replace('/', '.')}.{fileName}"; 31 | using (var stream = _assembly.GetManifestResourceStream(resourceLocation)) 32 | { 33 | using var reader = new StreamReader(stream); 34 | content = reader.ReadToEnd(); 35 | } 36 | 37 | return content; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/EntityFrameworkCore.Scaffolding.Handlebars.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/EntityPropertyInfo.cs: -------------------------------------------------------------------------------- 1 | namespace EntityFrameworkCore.Scaffolding.Handlebars 2 | { 3 | /// 4 | /// Entity property info. 5 | /// 6 | public class EntityPropertyInfo 7 | { 8 | /// 9 | /// Constructor. 10 | /// 11 | public EntityPropertyInfo() { } 12 | 13 | /// 14 | /// Constructor. 15 | /// 16 | /// Property type. 17 | /// Property name. 18 | /// Property is nullable. 19 | /// Is Enumeration Property Type 20 | /// Default Enumeration Value. Format will be EnumName.EnumValue 21 | public EntityPropertyInfo(string propertyType, string propertyName, bool? propertyIsNullable = null 22 | , bool? isEnumPropertyType = false, string propertyDefaultEnumValue = null) 23 | { 24 | PropertyType = propertyType; 25 | PropertyName = propertyName; 26 | PropertyIsNullable = propertyIsNullable; 27 | IsEnumPropertyType = isEnumPropertyType; 28 | PropertyDefaultEnumValue = propertyDefaultEnumValue; 29 | } 30 | 31 | /// 32 | /// Property type. 33 | /// 34 | public string PropertyType { get; set; } 35 | 36 | /// 37 | /// Property name. 38 | /// 39 | public string PropertyName { get; set; } 40 | 41 | /// 42 | /// Property is nullable. 43 | /// 44 | public bool? PropertyIsNullable { get; set; } 45 | /// 46 | /// Property Type is an Enumeration. 47 | /// Used in TransformPropertyTypeIfEnumaration 48 | /// for Many to Many Virtual EntityTypes 49 | /// 50 | public bool? IsEnumPropertyType { get; set; } 51 | /// 52 | /// Property Default Value when using Enumarations 53 | /// Format will be EnumName.EnumValue 54 | /// 55 | public string PropertyDefaultEnumValue { get; set; } 56 | } 57 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/FileSystemTemplateFileService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Reflection; 4 | using EntityFrameworkCore.Scaffolding.Handlebars.Internal; 5 | 6 | namespace EntityFrameworkCore.Scaffolding.Handlebars 7 | { 8 | /// 9 | /// Provides files to the template service from the file system. 10 | /// 11 | public class FileSystemTemplateFileService : FileSystemFileService, ITemplateFileService 12 | { 13 | /// 14 | /// Allows files to be stored for later retrieval. Used for testing purposes. 15 | /// 16 | /// Files used by the template service. 17 | /// Array of file paths. 18 | public virtual string[] InputFiles(params InputFile[] files) 19 | { 20 | var filePaths = new List(); 21 | 22 | foreach (var file in files) 23 | { 24 | var path = Path.Combine(file.Directory, file.File); 25 | filePaths.Add(path); 26 | } 27 | 28 | return filePaths.ToArray(); 29 | } 30 | 31 | /// 32 | /// Retreive template file contents from the file system. 33 | /// If template is not present, copy it locally. 34 | /// 35 | /// Relative directory name. 36 | /// File name. 37 | /// Alternative relative directory. Used for testing purposes. 38 | /// File contents. 39 | public virtual string RetrieveTemplateFileContents(string relativeDirectory, string fileName, 40 | string altRelativeDirectory = null) 41 | { 42 | string contents; 43 | string directory = altRelativeDirectory ?? relativeDirectory; 44 | string path = Path.Combine(directory, fileName); 45 | if (File.Exists(path)) 46 | { 47 | contents = RetrieveFileContents(directory, fileName); 48 | } 49 | else 50 | { 51 | var assemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 52 | var localDirectory = Path.Combine(assemblyDirectory, relativeDirectory); 53 | var templateContents = RetrieveFileContents(localDirectory, fileName); 54 | OutputFile(directory, fileName, templateContents); 55 | contents = RetrieveFileContents(directory, fileName); 56 | } 57 | return contents; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | 6 | using System.Diagnostics.CodeAnalysis; 7 | 8 | [assembly: SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "", Scope = "type", Target = "~T:EntityFrameworkCore.Scaffolding.Handlebars.HbsCSharpDbContextGenerator")] 9 | [assembly: SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "", Scope = "type", Target = "~T:EntityFrameworkCore.Scaffolding.Handlebars.HbsCSharpModelGenerator")] 10 | [assembly: SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "", Scope = "type", Target = "~T:EntityFrameworkCore.Scaffolding.Handlebars.HbsTypeScriptModelGenerator")] 11 | [assembly: SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "", Scope = "type", Target = "~T:EntityFrameworkCore.Scaffolding.Handlebars.HbsCSharpEntityTypeGenerator")] 12 | [assembly: SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "", Scope = "type", Target = "~T:EntityFrameworkCore.Scaffolding.Handlebars.HbsReverseEngineerScaffolder")] 13 | [assembly: SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "", Scope = "type", Target = "~T:EntityFrameworkCore.Scaffolding.Handlebars.HbsTypeScriptEntityTypeGenerator")] 14 | [assembly: SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "", Scope = "type", Target = "~T:EntityFrameworkCore.Scaffolding.Handlebars.NullCSharpDbContextGenerator")] 15 | [assembly: SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "", Scope = "member", Target = "~M:Microsoft.EntityFrameworkCore.Design.ServiceCollectionExtensions.AddHandlebarsScaffolding(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Action{EntityFrameworkCore.Scaffolding.Handlebars.HandlebarsScaffoldingOptions})~Microsoft.Extensions.DependencyInjection.IServiceCollection")] 16 | [assembly: SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "", Scope = "type", Target = "~T:EntityFrameworkCore.Scaffolding.Handlebars.NullCSharpEntityTypeGenerator")] 17 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/HandlebarsScaffoldingOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using Microsoft.EntityFrameworkCore.Design; 5 | 6 | namespace EntityFrameworkCore.Scaffolding.Handlebars 7 | { 8 | /// 9 | /// Options for generating scaffolding with handlebars. 10 | /// 11 | public class HandlebarsScaffoldingOptions 12 | { 13 | /// 14 | /// Gets or sets which type of scaffolding should be generated. 15 | /// 16 | public ReverseEngineerOptions ReverseEngineerOptions { get; set; } = ReverseEngineerOptions.DbContextAndEntities; 17 | 18 | /// 19 | /// Gets or sets language options for generated scaffolding. 20 | /// 21 | public LanguageOptions LanguageOptions { get; set; } 22 | 23 | /// 24 | /// Gets or sets tables that should be excluded from; can include schema. 25 | /// 26 | public List ExcludedTables { get; set; } 27 | 28 | /// 29 | /// Gets or sets Template data to pass in to template creation. 30 | /// 31 | public IDictionary TemplateData { get; set; } 32 | 33 | /// 34 | /// Gets or sets an assembly to read embedded templates from (optional). 35 | /// 36 | public Assembly EmbeddedTemplatesAssembly { get; set; } 37 | 38 | /// 39 | /// Gets or sets the namespace of the embedded templates to read (optional). 40 | /// 41 | public string EmbeddedTemplatesNamespace { get; set; } 42 | 43 | /// 44 | /// Gets or sets if schema folders are created for table entity classes as per db schema naming. 45 | /// 46 | public bool EnableSchemaFolders { get; set; } 47 | 48 | /// 49 | /// Gets or sets whether entity properties are declared and instantiated in the C# 8.0+ nullable reference types style (optional). 50 | /// https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references 51 | /// https://docs.microsoft.com/en-us/ef/core/miscellaneous/nullable-reference-types 52 | /// 53 | [Obsolete("Deprecated in favor of support for nullable reference types in EF Core 6.", true)] 54 | public bool EnableNullableReferenceTypes { get; set; } 55 | 56 | /// 57 | /// Gets or sets whether table and column descriptions generate XML comments. 58 | /// 59 | public bool GenerateComments { get; set; } = true; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/HbsBlockHelperService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using HandlebarsDotNet; 4 | 5 | namespace EntityFrameworkCore.Scaffolding.Handlebars 6 | { 7 | /// 8 | /// Provide services required to register Handlebars block helpers. 9 | /// 10 | public class HbsBlockHelperService : IHbsBlockHelperService 11 | { 12 | /// 13 | /// Handlebars block helpers. 14 | /// 15 | public Dictionary> Helpers { get; } 16 | 17 | /// 18 | /// Constructor for the Handlebars block helper service. 19 | /// 20 | /// Dictionary of Handlebars helpers. 21 | public HbsBlockHelperService(Dictionary> helpers) 22 | { 23 | Helpers = helpers; 24 | } 25 | 26 | /// 27 | /// Register Handlebars block helpers. 28 | /// 29 | public void RegisterBlockHelpers() 30 | { 31 | foreach (var helper in Helpers) 32 | HandlebarsDotNet.Handlebars.RegisterHelper(helper.Key, 33 | (output, options, context, args) => helper.Value(output, options, context, args)); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/HbsContextTransformationService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace EntityFrameworkCore.Scaffolding.Handlebars 3 | { 4 | /// 5 | /// Default service for transforming context definitions. 6 | /// 7 | public class HbsContextTransformationService : IContextTransformationService 8 | { 9 | /// 10 | /// Context file name transformer. 11 | /// 12 | public Func ContextFileNameTransformer { get; } 13 | 14 | /// 15 | /// HbsContextTransformationService constructor. 16 | /// 17 | /// Context file name transformer. 18 | public HbsContextTransformationService( 19 | Func contextFileNameTransformer = null) 20 | { 21 | ContextFileNameTransformer = contextFileNameTransformer; 22 | } 23 | 24 | /// 25 | /// Transform context file name. 26 | /// 27 | /// Context file name. 28 | /// Transformed context file name. 29 | public string TransformContextFileName(string contextFileName) => 30 | ContextFileNameTransformer?.Invoke(contextFileName) ?? contextFileName; 31 | } 32 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/HbsEntityTypeTemplateService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Globalization; 3 | using EntityFrameworkCore.Scaffolding.Handlebars.Helpers; 4 | using HandlebarsDotNet; 5 | using Microsoft.EntityFrameworkCore.Design; 6 | using HandlebarsLib = HandlebarsDotNet.Handlebars; 7 | 8 | namespace EntityFrameworkCore.Scaffolding.Handlebars 9 | { 10 | /// 11 | /// Provide services required to generate entity type classes using Handlebars templates. 12 | /// 13 | public class HbsEntityTypeTemplateService : HbsTemplateService, IEntityTypeTemplateService 14 | { 15 | private Dictionary EntitiesTemplateFiles { get; } 16 | 17 | /// 18 | /// Entity type template. 19 | /// 20 | public HandlebarsTemplate EntityTypeTemplate { get; private set; } 21 | 22 | /// 23 | /// Constructor for entity type template service. 24 | /// 25 | /// Template file service. 26 | /// Template language service. 27 | public HbsEntityTypeTemplateService(ITemplateFileService fileService, 28 | ITemplateLanguageService languageService) : base(fileService, languageService) 29 | { 30 | EntitiesTemplateFiles = LanguageService.GetEntitiesTemplateFileInfo(); 31 | } 32 | 33 | /// 34 | /// Generate entity type class. 35 | /// 36 | /// Data used to generate entity type class. 37 | /// Generated entity type class. 38 | public virtual string GenerateEntityType(object data) 39 | { 40 | if (EntityTypeTemplate == null) 41 | { 42 | EntityTypeTemplate = CompileEntityTypeTemplate(); 43 | } 44 | string entityType = EntityTypeTemplate(data); 45 | return entityType; 46 | } 47 | 48 | /// 49 | /// Compile entity type template. 50 | /// 51 | /// Language option. 52 | /// Entity type template. 53 | protected virtual HandlebarsTemplate CompileEntityTypeTemplate( 54 | LanguageOptions language = LanguageOptions.CSharp) 55 | { 56 | EntitiesTemplateFiles.TryGetValue(Constants.EntityTypeTemplate, out TemplateFileInfo classFile); 57 | var entityTemplateFile = FileService.RetrieveTemplateFileContents( 58 | classFile.RelativeDirectory, classFile.FileName); 59 | var entityTemplate = HandlebarsLib.Compile(entityTemplateFile); 60 | return entityTemplate; 61 | } 62 | 63 | /// 64 | /// Get partial templates. 65 | /// 66 | /// Language option. 67 | /// Partial templates. 68 | protected override IDictionary GetPartialTemplates( 69 | LanguageOptions language = LanguageOptions.CSharp) 70 | { 71 | EntitiesTemplateFiles.TryGetValue(Constants.EntityTypeCtorTemplate, out TemplateFileInfo ctorFile); 72 | var ctorTemplateFile = FileService.RetrieveTemplateFileContents( 73 | ctorFile.RelativeDirectory, ctorFile.FileName); 74 | 75 | EntitiesTemplateFiles.TryGetValue(Constants.EntityTypeImportTemplate, out TemplateFileInfo importFile); 76 | var importTemplateFile = FileService.RetrieveTemplateFileContents( 77 | importFile.RelativeDirectory, importFile.FileName); 78 | 79 | EntitiesTemplateFiles.TryGetValue(Constants.EntityTypePropertyTemplate, out TemplateFileInfo propertyFile); 80 | var propertyTemplateFile = FileService.RetrieveTemplateFileContents( 81 | propertyFile.RelativeDirectory, propertyFile.FileName); 82 | 83 | var templates = new Dictionary 84 | { 85 | { 86 | Constants.EntityTypeCtorTemplate.ToLower(CultureInfo.InvariantCulture), 87 | ctorTemplateFile 88 | }, 89 | { 90 | Constants.EntityTypeImportTemplate.ToLower(CultureInfo.InvariantCulture), 91 | importTemplateFile 92 | }, 93 | { 94 | Constants.EntityTypePropertyTemplate.ToLower(CultureInfo.InvariantCulture), 95 | propertyTemplateFile 96 | }, 97 | }; 98 | return templates; 99 | } 100 | } 101 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/HbsEntityTypeTransformationService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace EntityFrameworkCore.Scaffolding.Handlebars 3 | { 4 | /// 5 | /// Default service for transforming entity type definitions. 6 | /// 7 | public class HbsEntityTypeTransformationService : HbsEntityTypeTransformationServiceBase 8 | { 9 | /// 10 | /// Entity name transformer. 11 | /// 12 | public new Func EntityTypeNameTransformer { get => base.EntityTypeNameTransformer; } 13 | 14 | /// 15 | /// Entity file name transformer. 16 | /// 17 | public new Func EntityFileNameTransformer { get => base.EntityFileNameTransformer; } 18 | 19 | /// 20 | /// Constructor transformer. 21 | /// 22 | public new Func ConstructorTransformer { get => base.ConstructorTransformer; } 23 | 24 | /// 25 | /// Property name transformer. 26 | /// 27 | public new Func PropertyTransformer { get => base.PropertyTransformer; } 28 | 29 | /// 30 | /// Navigation property name transformer. 31 | /// 32 | public new Func NavPropertyTransformer { get => base.NavPropertyTransformer; } 33 | 34 | /// 35 | /// HbsEntityTypeTransformationService constructor. 36 | /// 37 | /// Entity type name transformer. 38 | /// Entity file name transformer. 39 | /// Constructor transformer. 40 | /// Property name transformer. 41 | /// Navigation property name transformer. 42 | public HbsEntityTypeTransformationService( 43 | Func entityTypeNameTransformer = null, 44 | Func entityFileNameTransformer = null, 45 | Func constructorTransformer = null, 46 | Func propertyTransformer = null, 47 | Func navPropertyTransformer = null) 48 | : base(entityTypeNameTransformer, entityFileNameTransformer) 49 | { 50 | base.ConstructorTransformer = constructorTransformer; 51 | base.PropertyTransformer = propertyTransformer; 52 | base.NavPropertyTransformer = navPropertyTransformer; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/HbsEntityTypeTransformationService2.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Metadata; 2 | using System; 3 | namespace EntityFrameworkCore.Scaffolding.Handlebars 4 | { 5 | /// 6 | /// Default service for transforming entity type definitions. 7 | /// 8 | public class HbsEntityTypeTransformationService2 : HbsEntityTypeTransformationServiceBase 9 | { 10 | /// 11 | /// Entity name transformer. 12 | /// 13 | public new Func EntityTypeNameTransformer { get => base.EntityTypeNameTransformer; } 14 | 15 | /// 16 | /// Entity file name transformer. 17 | /// 18 | public new Func EntityFileNameTransformer { get => base.EntityFileNameTransformer; } 19 | 20 | /// 21 | /// Constructor transformer. 22 | /// 23 | public new Func ConstructorTransformer { get => ConstructorTransformer2; } 24 | 25 | /// 26 | /// Property name transformer. 27 | /// 28 | public new Func PropertyTransformer { get => PropertyTransformer2; } 29 | 30 | /// 31 | /// Navigation property name transformer. 32 | /// 33 | public new Func NavPropertyTransformer { get => NavPropertyTransformer2; } 34 | 35 | /// 36 | /// HbsEntityTypeTransformationService constructor. 37 | /// 38 | /// Entity type name transformer. 39 | /// Entity file name transformer. 40 | /// Constructor transformer. 41 | /// Property name transformer. 42 | /// Navigation property name transformer. 43 | public HbsEntityTypeTransformationService2( 44 | Func entityTypeNameTransformer = null, 45 | Func entityFileNameTransformer = null, 46 | Func constructorTransformer = null, 47 | Func propertyTransformer = null, 48 | Func navPropertyTransformer = null) 49 | : base(entityTypeNameTransformer, entityFileNameTransformer) 50 | { 51 | ConstructorTransformer2 = constructorTransformer; 52 | PropertyTransformer2 = propertyTransformer; 53 | NavPropertyTransformer2 = navPropertyTransformer; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/HbsHelperService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using HandlebarsDotNet; 4 | using HandlebarsLib = HandlebarsDotNet.Handlebars; 5 | 6 | namespace EntityFrameworkCore.Scaffolding.Handlebars 7 | { 8 | /// 9 | /// Provide services required to register Handlebars helpers. 10 | /// 11 | public class HbsHelperService : IHbsHelperService 12 | { 13 | /// 14 | /// Handlebars helpers. 15 | /// 16 | public Dictionary> Helpers { get; } 17 | 18 | /// 19 | /// Constructor for the Handlebars helper service. 20 | /// 21 | /// Dictionary of Handlebars helpers. 22 | public HbsHelperService(Dictionary> helpers) 23 | { 24 | Helpers = helpers; 25 | } 26 | 27 | /// 28 | /// Register Handlebars helpers. 29 | /// 30 | public void RegisterHelpers() 31 | { 32 | foreach (var helper in Helpers) 33 | HandlebarsLib.RegisterHelper(helper.Key, 34 | (output, context, args) => helper.Value(output, context, args)); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/HbsTemplateService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Design; 2 | using System.Collections.Generic; 3 | using HandlebarsLib = HandlebarsDotNet.Handlebars; 4 | 5 | namespace EntityFrameworkCore.Scaffolding.Handlebars 6 | { 7 | /// 8 | /// Provide services required to generate classes using Handlebars templates. 9 | /// 10 | public abstract class HbsTemplateService : IHbsTemplateService 11 | { 12 | /// 13 | /// Template file service. 14 | /// 15 | protected readonly ITemplateFileService FileService; 16 | 17 | /// 18 | /// Template language service. 19 | /// 20 | protected readonly ITemplateLanguageService LanguageService; 21 | 22 | /// 23 | /// Constructor for the template service. 24 | /// 25 | /// Template file service. 26 | /// Template language service. 27 | protected HbsTemplateService(ITemplateFileService fileService, 28 | ITemplateLanguageService languageService) 29 | { 30 | FileService = fileService; 31 | LanguageService = languageService; 32 | } 33 | 34 | /// 35 | /// Register partial templates. 36 | /// 37 | public virtual void RegisterPartialTemplates() 38 | { 39 | var partialTemplates = GetPartialTemplates(); 40 | foreach (var partialTemplate in partialTemplates) 41 | { 42 | HandlebarsLib.RegisterTemplate(partialTemplate.Key, partialTemplate.Value); 43 | } 44 | } 45 | 46 | /// 47 | /// Get partial templates. 48 | /// 49 | /// Language option. 50 | /// Partial templates. 51 | protected abstract IDictionary GetPartialTemplates( 52 | LanguageOptions language = LanguageOptions.CSharp); 53 | } 54 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/Helpers/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace EntityFrameworkCore.Scaffolding.Handlebars.Helpers 2 | { 3 | /// 4 | /// Constants used by the Handlebars scaffolding generator. 5 | /// 6 | public static class Constants 7 | { 8 | /// Spaces Handlebars helper. 9 | public const string SpacesHelper = "spaces"; 10 | 11 | /// Handlebars templates file extension. 12 | public const string TemplateExtension = ".hbs"; 13 | 14 | /// Code templates folder. 15 | public const string CodeTemplatesDirectory = "CodeTemplates"; 16 | 17 | /// Entity type template. 18 | public const string EntityTypeTemplate = "Class"; 19 | 20 | /// Entity type constructor template. 21 | public const string EntityTypeCtorTemplate = "Constructor"; 22 | 23 | /// Entity type imports template. 24 | public const string EntityTypeImportTemplate = "Imports"; 25 | 26 | /// Entity type properties template. 27 | public const string EntityTypePropertyTemplate = "Properties"; 28 | 29 | /// DbContext template. 30 | public const string DbContextTemplate = "DbContext"; 31 | 32 | /// DbContext imports template. 33 | public const string DbContextImportTemplate = "DbImports"; 34 | 35 | /// DbContext constructor template. 36 | public const string DbContextCtorTemplate = "DbConstructor"; 37 | 38 | /// DbContext OnConfiguring template. 39 | public const string DbContextOnConfiguringTemplate = "DbOnConfiguring"; 40 | 41 | /// DbContext DbSets template. 42 | public const string DbContextDbSetsTemplate = "DbSets"; 43 | 44 | /// C# template folders. 45 | public static class CSharpTemplateDirectories 46 | { 47 | /// DbContext C# template folder. 48 | public const string DbContextDirectory = CodeTemplatesDirectory + "/CSharpDbContext"; 49 | 50 | /// DbContext partial C# templates folder. 51 | public const string DbContextPartialsDirectory = DbContextDirectory + "/Partials"; 52 | 53 | /// Entity type C# template folder. 54 | public const string EntityTypeDirectory = CodeTemplatesDirectory + "/CSharpEntityType"; 55 | 56 | /// Entity type partial C# templates folder. 57 | public const string EntityTypePartialsDirectory = EntityTypeDirectory + "/Partials"; 58 | } 59 | 60 | /// TypeScript template folders. 61 | public static class TypeScriptTemplateDirectories 62 | { 63 | /// DbContext TypeScript template folder. 64 | public const string DbContextDirectory = CodeTemplatesDirectory + "/TypeScriptDbContext"; 65 | 66 | /// DbContext partial TypeScript templates folder. 67 | public const string DbContextPartialsDirectory = DbContextDirectory + "/Partials"; 68 | 69 | /// Entity type TypeScript template folder. 70 | public const string EntityTypeDirectory = CodeTemplatesDirectory + "/TypeScriptEntityType"; 71 | 72 | /// Entity type partial TypeScript templates folder. 73 | public const string EntityTypePartialsDirectory = EntityTypeDirectory + "/Partials"; 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/Helpers/HandlebarsHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using HandlebarsDotNet; 3 | 4 | namespace EntityFrameworkCore.Scaffolding.Handlebars.Helpers 5 | { 6 | /// 7 | /// Handlebars helpers used by the scaffolding generator. 8 | /// 9 | public static class HandlebarsHelpers 10 | { 11 | /// 12 | /// Get the spaces Handlebars helper. 13 | /// 14 | /// Spaces Handlebars helper. 15 | public static Action SpacesHelper 16 | => (writer, context, parameters) => 17 | { 18 | var spaces = string.Empty; 19 | if (parameters.Length > 0 20 | && parameters[0] is string param 21 | && int.TryParse(param, out int count)) 22 | { 23 | for (int i = 0; i < count; i++) 24 | spaces += " "; 25 | } 26 | writer.Write(spaces); 27 | }; 28 | } 29 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/IContextTransformationService.cs: -------------------------------------------------------------------------------- 1 | namespace EntityFrameworkCore.Scaffolding.Handlebars 2 | { 3 | /// 4 | /// Service for transforming context definitions. 5 | /// 6 | public interface IContextTransformationService 7 | { 8 | /// 9 | /// Transform context file name. 10 | /// 11 | /// Context file name. 12 | /// Transformed entity file name. 13 | string TransformContextFileName(string contextFileName); 14 | } 15 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/IDbContextTemplateService.cs: -------------------------------------------------------------------------------- 1 | using HandlebarsDotNet; 2 | 3 | namespace EntityFrameworkCore.Scaffolding.Handlebars 4 | { 5 | /// 6 | /// Provide services required to generate the DbContext class using Handlebars templates. 7 | /// 8 | public interface IDbContextTemplateService : IHbsTemplateService 9 | { 10 | /// 11 | /// DbContext template. 12 | /// 13 | HandlebarsTemplate DbContextTemplate { get; } 14 | 15 | /// 16 | /// Generate DbContext class. 17 | /// 18 | /// Data used to generate DbContext class. 19 | /// Generated DbContext class. 20 | string GenerateDbContext(object data); 21 | } 22 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/IEntityTypeTemplateService.cs: -------------------------------------------------------------------------------- 1 | using HandlebarsDotNet; 2 | 3 | namespace EntityFrameworkCore.Scaffolding.Handlebars 4 | { 5 | /// 6 | /// Provide services required to generate entity type classes using Handlebars templates. 7 | /// 8 | public interface IEntityTypeTemplateService : IHbsTemplateService 9 | { 10 | /// 11 | /// Entity type template. 12 | /// 13 | HandlebarsTemplate EntityTypeTemplate { get; } 14 | 15 | /// 16 | /// Generate entity type class. 17 | /// 18 | /// Data used to generate entity type class. 19 | /// Generated entity type class. 20 | string GenerateEntityType(object data); 21 | } 22 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/IEntityTypeTransformationService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Metadata; 2 | using System.Collections.Generic; 3 | 4 | namespace EntityFrameworkCore.Scaffolding.Handlebars 5 | { 6 | /// 7 | /// Service for transforming entity type definitions. 8 | /// 9 | public interface IEntityTypeTransformationService 10 | { 11 | /// 12 | /// Transform entity type name. 13 | /// 14 | /// Entity type name. 15 | /// Transformed entity type name. 16 | string TransformTypeEntityName(string entityName); 17 | 18 | /// 19 | /// Transform entity file name. 20 | /// 21 | /// Entity file name. 22 | /// Transformed entity file name. 23 | string TransformEntityFileName(string entityFileName); 24 | 25 | /// 26 | /// Transform single property name. 27 | /// 28 | /// Entity type. 29 | /// Property name. 30 | /// Property type 31 | /// Transformed property name. 32 | string TransformPropertyName(IEntityType entityType, string propertyName, string propertyType); 33 | 34 | /// 35 | /// Transform single navigation property name. 36 | /// 37 | /// Entity type. 38 | /// Property name. 39 | /// Property type 40 | /// Transformed property name. 41 | string TransformNavPropertyName(IEntityType entityType, string propertyName, string propertyType); 42 | 43 | /// 44 | /// Transforms the Property Type if it is an Enumeration. 45 | /// Returns null when not an Enumeration 46 | /// 47 | /// Entity type. 48 | /// Property name. 49 | /// Property type 50 | /// Transformed property name, null when not an Enumeration 51 | public string TransformPropertyTypeIfEnumaration(IEntityType entityType, string propertyName, string propertyType); 52 | 53 | /// 54 | /// Transform Default Enum Value for a property 55 | /// 56 | /// Entity type. 57 | /// Property name. 58 | /// Property type 59 | /// Default Enumeration Value in format Format will be EnumName.EnumValue 60 | public string TransformPropertyDefaultEnum(IEntityType entityType, string propertyName, string propertyType); 61 | 62 | /// 63 | /// Transform entity type constructor. 64 | /// 65 | /// Entity type. 66 | /// Constructor lines. 67 | /// Transformed constructor lines. 68 | List> TransformConstructor(IEntityType entityType, List> lines); 69 | 70 | /// 71 | /// Transform entity type properties. 72 | /// 73 | /// Entity type. 74 | /// Entity type properties. 75 | /// Transformed entity type properties. 76 | List> TransformProperties(IEntityType entityType, List> properties); 77 | 78 | /// 79 | /// Transform entity type navigation properties. 80 | /// 81 | /// Entity type. 82 | /// Entity type navigation properties. 83 | /// Transformed entity type navigation properties. 84 | /// 85 | List> TransformNavigationProperties(IEntityType entityType, List> navProperties); 86 | } 87 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/IHbsBlockHelperService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using HandlebarsDotNet; 4 | 5 | namespace EntityFrameworkCore.Scaffolding.Handlebars 6 | { 7 | /// 8 | /// Provide services required to register Handlebars block helpers. 9 | /// 10 | public interface IHbsBlockHelperService 11 | { 12 | /// 13 | /// Handlebars block helpers. 14 | /// 15 | Dictionary> Helpers { get; } 16 | 17 | /// 18 | /// Register Handlebars block helpers. 19 | /// 20 | void RegisterBlockHelpers(); 21 | } 22 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/IHbsHelperService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using HandlebarsDotNet; 4 | 5 | namespace EntityFrameworkCore.Scaffolding.Handlebars 6 | { 7 | /// 8 | /// Provide services required to register Handlebars helpers. 9 | /// 10 | public interface IHbsHelperService 11 | { 12 | /// 13 | /// Handlebars helpers. 14 | /// 15 | Dictionary> Helpers { get; } 16 | 17 | /// 18 | /// Register Handlebars helpers. 19 | /// 20 | void RegisterHelpers(); 21 | } 22 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/IHbsTemplateService.cs: -------------------------------------------------------------------------------- 1 | namespace EntityFrameworkCore.Scaffolding.Handlebars 2 | { 3 | /// 4 | /// Provide services required to generate classes using Handlebars templates. 5 | /// 6 | public interface IHbsTemplateService 7 | { 8 | /// 9 | /// Register partial templates. 10 | /// 11 | void RegisterPartialTemplates(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/IModelExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using EntityFrameworkCore.Scaffolding.Handlebars.Internal; 5 | using Microsoft.EntityFrameworkCore; 6 | using Microsoft.EntityFrameworkCore.Metadata; 7 | 8 | namespace EntityFrameworkCore.Scaffolding.Handlebars 9 | { 10 | /// 11 | /// Extension methods for Entity Framework class. 12 | /// 13 | public static class IModelExtensions 14 | { 15 | /// 16 | /// Gets all entity types that are to be used in scaffolding. 17 | /// 18 | /// Model to retrieve entity types from. 19 | /// Scaffolding options to use in determining entity types. 20 | /// Filtered set of entity types for scaffolding. 21 | public static IEnumerable GetScaffoldEntityTypes(this IModel model, HandlebarsScaffoldingOptions options) 22 | { 23 | var entityTypes = model.GetEntityTypes(); 24 | if (options.ExcludedTables != null && options.ExcludedTables.Any()) 25 | { 26 | // Handle matching view or table name for excludes. 27 | var excludedTables = options.ExcludedTables.Select(t => new TableAndSchema(t)).ToList(); 28 | entityTypes = (from type in entityTypes 29 | let name = type.GetTableName() 30 | let isTable = !string.IsNullOrEmpty(name) 31 | let table = isTable 32 | ? type.GetTableName() 33 | : type.GetViewName() 34 | let schema = isTable 35 | ? type.GetSchema() 36 | : type.GetViewSchema() 37 | where !excludedTables.Any(e => 38 | (string.IsNullOrEmpty(e.Schema) || 39 | string.Equals(schema, e.Schema, StringComparison.OrdinalIgnoreCase)) 40 | && string.Equals(table, e.Table, StringComparison.OrdinalIgnoreCase)) 41 | select type).ToList(); 42 | } 43 | 44 | return entityTypes; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/ITemplateFileService.cs: -------------------------------------------------------------------------------- 1 | using EntityFrameworkCore.Scaffolding.Handlebars.Internal; 2 | 3 | namespace EntityFrameworkCore.Scaffolding.Handlebars 4 | { 5 | /// 6 | /// Provides files to the template service. 7 | /// 8 | public interface ITemplateFileService : IFileService 9 | { 10 | /// 11 | /// Allows files to be stored for later retrieval. Used for testing purposes. 12 | /// 13 | /// Files used by the template service. 14 | /// Array of file paths. 15 | string[] InputFiles(params InputFile[] files); 16 | 17 | /// 18 | /// Retreive template file contents from the file system. 19 | /// If template is not present, copy it locally. 20 | /// 21 | /// Relative directory name. 22 | /// File name. 23 | /// Alternative relative directory. Used for testing purposes. 24 | /// File contents. 25 | string RetrieveTemplateFileContents(string relativeDirectory, string fileName, 26 | string altRelativeDirectory = null); 27 | } 28 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/ITemplateLanguageService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace EntityFrameworkCore.Scaffolding.Handlebars 4 | { 5 | /// 6 | /// Provide services to obtain template file information. 7 | /// 8 | public interface ITemplateLanguageService 9 | { 10 | /// 11 | /// Get DbContext template file information. 12 | /// 13 | /// Dictionary of templates with file information. 14 | Dictionary GetDbContextTemplateFileInfo(); 15 | 16 | /// 17 | /// Get Entities template file information. 18 | /// 19 | /// Dictionary of templates with file information. 20 | Dictionary GetEntitiesTemplateFileInfo(); 21 | } 22 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/ITypeScriptHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EntityFrameworkCore.Scaffolding.Handlebars 4 | { 5 | /// 6 | /// TypeScript Helper 7 | /// 8 | public interface ITypeScriptHelper 9 | { 10 | /// 11 | /// Convert CLR type to TypeScript type 12 | /// 13 | /// CLR type. 14 | /// TypeScript type 15 | string TypeName(Type clrType); 16 | 17 | /// 18 | /// Convert string to camel case. 19 | /// 20 | /// Input string. 21 | /// Input string in camel case. 22 | string ToCamelCase(string s); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/InMemoryTemplateFileService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using EntityFrameworkCore.Scaffolding.Handlebars.Internal; 4 | 5 | namespace EntityFrameworkCore.Scaffolding.Handlebars 6 | { 7 | /// 8 | /// Provides files to the template service from an in-memory store. 9 | /// 10 | public class InMemoryTemplateFileService : InMemoryFileService, ITemplateFileService 11 | { 12 | /// 13 | /// Allows files to be stored for later retrieval. Used for testing purposes. 14 | /// 15 | /// Files used by the template service. 16 | /// Array of file paths. 17 | public virtual string[] InputFiles(params InputFile[] files) 18 | { 19 | var filePaths = new List(); 20 | 21 | foreach (var file in files) 22 | { 23 | if (!NameToContentMap.TryGetValue(file.Directory, out var filesMap)) 24 | { 25 | filesMap = new Dictionary(); 26 | NameToContentMap[file.Directory] = filesMap; 27 | } 28 | 29 | filesMap[file.File] = file.Contents; 30 | 31 | var path = Path.Combine(file.Directory, file.File); 32 | filePaths.Add(path); 33 | } 34 | 35 | return filePaths.ToArray(); 36 | } 37 | 38 | /// 39 | /// Retrieve template file contents from the file system. 40 | /// If template is not present, copy it locally. 41 | /// 42 | /// Relative directory name. 43 | /// File name. 44 | /// Alternative relative directory. Used for testing purposes. 45 | /// File contents. 46 | public virtual string RetrieveTemplateFileContents(string relativeDirectory, string fileName, string altRelativeDirectory = null) 47 | { 48 | return RetrieveFileContents(relativeDirectory, fileName); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/InputFile.cs: -------------------------------------------------------------------------------- 1 | namespace EntityFrameworkCore.Scaffolding.Handlebars 2 | { 3 | /// 4 | /// File supplied to template file service. 5 | /// 6 | public class InputFile 7 | { 8 | /// 9 | /// Directory name. 10 | /// 11 | public string Directory { get; set; } 12 | 13 | /// 14 | /// File name. 15 | /// 16 | public string File { get; set; } 17 | 18 | /// 19 | /// File contents. 20 | /// 21 | public string Contents { get; set; } 22 | } 23 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/Internal/Check.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using JetBrains.Annotations; 6 | using Microsoft.EntityFrameworkCore.Diagnostics; 7 | 8 | namespace EntityFrameworkCore.Scaffolding.Handlebars.Internal 9 | { 10 | [DebuggerStepThrough] 11 | internal class Check 12 | { 13 | [ContractAnnotation("value:null => halt")] 14 | public static T NotNull([NoEnumeration] T value, [InvokerParameterName] [NotNull] string parameterName) 15 | { 16 | #pragma warning disable IDE0041 // Use 'is null' check 17 | if (ReferenceEquals(value, null)) 18 | #pragma warning restore IDE0041 // Use 'is null' check 19 | { 20 | NotEmpty(parameterName, nameof(parameterName)); 21 | 22 | throw new ArgumentNullException(parameterName); 23 | } 24 | 25 | return value; 26 | } 27 | 28 | [ContractAnnotation("value:null => halt")] 29 | public static IReadOnlyList NotEmpty(IReadOnlyList value, [InvokerParameterName] [NotNull] string parameterName) 30 | { 31 | NotNull(value, parameterName); 32 | 33 | if (value.Count == 0) 34 | { 35 | NotEmpty(parameterName, nameof(parameterName)); 36 | 37 | throw new ArgumentException(AbstractionsStrings.CollectionArgumentIsEmpty(parameterName)); 38 | } 39 | 40 | return value; 41 | } 42 | 43 | [ContractAnnotation("value:null => halt")] 44 | public static string NotEmpty(string value, [InvokerParameterName] [NotNull] string parameterName) 45 | { 46 | Exception e = null; 47 | if (value is null) 48 | { 49 | e = new ArgumentNullException(parameterName); 50 | } 51 | else if (value.Trim().Length == 0) 52 | { 53 | e = new ArgumentException(AbstractionsStrings.ArgumentIsEmpty(parameterName)); 54 | } 55 | 56 | if (e != null) 57 | { 58 | NotEmpty(parameterName, nameof(parameterName)); 59 | 60 | throw e; 61 | } 62 | 63 | return value; 64 | } 65 | 66 | public static string NullButNotEmpty(string value, [InvokerParameterName] [NotNull] string parameterName) 67 | { 68 | if (!(value is null) 69 | && value.Length == 0) 70 | { 71 | NotEmpty(parameterName, nameof(parameterName)); 72 | 73 | throw new ArgumentException(AbstractionsStrings.ArgumentIsEmpty(parameterName)); 74 | } 75 | 76 | return value; 77 | } 78 | 79 | public static IReadOnlyList HasNoNulls(IReadOnlyList value, [InvokerParameterName] [NotNull] string parameterName) 80 | where T : class 81 | { 82 | NotNull(value, parameterName); 83 | 84 | if (value.Any(e => e == null)) 85 | { 86 | NotEmpty(parameterName, nameof(parameterName)); 87 | 88 | throw new ArgumentException(parameterName); 89 | } 90 | 91 | return value; 92 | } 93 | 94 | [Conditional("DEBUG")] 95 | public static void DebugAssert([System.Diagnostics.CodeAnalysis.DoesNotReturnIf(false)] bool condition, string message) 96 | { 97 | if (!condition) 98 | { 99 | throw new Exception($"Check.DebugAssert failed: {message}"); 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/Internal/EntityTypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Microsoft.EntityFrameworkCore.Metadata; 4 | 5 | namespace EntityFrameworkCore.Scaffolding.Handlebars.Internal; 6 | 7 | /// 8 | /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to 9 | /// the same compatibility standards as public APIs. It may be changed or removed without notice in 10 | /// any release. You should only use it directly in your code with extreme caution and knowing that 11 | /// doing so can result in application failures when updating to a new Entity Framework Core release. 12 | /// 13 | public static class EntityTypeExtensions 14 | { 15 | /// 16 | /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to 17 | /// the same compatibility standards as public APIs. It may be changed or removed without notice in 18 | /// any release. You should only use it directly in your code with extreme caution and knowing that 19 | /// doing so can result in application failures when updating to a new Entity Framework Core release. 20 | /// 21 | public static IEnumerable GetPropertiesAndNavigations( 22 | this IEntityType entityType) 23 | => entityType.GetProperties().Concat(entityType.GetNavigations()); 24 | 25 | /// 26 | /// Determines if the given is a join entity 27 | /// type for a many-to-many relationship where Entity would not be generated. 28 | /// This is where only Key properties are present. 29 | /// 30 | /// Entity Type 31 | /// 32 | public static bool IsManyToManyJoinEntityType(this IEntityType entityType) 33 | { 34 | if (!entityType.GetNavigations().Any() 35 | && !entityType.GetSkipNavigations().Any()) 36 | { 37 | var primaryKey = entityType.FindPrimaryKey(); 38 | var properties = entityType.GetProperties().ToList(); 39 | var foreignKeys = entityType.GetForeignKeys().ToList(); 40 | if (primaryKey != null 41 | && primaryKey.Properties.Count > 1 42 | && foreignKeys.Count == 2 43 | && primaryKey.Properties.Count == properties.Count 44 | && foreignKeys[0].Properties.Count + foreignKeys[1].Properties.Count == properties.Count 45 | && !foreignKeys[0].Properties.Intersect(foreignKeys[1].Properties).Any() 46 | && foreignKeys[0].IsRequired 47 | && foreignKeys[1].IsRequired 48 | && !foreignKeys[0].IsUnique 49 | && !foreignKeys[1].IsUnique) 50 | { 51 | return true; 52 | } 53 | } 54 | return false; 55 | } 56 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/Internal/FileSystemFileService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | 5 | namespace EntityFrameworkCore.Scaffolding.Handlebars.Internal 6 | { 7 | /// 8 | /// This API supports the Entity Framework Core infrastructure and is not intended to be used 9 | /// directly from your code. This API may change or be removed in future releases. 10 | /// 11 | public class FileSystemFileService : IFileService 12 | { 13 | /// 14 | /// This API supports the Entity Framework Core infrastructure and is not intended to be used 15 | /// directly from your code. This API may change or be removed in future releases. 16 | /// 17 | public virtual bool DirectoryExists(string directoryName) 18 | { 19 | return Directory.Exists(directoryName); 20 | } 21 | 22 | /// 23 | /// This API supports the Entity Framework Core infrastructure and is not intended to be used 24 | /// directly from your code. This API may change or be removed in future releases. 25 | /// 26 | public virtual bool FileExists(string directoryName, string fileName) 27 | { 28 | return File.Exists(Path.Combine(directoryName, fileName)); 29 | } 30 | 31 | /// 32 | /// This API supports the Entity Framework Core infrastructure and is not intended to be used 33 | /// directly from your code. This API may change or be removed in future releases. 34 | /// 35 | public virtual bool IsFileReadOnly(string directoryName, string fileName) 36 | { 37 | string path = Path.Combine(directoryName, fileName); 38 | if (File.Exists(path)) 39 | return File.GetAttributes(path).HasFlag((Enum)FileAttributes.ReadOnly); 40 | return false; 41 | } 42 | 43 | /// 44 | /// This API supports the Entity Framework Core infrastructure and is not intended to be used 45 | /// directly from your code. This API may change or be removed in future releases. 46 | /// 47 | public virtual string RetrieveFileContents(string directoryName, string fileName) 48 | { 49 | return File.ReadAllText(Path.Combine(directoryName, fileName)); 50 | } 51 | 52 | /// 53 | /// This API supports the Entity Framework Core infrastructure and is not intended to be used 54 | /// directly from your code. This API may change or be removed in future releases. 55 | /// 56 | public virtual string OutputFile(string directoryName, string fileName, string contents) 57 | { 58 | Directory.CreateDirectory(directoryName); 59 | string path = Path.Combine(directoryName, fileName); 60 | File.WriteAllText(path, contents, Encoding.UTF8); 61 | return path; 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/Internal/ICSharpDbContextGenerator.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Metadata; 2 | 3 | namespace EntityFrameworkCore.Scaffolding.Handlebars.Internal; 4 | 5 | /// 6 | /// Generator for the DbContext class. 7 | /// 8 | public interface ICSharpDbContextGenerator 9 | { 10 | /// 11 | /// Generate the DbContext class. 12 | /// 13 | /// Metadata about the shape of entities, the relationships between them, and how they map to the database. 14 | /// Name of DbContext class. 15 | /// Database connection string. 16 | /// Context namespace. 17 | /// Model namespace. 18 | /// If false use fluent modeling API. 19 | /// True if using nullable reference types. 20 | /// Suppress connection string warning. 21 | /// Suppress OnConfiguring method. 22 | /// DbContext class. 23 | string WriteCode( 24 | IModel model, 25 | string contextName, 26 | string connectionString, 27 | string contextNamespace, 28 | string modelNamespace, 29 | bool useDataAnnotations, 30 | bool useNullableReferenceTypes, 31 | bool suppressConnectionStringWarning, 32 | bool suppressOnConfiguring); 33 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/Internal/ICSharpEntityTypeGenerator.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Metadata; 2 | 3 | namespace EntityFrameworkCore.Scaffolding.Handlebars.Internal; 4 | 5 | /// 6 | /// Generator for entity type classes. 7 | /// 8 | public interface ICSharpEntityTypeGenerator 9 | { 10 | /// 11 | /// Generate entity type class. 12 | /// 13 | /// Represents an entity type in an . 14 | /// Entity type namespace. 15 | /// If true use data annotations. 16 | /// If true use nullable reference types. 17 | /// Generated entity type. 18 | string WriteCode( 19 | IEntityType entityType, 20 | string @namespace, 21 | bool useDataAnnotations, 22 | bool useNullableReferenceTypes); 23 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/Internal/IFileService.cs: -------------------------------------------------------------------------------- 1 | namespace EntityFrameworkCore.Scaffolding.Handlebars.Internal 2 | { 3 | /// 4 | /// Abstraction of a file service. 5 | /// 6 | public interface IFileService 7 | { 8 | /// 9 | /// Returns true if directory exists, otherwise returns false. 10 | /// 11 | /// Name of a directory. 12 | /// True if directory exists. 13 | bool DirectoryExists(string directoryName); 14 | 15 | /// 16 | /// Returns true if file exists, otherwise returns false. 17 | /// 18 | /// Name of a directory. 19 | /// Name of a file. 20 | /// True if file exists. 21 | bool FileExists(string directoryName, string fileName); 22 | 23 | /// 24 | /// Returns true if file is read only, otherwise returns false. 25 | /// 26 | /// Name of a directory. 27 | /// Name of a file. 28 | /// True if file is read only. 29 | bool IsFileReadOnly(string directoryName, string fileName); 30 | 31 | /// 32 | /// Name of an output file. 33 | /// 34 | /// Name of a directory. 35 | /// Name of a file. 36 | /// File contents. 37 | /// Name of an output file. 38 | string OutputFile(string directoryName, string fileName, string contents); 39 | 40 | /// 41 | /// Retrieve file contents. 42 | /// 43 | /// Name of a directory. 44 | /// Name of a file. 45 | /// File contents. 46 | string RetrieveFileContents(string directoryName, string fileName); 47 | } 48 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/Internal/InMemoryFileService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | 4 | namespace EntityFrameworkCore.Scaffolding.Handlebars.Internal 5 | { 6 | /// 7 | /// This API supports the Entity Framework Core infrastructure and is not intended to be used 8 | /// directly from your code. This API may change or be removed in future releases. 9 | /// 10 | public class InMemoryFileService : IFileService 11 | { 12 | /// 13 | /// This API supports the Entity Framework Core infrastructure and is not intended to be used 14 | /// directly from your code. This API may change or be removed in future releases. 15 | /// 16 | protected readonly Dictionary> NameToContentMap 17 | = new Dictionary>(); 18 | 19 | /// 20 | /// This API supports the Entity Framework Core infrastructure and is not intended to be used 21 | /// directly from your code. This API may change or be removed in future releases. 22 | /// 23 | public virtual bool DirectoryExists(string directoryName) 24 | => NameToContentMap.TryGetValue(directoryName, out _); 25 | 26 | /// 27 | /// This API supports the Entity Framework Core infrastructure and is not intended to be used 28 | /// directly from your code. This API may change or be removed in future releases. 29 | /// 30 | public virtual bool FileExists(string directoryName, string fileName) 31 | => NameToContentMap.TryGetValue(directoryName, out var filesMap) 32 | && filesMap.TryGetValue(fileName, out _); 33 | 34 | /// 35 | /// This API supports the Entity Framework Core infrastructure and is not intended to be used 36 | /// directly from your code. This API may change or be removed in future releases. 37 | /// 38 | public virtual bool IsFileReadOnly(string outputDirectoryName, string outputFileName) => false; 39 | 40 | /// 41 | /// This API supports the Entity Framework Core infrastructure and is not intended to be used 42 | /// directly from your code. This API may change or be removed in future releases. 43 | /// 44 | public virtual string RetrieveFileContents(string directoryName, string fileName) 45 | { 46 | if (!NameToContentMap.TryGetValue(directoryName, out var filesMap)) 47 | { 48 | throw new DirectoryNotFoundException("Could not find directory " + directoryName); 49 | } 50 | 51 | if (!filesMap.TryGetValue(fileName, out var contents)) 52 | { 53 | throw new FileNotFoundException("Could not find file " + Path.Combine(directoryName, fileName)); 54 | } 55 | 56 | return contents; 57 | } 58 | 59 | /// 60 | /// This API supports the Entity Framework Core infrastructure and is not intended to be used 61 | /// directly from your code. This API may change or be removed in future releases. 62 | /// 63 | public virtual string OutputFile( 64 | string directoryName, 65 | string fileName, 66 | string contents) 67 | { 68 | if (!NameToContentMap.TryGetValue(directoryName, out var filesMap)) 69 | { 70 | filesMap = new Dictionary(); 71 | NameToContentMap[directoryName] = filesMap; 72 | } 73 | 74 | filesMap[fileName] = contents; 75 | 76 | return Path.Combine(directoryName, fileName); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/Internal/NamespaceComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace EntityFrameworkCore.Scaffolding.Handlebars.Internal 5 | { 6 | /// 7 | /// A custom string comparer to sort using statements to have System prefixed namespaces first. 8 | /// 9 | public class NamespaceComparer : IComparer 10 | { 11 | /// 12 | public virtual int Compare(string x, string y) 13 | { 14 | var xSystemNamespace = x != null && (x == "System" || x.StartsWith("System.", StringComparison.Ordinal)); 15 | var ySystemNamespace = y != null && (y == "System" || y.StartsWith("System.", StringComparison.Ordinal)); 16 | 17 | return xSystemNamespace && !ySystemNamespace 18 | ? -1 19 | : !xSystemNamespace && ySystemNamespace 20 | ? 1 21 | : string.CompareOrdinal(x, y); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/Internal/RelationalAnnotationNames.cs: -------------------------------------------------------------------------------- 1 | namespace EntityFrameworkCore.Scaffolding.Handlebars.Internal 2 | { 3 | /// 4 | /// Names for well-known relational model annotations. Applications should not use these names 5 | /// directly, but should instead use the extension methods on metadata objects. 6 | /// 7 | public static class RelationalAnnotationNames2 8 | { 9 | /// 10 | /// The prefix used for any relational annotation. 11 | /// 12 | public const string Prefix = "Relational:"; 13 | 14 | /// 15 | /// The definition of a database view. 16 | /// 17 | public const string ViewDefinition = Prefix + "ViewDefinition"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/Internal/SharedTypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Reflection; 5 | using JetBrains.Annotations; 6 | 7 | namespace EntityFrameworkCore.Scaffolding.Handlebars.Internal 8 | { 9 | [DebuggerStepThrough] 10 | internal static class SharedTypeExtensions 11 | { 12 | private static readonly Dictionary _builtInTypeNames = new Dictionary 13 | { 14 | { typeof(bool), "bool" }, 15 | { typeof(byte), "byte" }, 16 | { typeof(char), "char" }, 17 | { typeof(decimal), "decimal" }, 18 | { typeof(double), "double" }, 19 | { typeof(float), "float" }, 20 | { typeof(int), "int" }, 21 | { typeof(long), "long" }, 22 | { typeof(object), "object" }, 23 | { typeof(sbyte), "sbyte" }, 24 | { typeof(short), "short" }, 25 | { typeof(string), "string" }, 26 | { typeof(uint), "uint" }, 27 | { typeof(ulong), "ulong" }, 28 | { typeof(ushort), "ushort" }, 29 | { typeof(void), "void" } 30 | }; 31 | 32 | public static bool IsNullableType(this Type type) 33 | { 34 | var typeInfo = type.GetTypeInfo(); 35 | 36 | return !typeInfo.IsValueType 37 | || typeInfo.IsGenericType 38 | && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>); 39 | } 40 | 41 | public static IEnumerable GetNamespaces([NotNull] this Type type) 42 | { 43 | if (_builtInTypeNames.ContainsKey(type)) 44 | { 45 | yield break; 46 | } 47 | 48 | yield return type.Namespace; 49 | 50 | if (type.IsGenericType) 51 | { 52 | foreach (var typeArgument in type.GenericTypeArguments) 53 | { 54 | foreach (var ns in typeArgument.GetNamespaces()) 55 | { 56 | yield return ns; 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/Internal/TableAndSchema.cs: -------------------------------------------------------------------------------- 1 | namespace EntityFrameworkCore.Scaffolding.Handlebars.Internal 2 | { 3 | internal class TableAndSchema 4 | { 5 | internal TableAndSchema(string tableName) 6 | { 7 | var parts = tableName.Split('.'); 8 | if (parts.Length > 1) 9 | { 10 | Schema = parts[0]; 11 | Table = parts[1]; 12 | } 13 | else 14 | { 15 | Table = parts[0]; 16 | } 17 | } 18 | 19 | internal string Schema { get; set; } 20 | 21 | internal string Table { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Trackable Entities 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 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/LanguageOptions.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | namespace Microsoft.EntityFrameworkCore.Design 3 | { 4 | /// 5 | /// Language options for reverse engineering classes from an existing database. 6 | /// 7 | public enum LanguageOptions 8 | { 9 | /// 10 | /// C# language. 11 | /// 12 | CSharp, 13 | 14 | /// 15 | /// TypeScript language. 16 | /// 17 | TypeScript 18 | } 19 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/NullCSharpDbContextGenerator.cs: -------------------------------------------------------------------------------- 1 | using EntityFrameworkCore.Scaffolding.Handlebars.Internal; 2 | using Microsoft.EntityFrameworkCore.Metadata; 3 | 4 | namespace EntityFrameworkCore.Scaffolding.Handlebars 5 | { 6 | /// 7 | /// DbContext generator that does not generate any code. 8 | /// 9 | public class NullCSharpDbContextGenerator : ICSharpDbContextGenerator 10 | { 11 | /// 12 | /// Generate the DbContext class. 13 | /// 14 | /// Metadata about the shape of entities, the relationships between them, and how they map to the database. 15 | /// Name of DbContext class. 16 | /// Database connection string. 17 | /// Context namespace. 18 | /// Model namespace. 19 | /// If false use fluent modeling API. 20 | /// If true use nullable reference types. 21 | /// Suppress connection string warning. 22 | /// Suppress OnConfiguring method. 23 | /// DbContext class. 24 | public string WriteCode(IModel model, string contextName, string connectionString, string contextNamespace, string modelNamespace, bool useDataAnnotations, bool useNullableReferenceTypes, bool suppressConnectionStringWarning, bool suppressOnConfiguring) 25 | { 26 | return string.Empty; 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/NullCSharpEntityTypeGenerator.cs: -------------------------------------------------------------------------------- 1 | using EntityFrameworkCore.Scaffolding.Handlebars.Internal; 2 | using Microsoft.EntityFrameworkCore.Metadata; 3 | 4 | namespace EntityFrameworkCore.Scaffolding.Handlebars 5 | { 6 | /// 7 | /// Entity type generator that does not generate any code. 8 | /// 9 | public class NullCSharpEntityTypeGenerator : ICSharpEntityTypeGenerator 10 | { 11 | /// 12 | /// Generate entity type class. 13 | /// 14 | /// Represents an entity type in an . 15 | /// Entity type namespace. 16 | /// If true use data annotations. 17 | /// If true use nullable reference types. 18 | /// Generated entity type. 19 | public string WriteCode(IEntityType entityType, string @namespace, bool useDataAnnotations, bool useNullableReferenceTypes) 20 | { 21 | return string.Empty; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/ReverseEngineerOptions.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | namespace Microsoft.EntityFrameworkCore.Design 3 | { 4 | /// 5 | /// Options for reverse engineering classes from an existing database. 6 | /// 7 | public enum ReverseEngineerOptions 8 | { 9 | /// 10 | /// Generate DbContext class only. 11 | /// 12 | DbContextOnly, 13 | 14 | /// 15 | /// Generate entity type classes only. 16 | /// 17 | EntitiesOnly, 18 | 19 | /// 20 | /// Generate both DbContext and entity type classes. 21 | /// 22 | DbContextAndEntities 23 | } 24 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/ScaffoldingDesignTimeServices.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Design; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace EntityFrameworkCore.Scaffolding.Handlebars 5 | { 6 | /// 7 | /// Used by EF Core toolchain to register design time services. 8 | /// 9 | public class ScaffoldingDesignTimeServices : IDesignTimeServices 10 | { 11 | /// 12 | /// Register Handlebars scaffolding with design time dependency injection system. 13 | /// 14 | /// Specifies the contract for a collection of service descriptors. 15 | public void ConfigureDesignTimeServices(IServiceCollection services) 16 | { 17 | services.AddHandlebarsScaffolding(configureOptions: options => 18 | options.ReverseEngineerOptions = ReverseEngineerOptions.DbContextAndEntities); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/TemplateFileInfo.cs: -------------------------------------------------------------------------------- 1 | namespace EntityFrameworkCore.Scaffolding.Handlebars 2 | { 3 | /// 4 | /// Template file information. 5 | /// 6 | public class TemplateFileInfo 7 | { 8 | /// 9 | /// Relative directory name. 10 | /// 11 | public string RelativeDirectory { get; set; } 12 | 13 | /// 14 | /// File name. 15 | /// 16 | public string FileName { get; set; } 17 | 18 | /// 19 | /// Alternative relative directory. Used for testing purposes. 20 | /// 21 | public string AltRelativeDirectory { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/TypeScriptHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Text; 4 | 5 | namespace EntityFrameworkCore.Scaffolding.Handlebars 6 | { 7 | /// 8 | /// TypeScript Helper 9 | /// 10 | public class TypeScriptHelper : ITypeScriptHelper 11 | { 12 | /// 13 | /// Convert CLR type to TypeScript type 14 | /// 15 | /// CLR type. 16 | /// TypeScript type 17 | public string TypeName(Type clrType) 18 | { 19 | var result = "any"; 20 | if (clrType == typeof(bool) || clrType == typeof(bool?)) 21 | result = "boolean"; 22 | if (clrType == typeof(char) || clrType == typeof(char?) 23 | || clrType == typeof(string)) 24 | result = "string"; 25 | if (clrType == typeof(DateTime) || clrType == typeof(DateTime?)) 26 | result = "Date"; 27 | if (clrType == typeof(byte) || clrType == typeof(byte?) 28 | || clrType == typeof(sbyte) || clrType == typeof(sbyte?) 29 | || clrType == typeof(decimal) || clrType == typeof(decimal?) 30 | || clrType == typeof(double) || clrType == typeof(double?) 31 | || clrType == typeof(short) || clrType == typeof(short?) 32 | || clrType == typeof(ushort) || clrType == typeof(ushort?) 33 | || clrType == typeof(int) || clrType == typeof(int?) 34 | || clrType == typeof(uint) || clrType == typeof(uint?) 35 | || clrType == typeof(long) || clrType == typeof(long?) 36 | || clrType == typeof(ulong) || clrType == typeof(ulong?) 37 | || clrType == typeof(float) || clrType == typeof(float?)) 38 | result = "number"; 39 | return result; 40 | } 41 | 42 | /// 43 | /// Convert string to camel case. 44 | /// 45 | /// Input string. 46 | /// Input string in camel case. 47 | public string ToCamelCase(string s) 48 | { 49 | if (s == null || s.Length < 2) 50 | return s; 51 | var chars = s.ToCharArray(); 52 | var sb = new StringBuilder(); 53 | sb.Append(chars[0].ToString().ToLower(CultureInfo.InvariantCulture)); 54 | for (int i = 1; i < chars.Length; i++) 55 | { 56 | sb.Append(chars[i]); 57 | } 58 | return sb.ToString(); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrackableEntities/EntityFrameworkCore.Scaffolding.Handlebars/2f6ff4dd956501c0f8fdec8b7c6f04dc4b928c1f/src/EntityFrameworkCore.Scaffolding.Handlebars/icon.png -------------------------------------------------------------------------------- /src/EntityFrameworkCore.Scaffolding.Handlebars/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrackableEntities/EntityFrameworkCore.Scaffolding.Handlebars/2f6ff4dd956501c0f8fdec8b7c6f04dc4b928c1f/src/EntityFrameworkCore.Scaffolding.Handlebars/key.snk -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CSharpEntityTypeAlt/Class.hbs: -------------------------------------------------------------------------------- 1 | {{> imports}} 2 | 3 | namespace {{namespace}} 4 | { 5 | {{#if custom-comment}} 6 | /// 7 | {{custom-comment}} 8 | /// 9 | {{/if}} 10 | {{#each class-annotations}} 11 | {{{class-annotation}}} 12 | {{/each}} 13 | public partial class {{class}} : {{base-class}} 14 | { 15 | {{{> constructor}}} 16 | {{{> properties}}} 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CSharpEntityTypeAlt/Partials/Constructor.hbs: -------------------------------------------------------------------------------- 1 | {{#if lines}} 2 | public {{class}}() 3 | { 4 | {{#each lines}} 5 | {{property-name}} = new HashSet<{{property-type}}>(); 6 | {{/each}} 7 | } 8 | 9 | {{/if}} 10 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CSharpEntityTypeAlt/Partials/Imports.hbs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | {{#if use-data-annotations}} 4 | using System.ComponentModel.DataAnnotations; 5 | using System.ComponentModel.DataAnnotations.Schema; 6 | using Microsoft.EntityFrameworkCore; 7 | {{/if}} 8 | {{#each imports}} 9 | using {{import}}; 10 | {{/each}} 11 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CSharpEntityTypeAlt/Partials/Properties.hbs: -------------------------------------------------------------------------------- 1 | {{#each properties}} 2 | {{#if property-comment}} 3 | 4 | /// 5 | {{property-comment}} 6 | /// 7 | {{/if}} 8 | {{#each property-annotations}} 9 | {{{property-annotation}}} 10 | {{/each}} 11 | public {{property-type}} {{property-name}} { get; set; }{{#if nullable-reference-types }}{{#unless property-isnullable}} = null!;{{/unless}}{{/if}} 12 | {{/each}} 13 | {{#if nav-properties}} 14 | 15 | {{#each nav-properties}} 16 | {{#each nav-property-annotations}} 17 | {{{nav-property-annotation}}} 18 | {{/each}} 19 | {{#if nav-property-collection}} 20 | public virtual ICollection<{{nav-property-type}}> {{nav-property-name}} { get; set; } 21 | {{else}} 22 | public virtual {{nav-property-type}} {{nav-property-name}} { get; set; }{{#if nullable-reference-types}}{{#unless nav-property-isnullable}} = null!;{{/unless}}{{/if}} 23 | {{/if}} 24 | {{/each}} 25 | {{/if}} -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/CSharpDbContext/DbContext.hbs: -------------------------------------------------------------------------------- 1 | {{> dbimports}} 2 | 3 | namespace {{namespace}} 4 | { 5 | public partial class {{class}} : DbContext 6 | { 7 | {{{> dbsets}}} 8 | 9 | {{{> dbconstructor}}} 10 | 11 | {{#unless suppress-on-configuring}} 12 | {{{> dbonconfiguring}}} 13 | 14 | {{/unless}} 15 | {{{on-model-creating}}} 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/CSharpDbContext/Partials/DbConstructor.hbs: -------------------------------------------------------------------------------- 1 |  public {{class}}() 2 | { 3 | } 4 | 5 | public {{class}}(DbContextOptions<{{class}}> options) : base(options) 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/CSharpDbContext/Partials/DbImports.hbs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata; 4 | {{#if model-namespace}} 5 | using {{model-namespace}}; 6 | {{/if}} 7 | {{#each model-imports}} 8 | using {{model-import}}; 9 | {{/each}} 10 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/CSharpDbContext/Partials/DbOnConfiguring.hbs: -------------------------------------------------------------------------------- 1 |  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 2 | { 3 | if (!optionsBuilder.IsConfigured) 4 | { 5 | {{#if connectionstring-warning}} 6 | {{connectionstring-warning}} 7 | {{/if}} 8 | optionsBuilder{{options-builder-provider}}; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/CSharpDbContext/Partials/DbSets.hbs: -------------------------------------------------------------------------------- 1 | {{#each dbsets}} 2 | public virtual DbSet<{{set-property-type}}> {{set-property-name}} { get; set; }{{#if nullable-reference-types }} = default!;{{/if}} 3 | {{/each}} 4 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/CSharpEntityType/Class.hbs: -------------------------------------------------------------------------------- 1 | {{> imports}} 2 | 3 | namespace {{namespace}} 4 | { 5 | {{#if comment}} 6 | /// 7 | {{comment}} 8 | /// 9 | {{/if}} 10 | {{#each class-annotations}} 11 | {{{class-annotation}}} 12 | {{/each}} 13 | public partial class {{class}} 14 | { 15 | {{{> constructor}}} 16 | {{{> properties}}} 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/CSharpEntityType/Partials/Constructor.hbs: -------------------------------------------------------------------------------- 1 | {{#if lines}} 2 | public {{class}}() 3 | { 4 | {{#each lines}} 5 | {{property-name}} = new HashSet<{{property-type}}>(); 6 | {{/each}} 7 | } 8 | 9 | {{/if}} 10 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/CSharpEntityType/Partials/Imports.hbs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | {{#if use-data-annotations}} 4 | using System.ComponentModel.DataAnnotations; 5 | using System.ComponentModel.DataAnnotations.Schema; 6 | using Microsoft.EntityFrameworkCore; 7 | {{/if}} 8 | {{#each imports}} 9 | using {{import}}; 10 | {{/each}} 11 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/CSharpEntityType/Partials/Properties.hbs: -------------------------------------------------------------------------------- 1 | {{#each properties}} 2 | {{#if property-comment}} 3 | /// 4 | /// {{property-comment}} 5 | /// 6 | {{/if}} 7 | {{#each property-annotations}} 8 | {{{property-annotation}}} 9 | {{/each}} 10 | public {{property-type}} {{property-name}} { get; set; }{{#if nullable-reference-types }}{{#unless property-isnullable}} = default!;{{/unless}}{{/if}} 11 | {{/each}} 12 | {{#if nav-properties}} 13 | 14 | {{#each nav-properties}} 15 | {{#each nav-property-annotations}} 16 | {{{nav-property-annotation}}} 17 | {{/each}} 18 | {{#if nav-property-collection}} 19 | public virtual ICollection<{{nav-property-type}}> {{nav-property-name}} { get; set; }{{#if nullable-reference-types}} = default!;{{/if}} 20 | {{else}} 21 | public virtual {{nav-property-type}} {{nav-property-name}} { get; set; }{{#if nullable-reference-types}}{{#unless nav-property-isnullable}} = default!;{{/unless}}{{/if}} 22 | {{/if}} 23 | {{/each}} 24 | {{/if}} -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/TypeScriptDbContext/DbContext.hbs: -------------------------------------------------------------------------------- 1 | {{> dbimports}} 2 | 3 | namespace {{namespace}} 4 | { 5 | public partial class {{class}} : DbContext 6 | { 7 | {{{> dbsets}}} 8 | 9 | {{{> dbconstructor}}} 10 | 11 | {{#unless suppress-on-configuring}} 12 | {{{> dbonconfiguring}}} 13 | 14 | {{/unless}} 15 | {{{on-model-creating}}} 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/TypeScriptDbContext/Partials/DbConstructor.hbs: -------------------------------------------------------------------------------- 1 |  public {{class}}() 2 | { 3 | } 4 | 5 | public {{class}}(DbContextOptions<{{class}}> options) : base(options) 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/TypeScriptDbContext/Partials/DbImports.hbs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata; 4 | {{#if model-namespace}} 5 | using {{model-namespace}}; 6 | {{/if}} 7 | {{#each model-imports}} 8 | using {{model-import}}; 9 | {{/each}} 10 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/TypeScriptDbContext/Partials/DbOnConfiguring.hbs: -------------------------------------------------------------------------------- 1 |  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 2 | { 3 | if (!optionsBuilder.IsConfigured) 4 | { 5 | {{#if connectionstring-warning}} 6 | {{connectionstring-warning}} 7 | {{/if}} 8 | optionsBuilder{{options-builder-provider}}; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/TypeScriptDbContext/Partials/DbSets.hbs: -------------------------------------------------------------------------------- 1 | {{#each dbsets}} 2 | public virtual DbSet<{{set-property-type}}> {{set-property-name}} { get; set; }{{#if nullable-reference-types }} = default!;{{/if}} 3 | {{/each}} 4 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/TypeScriptEntityType/Class.hbs: -------------------------------------------------------------------------------- 1 | {{> imports}} 2 | 3 | export interface {{class}} { 4 | {{{> properties}}} 5 | } 6 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/TypeScriptEntityType/Partials/Constructor.hbs: -------------------------------------------------------------------------------- 1 | {{spaces 4}}constructor() { 2 | {{spaces 3}} } 3 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/TypeScriptEntityType/Partials/Imports.hbs: -------------------------------------------------------------------------------- 1 | {{#each imports}} 2 | import { {{import}} } from './{{import}}'; 3 | {{/each}} 4 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplates/TypeScriptEntityType/Partials/Properties.hbs: -------------------------------------------------------------------------------- 1 | {{#each properties}} 2 | {{spaces 4}}{{property-name}}: {{property-type}}; 3 | {{/each}} 4 | {{#if nav-properties}} 5 | {{#each nav-properties}} 6 | {{#if nav-property-collection}} 7 | {{spaces 4}}{{nav-property-name}}: {{nav-property-type}}[]; 8 | {{else}} 9 | {{spaces 4}}{{nav-property-name}}: {{nav-property-type}}; 10 | {{/if}} 11 | {{/each}} 12 | {{/if}} -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/CodeTemplatesAlt/CSharpEntityType/Class.hbs: -------------------------------------------------------------------------------- 1 | {{> imports}} 2 | 3 | namespace {{namespace}} 4 | { 5 | {{#if comment}} 6 | /// 7 | {{comment}} 8 | /// 9 | {{/if}} 10 | {{#each class-annotations}} 11 | {{{class-annotation}}} 12 | {{/each}} 13 | public partial class {{class}} 14 | { 15 | {{{> constructor}}} 16 | {{{> properties}}} 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Contexts/NorthwindDbContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Scaffolding.Handlebars.Tests.Models; 3 | 4 | namespace Scaffolding.Handlebars.Tests.Contexts 5 | { 6 | public class NorthwindDbContext : DbContext 7 | { 8 | public NorthwindDbContext() { } 9 | 10 | public NorthwindDbContext(DbContextOptions options) : base(options) { } 11 | 12 | public DbSet Categories { get; set; } 13 | public DbSet Products { get; set; } 14 | public DbSet Customers { get; set; } 15 | 16 | protected override void OnModelCreating(ModelBuilder modelBuilder) 17 | { 18 | modelBuilder.Entity() 19 | .ToTable(t => t.HasComment("A category of products")) 20 | .Property(category => category.CategoryName) 21 | .HasComment("The name of a category"); 22 | modelBuilder.Entity(entity => 23 | { 24 | entity.Property(e => e.CustomerKey).IsFixedLength(); 25 | }); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/EmbeddedResourceTemplateFileServiceTests.ExpectedTemplates.cs: -------------------------------------------------------------------------------- 1 | namespace Scaffolding.Handlebars.Tests 2 | { 3 | public partial class EmbeddedResourceTemplateFileServiceTests 4 | { 5 | private static class ExpectedTemplates 6 | { 7 | public const string ContextTemplate = 8 | @"{{> dbimports}} 9 | 10 | namespace {{namespace}} 11 | { 12 | public partial class {{class}} : DbContext 13 | { 14 | {{{> dbsets}}} 15 | 16 | {{{> dbconstructor}}} 17 | 18 | {{#unless suppress-on-configuring}} 19 | {{{> dbonconfiguring}}} 20 | 21 | {{/unless}} 22 | {{{on-model-creating}}} 23 | } 24 | } 25 | "; 26 | 27 | public const string EntityTemplate = 28 | @"{{> imports}} 29 | 30 | namespace {{namespace}} 31 | { 32 | {{#if comment}} 33 | /// 34 | {{comment}} 35 | /// 36 | {{/if}} 37 | {{#each class-annotations}} 38 | {{{class-annotation}}} 39 | {{/each}} 40 | public partial class {{class}} 41 | { 42 | {{{> constructor}}} 43 | {{{> properties}}} 44 | } 45 | } 46 | "; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/EmbeddedResourceTemplateFileServiceTests.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using EntityFrameworkCore.Scaffolding.Handlebars; 3 | using Scaffolding.Handlebars.Tests.Helpers; 4 | using Xunit; 5 | 6 | namespace Scaffolding.Handlebars.Tests 7 | { 8 | public partial class EmbeddedResourceTemplateFileServiceTests 9 | { 10 | private readonly string _projectRootDir = Path.Combine("..", "..", ".."); 11 | 12 | [Theory] 13 | [InlineData( 14 | Constants.Templates.CSharpTemplateDirectories.ContextFolder, 15 | Constants.Templates.ContextClassFile, 16 | ExpectedTemplates.ContextTemplate)] 17 | [InlineData( 18 | Constants.Templates.CSharpTemplateDirectories.EntityTypeFolder, 19 | Constants.Templates.EntityClassFile, 20 | ExpectedTemplates.EntityTemplate)] 21 | public void Template_File_Service_Should_Retrieve_Template( 22 | string templateFolderName, string templateFileName, string expectedTemplate) 23 | { 24 | // Act 25 | var templateExisting = RetrieveTemplate(templateFolderName, templateFileName, true); 26 | var templateNonExisting = RetrieveTemplate(templateFolderName, templateFileName, false); 27 | 28 | // Assert 29 | Assert.Equal(expectedTemplate, templateExisting); 30 | Assert.Equal(expectedTemplate, templateNonExisting); 31 | } 32 | 33 | private string RetrieveTemplate(string templateFolderName, string templateFileName, bool useExisting) 34 | { 35 | // Arrange 36 | string localDirectory = Path.Combine(_projectRootDir, 37 | Constants.Templates.CodeTemplatesFolder, templateFolderName); 38 | string altDirectory = useExisting 39 | ? localDirectory 40 | : Path.Combine(_projectRootDir, 41 | Constants.Templates.CodeTemplatesAltFolder, templateFolderName); 42 | string relativeDirectory = $"{Constants.Templates.CodeTemplatesFolder}" + 43 | $"/{templateFolderName}"; 44 | 45 | var type = typeof(EmbeddedResourceTemplateFileServiceTests); 46 | var templateService = new EmbeddedResourceTemplateFileService(type.Assembly, type.Namespace); 47 | 48 | // Act 49 | return templateService.RetrieveTemplateFileContents( 50 | relativeDirectory, templateFileName, altDirectory); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/ExpectedTypeScriptContexts.cs: -------------------------------------------------------------------------------- 1 | namespace Scaffolding.Handlebars.Tests 2 | { 3 | public partial class HbsTypeScriptScaffoldingGeneratorTests 4 | { 5 | private static class ExpectedContexts 6 | { 7 | public static string ContextClass = 8 | @"using System; 9 | using System.Collections.Generic; 10 | using Microsoft.EntityFrameworkCore; 11 | using Microsoft.EntityFrameworkCore.Metadata; 12 | 13 | namespace FakeNamespace 14 | { 15 | public partial class FakeDbContext : DbContext 16 | { 17 | public virtual DbSet Categories { get; set; } 18 | public virtual DbSet Customers { get; set; } 19 | public virtual DbSet Products { get; set; } 20 | 21 | public FakeDbContext(DbContextOptions options) : base(options) 22 | { 23 | } 24 | 25 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 26 | { 27 | if (!optionsBuilder.IsConfigured) 28 | { 29 | #warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263. 30 | optionsBuilder.UseSqlServer(""" + ConnectionString.Replace(@"\",@"\\") + @"""); 31 | } 32 | } 33 | 34 | protected override void OnModelCreating(ModelBuilder modelBuilder) 35 | { 36 | modelBuilder.Entity(entity => 37 | { 38 | entity.ToTable(""Category""); 39 | 40 | entity.HasAnnotation(""Relational:Comment"", ""A category of products""); 41 | 42 | entity.Property(e => e.CategoryName) 43 | .IsRequired() 44 | .HasMaxLength(15) 45 | .HasComment(""The name of a category""); 46 | }); 47 | 48 | modelBuilder.Entity(entity => 49 | { 50 | entity.HasKey(e => e.CustomerKey); 51 | 52 | entity.ToTable(""Customer""); 53 | 54 | entity.Property(e => e.CustomerKey) 55 | .HasMaxLength(5) 56 | .IsFixedLength(); 57 | 58 | entity.Property(e => e.City).HasMaxLength(15); 59 | 60 | entity.Property(e => e.CompanyName) 61 | .IsRequired() 62 | .HasMaxLength(40); 63 | 64 | entity.Property(e => e.ContactName).HasMaxLength(30); 65 | 66 | entity.Property(e => e.Country).HasMaxLength(15); 67 | }); 68 | 69 | modelBuilder.Entity(entity => 70 | { 71 | entity.ToTable(""Product""); 72 | 73 | entity.HasIndex(e => e.CategoryId, ""IX_Product_CategoryId""); 74 | 75 | entity.Property(e => e.ProductName) 76 | .IsRequired() 77 | .HasMaxLength(40); 78 | 79 | entity.Property(e => e.RowVersion) 80 | .IsRowVersion() 81 | .IsConcurrencyToken(); 82 | 83 | entity.Property(e => e.UnitPrice).HasColumnType(""money""); 84 | 85 | entity.HasOne(d => d.Category) 86 | .WithMany(p => p.Products) 87 | .HasForeignKey(d => d.CategoryId); 88 | }); 89 | 90 | OnModelCreatingPartial(modelBuilder); 91 | } 92 | 93 | partial void OnModelCreatingPartial(ModelBuilder modelBuilder); 94 | } 95 | } 96 | "; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/ExpectedTypeScriptInterfaces.cs: -------------------------------------------------------------------------------- 1 | namespace Scaffolding.Handlebars.Tests 2 | { 3 | public partial class HbsTypeScriptScaffoldingGeneratorTests 4 | { 5 | private static class ExpectedEntities 6 | { 7 | public const string CategoryClass = 8 | @"import { Product } from './Product'; 9 | 10 | /** 11 | * A category of products 12 | */ 13 | export interface Category { 14 | categoryId: number; 15 | /** 16 | * The name of a category 17 | */ 18 | categoryName: string; 19 | products: Product[]; 20 | } 21 | "; 22 | 23 | public const string ProductClass = 24 | @"import { Category } from './Category'; 25 | 26 | export interface Product { 27 | productId: number; 28 | productName: string; 29 | unitPrice: number; 30 | discontinued: boolean; 31 | rowVersion: any; 32 | categoryId: number; 33 | category: Category; 34 | } 35 | "; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Fakes/FakeCSharpTemplateLanguageService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EntityFrameworkCore.Scaffolding.Handlebars; 3 | using EntityFrameworkCore.Scaffolding.Handlebars.Helpers; 4 | 5 | namespace Scaffolding.Handlebars.Tests.Fakes 6 | { 7 | public class FakeCSharpTemplateLanguageService : ITemplateLanguageService 8 | { 9 | private readonly string _entityTypeDirectory; 10 | private readonly string _entityTypePartialsDirectory; 11 | 12 | public FakeCSharpTemplateLanguageService(bool useAltTemplates) 13 | { 14 | _entityTypeDirectory = useAltTemplates ? "CSharpEntityTypeAlt" : "CodeTemplates/CSharpEntityType"; 15 | _entityTypePartialsDirectory = _entityTypeDirectory + "/Partials"; 16 | } 17 | 18 | public Dictionary GetDbContextTemplateFileInfo() 19 | { 20 | var result = new Dictionary 21 | { 22 | { 23 | Constants.DbContextTemplate, 24 | new TemplateFileInfo 25 | { 26 | RelativeDirectory = Constants.CSharpTemplateDirectories.DbContextDirectory, 27 | FileName = Constants.DbContextTemplate + Constants.TemplateExtension 28 | } 29 | }, 30 | { 31 | Constants.DbContextImportTemplate, 32 | new TemplateFileInfo 33 | { 34 | RelativeDirectory = Constants.CSharpTemplateDirectories.DbContextPartialsDirectory, 35 | FileName = Constants.DbContextImportTemplate + Constants.TemplateExtension 36 | } 37 | }, 38 | { 39 | Constants.DbContextCtorTemplate, 40 | new TemplateFileInfo 41 | { 42 | RelativeDirectory = Constants.CSharpTemplateDirectories.DbContextPartialsDirectory, 43 | FileName = Constants.DbContextCtorTemplate + Constants.TemplateExtension 44 | } 45 | }, 46 | { 47 | Constants.DbContextOnConfiguringTemplate, 48 | new TemplateFileInfo 49 | { 50 | RelativeDirectory = Constants.CSharpTemplateDirectories.DbContextPartialsDirectory, 51 | FileName = Constants.DbContextOnConfiguringTemplate + Constants.TemplateExtension 52 | } 53 | }, 54 | { 55 | Constants.DbContextDbSetsTemplate, 56 | new TemplateFileInfo 57 | { 58 | RelativeDirectory = Constants.CSharpTemplateDirectories.DbContextPartialsDirectory, 59 | FileName = Constants.DbContextDbSetsTemplate + Constants.TemplateExtension 60 | } 61 | }, 62 | }; 63 | return result; 64 | } 65 | 66 | public Dictionary GetEntitiesTemplateFileInfo() 67 | { 68 | var result = new Dictionary 69 | { 70 | { 71 | Constants.EntityTypeTemplate, 72 | new TemplateFileInfo 73 | { 74 | RelativeDirectory = _entityTypeDirectory, 75 | FileName = Constants.EntityTypeTemplate + Constants.TemplateExtension 76 | } 77 | }, 78 | { 79 | Constants.EntityTypeImportTemplate, 80 | new TemplateFileInfo 81 | { 82 | RelativeDirectory = _entityTypePartialsDirectory, 83 | FileName = Constants.EntityTypeImportTemplate + Constants.TemplateExtension 84 | } 85 | }, 86 | { 87 | Constants.EntityTypeCtorTemplate, 88 | new TemplateFileInfo 89 | { 90 | RelativeDirectory = _entityTypePartialsDirectory, 91 | FileName = Constants.EntityTypeCtorTemplate + Constants.TemplateExtension 92 | } 93 | }, 94 | { 95 | Constants.EntityTypePropertyTemplate, 96 | new TemplateFileInfo 97 | { 98 | RelativeDirectory = _entityTypePartialsDirectory, 99 | FileName = Constants.EntityTypePropertyTemplate + Constants.TemplateExtension 100 | } 101 | }, 102 | }; 103 | return result; 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Fakes/FakeDatabaseModelFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.Common; 3 | using Microsoft.EntityFrameworkCore.Scaffolding; 4 | using Microsoft.EntityFrameworkCore.Scaffolding.Metadata; 5 | 6 | namespace Scaffolding.Handlebars.Tests.Fakes 7 | { 8 | public class FakeDatabaseModelFactory : IDatabaseModelFactory 9 | { 10 | public DatabaseModel Create(string connectionString, DatabaseModelFactoryOptions options) 11 | => throw new NotImplementedException(); 12 | 13 | public DatabaseModel Create(DbConnection connection, DatabaseModelFactoryOptions options) 14 | => throw new NotImplementedException(); 15 | } 16 | } -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Fakes/FakeHbsEntityTypeTemplateService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Globalization; 3 | using EntityFrameworkCore.Scaffolding.Handlebars; 4 | using EntityFrameworkCore.Scaffolding.Handlebars.Helpers; 5 | using HandlebarsDotNet; 6 | using Microsoft.EntityFrameworkCore.Design; 7 | using HandlebarsLib = HandlebarsDotNet.Handlebars; 8 | 9 | namespace Scaffolding.Handlebars.Tests.Fakes 10 | { 11 | /// 12 | /// Provide services required to generate entity type classes using Handlebars templates. 13 | /// 14 | public class FakeHbsEntityTypeTemplateService : HbsTemplateService, IEntityTypeTemplateService 15 | { 16 | private Dictionary EntitiesTemplateFiles { get; } 17 | 18 | /// 19 | /// Entity type template. 20 | /// 21 | public HandlebarsTemplate EntityTypeTemplate { get; private set; } 22 | 23 | /// 24 | /// Constructor for entity type template service. 25 | /// 26 | /// Template file service. 27 | /// Template language service. 28 | public FakeHbsEntityTypeTemplateService(ITemplateFileService fileService, 29 | ITemplateLanguageService languageService) : base(fileService, languageService) 30 | { 31 | EntitiesTemplateFiles = LanguageService.GetEntitiesTemplateFileInfo(); 32 | } 33 | 34 | /// 35 | /// Generate entity type class. 36 | /// 37 | /// Data used to generate entity type class. 38 | /// Generated entity type class. 39 | public virtual string GenerateEntityType(object data) 40 | { 41 | if (EntityTypeTemplate == null) 42 | { 43 | EntityTypeTemplate = CompileEntityTypeTemplate(); 44 | } 45 | string entityType = EntityTypeTemplate(data); 46 | return entityType; 47 | } 48 | 49 | /// 50 | /// Compile entity type template. 51 | /// 52 | /// Language option. 53 | /// Entity type template. 54 | protected virtual HandlebarsTemplate CompileEntityTypeTemplate( 55 | LanguageOptions language = LanguageOptions.CSharp) 56 | { 57 | EntitiesTemplateFiles.TryGetValue(Constants.EntityTypeTemplate, out TemplateFileInfo classFile); 58 | var entityTemplateFile = FileService.RetrieveTemplateFileContents( 59 | classFile.RelativeDirectory, classFile.FileName); 60 | var entityTemplate = HandlebarsLib.Compile(entityTemplateFile); 61 | return entityTemplate; 62 | } 63 | 64 | /// 65 | /// Get partial templates. 66 | /// 67 | /// Language option. 68 | /// Partial templates. 69 | protected override IDictionary GetPartialTemplates( 70 | LanguageOptions language = LanguageOptions.CSharp) 71 | { 72 | EntitiesTemplateFiles.TryGetValue(Constants.EntityTypeCtorTemplate, out TemplateFileInfo ctorFile); 73 | var ctorTemplateFile = FileService.RetrieveTemplateFileContents( 74 | ctorFile.RelativeDirectory, ctorFile.FileName); 75 | 76 | EntitiesTemplateFiles.TryGetValue(Constants.EntityTypeImportTemplate, out TemplateFileInfo importFile); 77 | var importTemplateFile = FileService.RetrieveTemplateFileContents( 78 | importFile.RelativeDirectory, importFile.FileName); 79 | 80 | EntitiesTemplateFiles.TryGetValue(Constants.EntityTypePropertyTemplate, out TemplateFileInfo propertyFile); 81 | var propertyTemplateFile = FileService.RetrieveTemplateFileContents( 82 | propertyFile.RelativeDirectory, propertyFile.FileName); 83 | 84 | var templates = new Dictionary 85 | { 86 | { 87 | Constants.EntityTypeCtorTemplate.ToLower(CultureInfo.InvariantCulture), 88 | ctorTemplateFile 89 | }, 90 | { 91 | Constants.EntityTypeImportTemplate.ToLower(CultureInfo.InvariantCulture), 92 | importTemplateFile 93 | }, 94 | { 95 | Constants.EntityTypePropertyTemplate.ToLower(CultureInfo.InvariantCulture), 96 | propertyTemplateFile 97 | }, 98 | }; 99 | return templates; 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Fakes/FakeScaffoldingModelFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Design; 2 | using Microsoft.EntityFrameworkCore.Design.Internal; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using Microsoft.EntityFrameworkCore.Scaffolding; 6 | using Microsoft.EntityFrameworkCore.Scaffolding.Internal; 7 | using Microsoft.EntityFrameworkCore.Scaffolding.Metadata; 8 | 9 | namespace Scaffolding.Handlebars.Tests.Fakes 10 | { 11 | public class FakeScaffoldingModelFactory : RelationalScaffoldingModelFactory 12 | { 13 | public FakeScaffoldingModelFactory( 14 | IOperationReporter reporter, 15 | ICandidateNamingService candidateNamingService, 16 | IPluralizer pluralizer, 17 | ICSharpUtilities cSharpUtilities, 18 | IScaffoldingTypeMapper scaffoldingTypeMapper, 19 | IModelRuntimeInitializer modelRuntimeInitializer) 20 | : base(reporter, candidateNamingService, pluralizer, cSharpUtilities, scaffoldingTypeMapper, modelRuntimeInitializer) 21 | { 22 | } 23 | 24 | public override IModel Create(DatabaseModel databaseModel, ModelReverseEngineerOptions options) 25 | { 26 | foreach (var sequence in databaseModel.Sequences) 27 | { 28 | sequence.Database = databaseModel; 29 | } 30 | 31 | foreach (var table in databaseModel.Tables) 32 | { 33 | table.Database = databaseModel; 34 | 35 | foreach (var column in table.Columns) 36 | { 37 | column.Table = table; 38 | } 39 | 40 | if (table.PrimaryKey != null) 41 | { 42 | table.PrimaryKey.Table = table; 43 | } 44 | 45 | foreach (var index in table.Indexes) 46 | { 47 | index.Table = table; 48 | } 49 | 50 | foreach (var uniqueConstraints in table.UniqueConstraints) 51 | { 52 | uniqueConstraints.Table = table; 53 | } 54 | 55 | foreach (var foreignKey in table.ForeignKeys) 56 | { 57 | foreignKey.Table = table; 58 | } 59 | } 60 | 61 | return base.Create(databaseModel, options); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Fakes/FakeTypeScriptTemplateLanguageService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EntityFrameworkCore.Scaffolding.Handlebars; 3 | using EntityFrameworkCore.Scaffolding.Handlebars.Helpers; 4 | 5 | namespace Scaffolding.Handlebars.Tests.Fakes 6 | { 7 | public class FakeTypeScriptTemplateLanguageService : ITemplateLanguageService 8 | { 9 | public Dictionary GetDbContextTemplateFileInfo() 10 | { 11 | var result = new Dictionary 12 | { 13 | { 14 | Constants.DbContextTemplate, 15 | new TemplateFileInfo 16 | { 17 | RelativeDirectory = Constants.TypeScriptTemplateDirectories.DbContextDirectory, 18 | FileName = Constants.DbContextTemplate + Constants.TemplateExtension 19 | } 20 | }, 21 | { 22 | Constants.DbContextImportTemplate, 23 | new TemplateFileInfo 24 | { 25 | RelativeDirectory = Constants.TypeScriptTemplateDirectories.DbContextPartialsDirectory, 26 | FileName = Constants.DbContextImportTemplate + Constants.TemplateExtension 27 | } 28 | }, 29 | { 30 | Constants.DbContextCtorTemplate, 31 | new TemplateFileInfo 32 | { 33 | RelativeDirectory = Constants.TypeScriptTemplateDirectories.DbContextPartialsDirectory, 34 | FileName = Constants.DbContextCtorTemplate + Constants.TemplateExtension 35 | } 36 | }, 37 | { 38 | Constants.DbContextOnConfiguringTemplate, 39 | new TemplateFileInfo 40 | { 41 | RelativeDirectory = Constants.TypeScriptTemplateDirectories.DbContextPartialsDirectory, 42 | FileName = Constants.DbContextOnConfiguringTemplate + Constants.TemplateExtension 43 | } 44 | }, 45 | { 46 | Constants.DbContextDbSetsTemplate, 47 | new TemplateFileInfo 48 | { 49 | RelativeDirectory = Constants.TypeScriptTemplateDirectories.DbContextPartialsDirectory, 50 | FileName = Constants.DbContextDbSetsTemplate + Constants.TemplateExtension 51 | } 52 | }, 53 | }; 54 | return result; 55 | } 56 | 57 | public Dictionary GetEntitiesTemplateFileInfo() 58 | { 59 | var result = new Dictionary 60 | { 61 | { 62 | Constants.EntityTypeTemplate, 63 | new TemplateFileInfo 64 | { 65 | RelativeDirectory = Constants.TypeScriptTemplateDirectories.EntityTypeDirectory, 66 | FileName = Constants.EntityTypeTemplate + Constants.TemplateExtension 67 | } 68 | }, 69 | { 70 | Constants.EntityTypeImportTemplate, 71 | new TemplateFileInfo 72 | { 73 | RelativeDirectory = Constants.TypeScriptTemplateDirectories.EntityTypePartialsDirectory, 74 | FileName = Constants.EntityTypeImportTemplate + Constants.TemplateExtension 75 | } 76 | }, 77 | { 78 | Constants.EntityTypeCtorTemplate, 79 | new TemplateFileInfo 80 | { 81 | RelativeDirectory = Constants.TypeScriptTemplateDirectories.EntityTypePartialsDirectory, 82 | FileName = Constants.EntityTypeCtorTemplate + Constants.TemplateExtension 83 | } 84 | }, 85 | { 86 | Constants.EntityTypePropertyTemplate, 87 | new TemplateFileInfo 88 | { 89 | RelativeDirectory = Constants.TypeScriptTemplateDirectories.EntityTypePartialsDirectory, 90 | FileName = Constants.EntityTypePropertyTemplate + Constants.TemplateExtension 91 | } 92 | }, 93 | }; 94 | return result; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Fakes/TestProviderCodeGenerator.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Design; 2 | using Microsoft.EntityFrameworkCore.Scaffolding; 3 | 4 | namespace Scaffolding.Handlebars.Tests.Fakes 5 | { 6 | public class TestProviderCodeGenerator : ProviderCodeGenerator 7 | { 8 | public TestProviderCodeGenerator(ProviderCodeGeneratorDependencies dependencies) 9 | : base(dependencies) 10 | { 11 | } 12 | 13 | public override MethodCallCodeFragment GenerateUseProvider(string connectionString, MethodCallCodeFragment providerOptions) 14 | #pragma warning disable CS0618 // Type or member is obsolete 15 | => new MethodCallCodeFragment("UseTestProvider", connectionString); 16 | #pragma warning restore CS0618 // Type or member is obsolete 17 | } 18 | } -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/FileSystemTemplateFileServiceTests.ExpectedTemplates.cs: -------------------------------------------------------------------------------- 1 | namespace Scaffolding.Handlebars.Tests 2 | { 3 | public partial class FileSystemTemplateFileServiceTests 4 | { 5 | private static class ExpectedTemplates 6 | { 7 | public const string ContextTemplate = 8 | @"{{> dbimports}} 9 | 10 | namespace {{namespace}} 11 | { 12 | public partial class {{class}} : DbContext 13 | { 14 | {{{> dbsets}}} 15 | 16 | {{{> dbconstructor}}} 17 | 18 | {{#unless suppress-on-configuring}} 19 | {{{> dbonconfiguring}}} 20 | 21 | {{/unless}} 22 | {{{on-model-creating}}} 23 | } 24 | } 25 | "; 26 | 27 | public const string EntityTemplate = 28 | @"{{> imports}} 29 | 30 | namespace {{namespace}} 31 | { 32 | {{#if comment}} 33 | /// 34 | {{comment}} 35 | /// 36 | {{/if}} 37 | {{#each class-annotations}} 38 | {{{class-annotation}}} 39 | {{/each}} 40 | public partial class {{class}} 41 | { 42 | {{{> constructor}}} 43 | {{{> properties}}} 44 | } 45 | } 46 | "; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/FileSystemTemplateFileServiceTests.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using EntityFrameworkCore.Scaffolding.Handlebars; 3 | using Scaffolding.Handlebars.Tests.Helpers; 4 | using Xunit; 5 | 6 | namespace Scaffolding.Handlebars.Tests 7 | { 8 | public partial class FileSystemTemplateFileServiceTests 9 | { 10 | private readonly string _projectRootDir = Path.Combine("..", "..", ".."); 11 | 12 | public FileSystemTemplateFileServiceTests() 13 | { 14 | var templatesAltFolder = Path.Combine(_projectRootDir, Constants.Templates.CodeTemplatesAltFolder); 15 | if (Directory.Exists(templatesAltFolder)) 16 | { 17 | Directory.Delete(templatesAltFolder, true); 18 | } 19 | } 20 | 21 | [Theory] 22 | [InlineData( 23 | Constants.Templates.CSharpTemplateDirectories.ContextFolder, 24 | Constants.Templates.ContextClassFile, 25 | ExpectedTemplates.ContextTemplate)] 26 | [InlineData( 27 | Constants.Templates.CSharpTemplateDirectories.EntityTypeFolder, 28 | Constants.Templates.EntityClassFile, 29 | ExpectedTemplates.EntityTemplate)] 30 | public void Template_File_Service_Should_Retrieve_Template( 31 | string templateFolderName, string templateFileName, string expectedTemplate) 32 | { 33 | // Act 34 | var templateExisting = RetrieveTemplate(templateFolderName, templateFileName, true); 35 | var templateNonExisting = RetrieveTemplate(templateFolderName, templateFileName, false); 36 | 37 | // Assert 38 | Assert.Equal(expectedTemplate, templateExisting); 39 | Assert.Equal(expectedTemplate, templateNonExisting); 40 | } 41 | 42 | private string RetrieveTemplate(string templateFolderName, string templateFileName, bool useExisting) 43 | { 44 | // Arrange 45 | string localDirectory = Path.Combine(_projectRootDir, 46 | Constants.Templates.CodeTemplatesFolder, templateFolderName); 47 | string altDirectory = useExisting 48 | ? localDirectory 49 | : Path.Combine(_projectRootDir, 50 | Constants.Templates.CodeTemplatesAltFolder, templateFolderName); 51 | string relativeDirectory = $"{Constants.Templates.CodeTemplatesFolder}" + 52 | $"/{templateFolderName}"; 53 | 54 | var templateService = new FileSystemTemplateFileService(); 55 | 56 | // Act 57 | return templateService.RetrieveTemplateFileContents( 58 | relativeDirectory, templateFileName, altDirectory); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | 6 | using System.Diagnostics.CodeAnalysis; 7 | 8 | [assembly: SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "", Scope = "member", Target = "~M:Scaffolding.Handlebars.Tests.ReverseEngineeringConfigurationTests.ValidateContextNameInReverseEngineerGenerator(System.String)")] 9 | [assembly: SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "", Scope = "type", Target = "~T:Scaffolding.Handlebars.Tests.Fakes.FakeScaffoldingModelFactory")] 10 | [assembly: SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "", Scope = "member", Target = "~M:Scaffolding.Handlebars.Tests.HbsTypeScriptScaffoldingGeneratorTests.CreateScaffolder(Microsoft.EntityFrameworkCore.Design.ReverseEngineerOptions,System.String)~Microsoft.EntityFrameworkCore.Scaffolding.IReverseEngineerScaffolder")] 11 | [assembly: SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "", Scope = "member", Target = "~M:Scaffolding.Handlebars.Tests.HbsCSharpScaffoldingGeneratorTests.CreateScaffolder(Microsoft.EntityFrameworkCore.Design.ReverseEngineerOptions,System.String)~Microsoft.EntityFrameworkCore.Scaffolding.IReverseEngineerScaffolder")] 12 | [assembly: SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "", Scope = "type", Target = "~T:Scaffolding.Handlebars.Tests.TestOperationReporter")] 13 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Helpers/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace Scaffolding.Handlebars.Tests.Helpers 2 | { 3 | public static class Constants 4 | { 5 | public static class Connections 6 | { 7 | public const string NorthwindTest = "NorthwindTestContext"; 8 | } 9 | 10 | public static class CollectionDefinitions 11 | { 12 | public const string DatabaseCollection = "Database Collection"; 13 | } 14 | 15 | public static class Parameters 16 | { 17 | public const string ProjectPath = "FakeProjectPath"; 18 | public const string RootNamespace = "FakeNamespace"; 19 | public const string ContextName = "FakeDbContext"; 20 | } 21 | 22 | public static class Templates 23 | { 24 | public const string ProjectFolder = "EntityFrameworkCore.Scaffolding.Handlebars"; 25 | public const string CodeTemplatesFolder = "CodeTemplates"; 26 | public const string CodeTemplatesAltFolder = "CodeTemplatesAlt"; 27 | public const string PartialsFolder = "Partials"; 28 | public const string EntityClassFile = "Class.hbs"; 29 | public const string EntityImportsFile = "Imports.hbs"; 30 | public const string EntityCtorFile = "Constructor.hbs"; 31 | public const string EntityPropertiesFile = "Properties.hbs"; 32 | public const string ContextClassFile = "DbContext.hbs"; 33 | public const string ContextImportsFile = "DbImports.hbs"; 34 | public const string ContextCtorFile = "DbConstructor.hbs"; 35 | public const string ContextOnConfiguringFile = "DbOnConfiguring.hbs"; 36 | public const string ContextDbSetsFile = "DbSets.hbs"; 37 | public static class CSharpTemplateDirectories 38 | { 39 | public const string EntityTypeFolder = "CSharpEntityType"; 40 | public const string ContextFolder = "CSharpDbContext"; 41 | } 42 | public static class TypeScriptTemplateDirectories 43 | { 44 | public const string EntityTypeFolder = "TypeScriptEntityType"; 45 | public const string ContextFolder = "TypeScriptDbContext"; 46 | } 47 | } 48 | 49 | public static class Files 50 | { 51 | public static class CSharpFiles 52 | { 53 | public const string DbContextFile = Parameters.ContextName + ".cs"; 54 | public const string CategoryFile = "Category.cs"; 55 | public const string CustomerFile = "Customer.cs"; 56 | public const string ProductFile = "Product.cs"; 57 | } 58 | public static class TypeScriptFiles 59 | { 60 | public const string DbContextFile = Parameters.ContextName + ".cs"; 61 | public const string CategoryFile = "Category.ts"; 62 | public const string CustomerFile = "Customer.ts"; 63 | public const string ProductFile = "Product.ts"; 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Helpers/DatabaseCollection.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace Scaffolding.Handlebars.Tests.Helpers; 4 | 5 | [CollectionDefinition(Constants.CollectionDefinitions.DatabaseCollection)] 6 | public class DatabaseCollection : ICollectionFixture 7 | { 8 | // This class has no code, and is never created. Its purpose is simply 9 | // to be the place to apply [CollectionDefinition] and all the 10 | // ICollectionFixture<> interfaces. 11 | } -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Helpers/DatabaseFixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.Data.Common; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.Configuration; 6 | using Scaffolding.Handlebars.Tests.Contexts; 7 | 8 | namespace Scaffolding.Handlebars.Tests.Helpers; 9 | 10 | public class DatabaseFixture : IDisposable 11 | { 12 | public IConfiguration Configuration { get; private set; } 13 | public string ConnectionString { get; private set; } 14 | public NorthwindDbContext NorthwindDbContext { get; private set; } 15 | 16 | private DbConnection _connection; 17 | 18 | public void Initialize() 19 | { 20 | Configuration = new ConfigurationBuilder() 21 | .AddJsonFile("appsettings.json") 22 | .AddUserSecrets("7cd5132a-1f06-4001-b62c-51cdcbe38dbf") 23 | .AddEnvironmentVariables() 24 | .Build(); 25 | 26 | ConnectionString = Configuration.GetConnectionString(Constants.Connections.NorthwindTest); 27 | 28 | var options = new DbContextOptionsBuilder() 29 | .UseSqlServer(ConnectionString) 30 | .Options; 31 | NorthwindDbContext = new NorthwindDbContext(options); 32 | 33 | // If login error, manually create NorthwindTest database 34 | NorthwindDbContext.Database.EnsureCreated(); 35 | _connection = NorthwindDbContext.Database.GetDbConnection(); 36 | } 37 | 38 | public void Dispose() 39 | { 40 | if (_connection != null && _connection.State != ConnectionState.Closed) 41 | _connection.Close(); 42 | } 43 | } -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Helpers/HandlebarsTransformers.cs: -------------------------------------------------------------------------------- 1 | using EntityFrameworkCore.Scaffolding.Handlebars; 2 | using System.Collections.Generic; 3 | 4 | namespace Scaffolding.Handlebars.Tests.Helpers 5 | { 6 | public static class HandlebarsTransformers 7 | { 8 | static readonly Dictionary _entityTypeNameMappings = new() 9 | { 10 | { "Product","ProductRenamed" }, 11 | { "Customer","CustomerRenamed" }, 12 | { "Category", "CategoryRenamed" } 13 | }; 14 | static readonly Dictionary _entityPropertyNameMappings = new() 15 | { 16 | { "ProductId", "ProductIdRenamed" }, 17 | { "UnitPrice","UnitPriceRenamed"}, 18 | { "CategoryId", "CategoryIdRenamed" }, 19 | { "CategoryName","CategoryNameRenamed" } 20 | }; 21 | public static string MapEntityName(string entityName) => 22 | _entityTypeNameMappings.TryGetValue(entityName, out var nameOverride) ? nameOverride : entityName; 23 | 24 | public static EntityPropertyInfo MapNavPropertyInfo(EntityPropertyInfo e) => 25 | new(MapPropertyTypeName(e.PropertyType), MapPropertyName(e.PropertyName)); 26 | 27 | public static EntityPropertyInfo MapPropertyInfo(EntityPropertyInfo e) => 28 | new(MapPropertyTypeName(e.PropertyType), MapPropertyName(e.PropertyName)); 29 | 30 | private static string MapPropertyTypeName(string propertyTypeName) => 31 | _entityTypeNameMappings.TryGetValue(propertyTypeName, out var propertyTypeNameOverride) ? propertyTypeNameOverride : propertyTypeName; 32 | 33 | private static string MapPropertyName(string propertyName) => 34 | _entityPropertyNameMappings.TryGetValue(propertyName, out var propertyNameOverride) ? propertyNameOverride : propertyName; 35 | } 36 | } -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Helpers/TempDirectory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using IOPath = System.IO.Path; 4 | 5 | namespace Scaffolding.Handlebars.Tests.Helpers 6 | { 7 | public class TempDirectory : IDisposable 8 | { 9 | public TempDirectory() 10 | { 11 | Path = IOPath.Combine(IOPath.GetTempPath(), IOPath.GetRandomFileName()); 12 | Directory.CreateDirectory(Path); 13 | } 14 | 15 | public string Path { get; } 16 | 17 | public void Dispose() 18 | => Directory.Delete(Path, recursive: true); 19 | } 20 | } -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Helpers/TestRelationalLoggingDefinitions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Diagnostics; 2 | 3 | namespace Scaffolding.Handlebars.Tests.Helpers 4 | { 5 | public class TestRelationalLoggingDefinitions : RelationalLoggingDefinitions 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/IModelExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EntityFrameworkCore.Scaffolding.Handlebars; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Metadata.Conventions; 5 | using Scaffolding.Handlebars.Tests.Models; 6 | using Xunit; 7 | 8 | namespace Scaffolding.Handlebars.Tests 9 | { 10 | public class IModelExtensionsTests 11 | { 12 | [Fact] 13 | public void IModel_Extensions_Should_Filter_EntityTypes_From_Options_By_Table_Name_Only() 14 | { 15 | var builder = new ModelBuilder(new ConventionSet()); 16 | builder.Entity() 17 | .ToTable("Category", "dbo"); 18 | 19 | builder.Entity() 20 | .ToTable("Product", "prd"); 21 | 22 | var options = new HandlebarsScaffoldingOptions 23 | { 24 | ExcludedTables = new List {"Product"} 25 | }; 26 | 27 | var entityTypes = builder.FinalizeModel().GetScaffoldEntityTypes(options); 28 | Assert.Contains(entityTypes, e => e.ClrType.Name == "Category"); 29 | Assert.DoesNotContain(entityTypes, e => e.ClrType.Name == "Product"); 30 | } 31 | 32 | [Fact] 33 | public void IModel_Extensions_Should_Filter_EntityTypes_From_Options_By_Table_Name_and_Schema() 34 | { 35 | var builder = new ModelBuilder(new ConventionSet()); 36 | builder.Entity() 37 | .ToTable("Category", "dbo"); 38 | 39 | builder.Entity() 40 | .ToTable("Product", "prd"); 41 | 42 | var options = new HandlebarsScaffoldingOptions 43 | { 44 | ExcludedTables = new List { "dbo.Category", "dbo.Product" } 45 | }; 46 | 47 | var entityTypes = builder.FinalizeModel().GetScaffoldEntityTypes(options); 48 | Assert.DoesNotContain(entityTypes, e => e.ClrType.Name == "Category"); 49 | Assert.Contains(entityTypes, e => e.ClrType.Name == "Product"); 50 | } 51 | 52 | [Fact] 53 | public void IModel_Extensions_Should_Not_Filter_If_No_Excluded_Tables() 54 | { 55 | var builder = new ModelBuilder(new ConventionSet()); 56 | builder.Entity() 57 | .ToTable("Category", "dbo"); 58 | 59 | builder.Entity() 60 | .ToTable("Product", "prd"); 61 | 62 | var options = new HandlebarsScaffoldingOptions 63 | { 64 | ExcludedTables = null 65 | }; 66 | 67 | var entityTypes = builder.FinalizeModel().GetScaffoldEntityTypes(options); 68 | Assert.Contains(entityTypes, e => e.ClrType.Name == "Category"); 69 | Assert.Contains(entityTypes, e => e.ClrType.Name == "Product"); 70 | } 71 | 72 | [Fact] 73 | public void IModel_Extensions_Should_Filter_EntityTypes_From_Options_By_View_Name_Only() 74 | { 75 | var builder = new ModelBuilder(new ConventionSet()); 76 | builder.Entity() 77 | .ToView("Category", "dbo"); 78 | 79 | builder.Entity() 80 | .ToView("Product", "prd"); 81 | 82 | var options = new HandlebarsScaffoldingOptions 83 | { 84 | ExcludedTables = new List { "Product" } 85 | }; 86 | 87 | var entityTypes = builder.FinalizeModel().GetScaffoldEntityTypes(options); 88 | Assert.Contains(entityTypes, e => e.ClrType.Name == "Category"); 89 | Assert.DoesNotContain(entityTypes, e => e.ClrType.Name == "Product"); 90 | } 91 | 92 | [Fact] 93 | public void IModel_Extensions_Should_Filter_EntityTypes_From_Options_By_View_Name_and_Schema() 94 | { 95 | var builder = new ModelBuilder(new ConventionSet()); 96 | builder.Entity() 97 | .ToView("Category", "dbo"); 98 | 99 | builder.Entity() 100 | .ToView("Product", "prd"); 101 | 102 | var options = new HandlebarsScaffoldingOptions 103 | { 104 | ExcludedTables = new List { "dbo.Category", "dbo.Product" } 105 | }; 106 | 107 | var entityTypes = builder.FinalizeModel().GetScaffoldEntityTypes(options); 108 | Assert.DoesNotContain(entityTypes, e => e.ClrType.Name == "Category"); 109 | Assert.Contains(entityTypes, e => e.ClrType.Name == "Product"); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Models/Category.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace Scaffolding.Handlebars.Tests.Models 6 | { 7 | [Table("Category")] 8 | public class Category 9 | { 10 | [Key] 11 | public int CategoryId { get; set; } 12 | [Required] 13 | [StringLength(15)] 14 | public string CategoryName { get; set; } 15 | public List Products { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Models/Customer.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace Scaffolding.Handlebars.Tests.Models 5 | { 6 | [Table("Customer")] 7 | public partial class Customer 8 | { 9 | [Key] 10 | [StringLength(5)] 11 | public string CustomerKey { get; set; } 12 | [Required] 13 | [StringLength(40)] 14 | public string CompanyName { get; set; } 15 | [StringLength(30)] 16 | public string ContactName { get; set; } 17 | [StringLength(15)] 18 | public string City { get; set; } 19 | [StringLength(15)] 20 | public string Country { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Models/Product.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace Scaffolding.Handlebars.Tests.Models 5 | { 6 | [Table("Product")] 7 | public class Product 8 | { 9 | [Key] 10 | public int ProductId { get; set; } 11 | [Required] 12 | [StringLength(40)] 13 | public string ProductName { get; set; } 14 | [Column(TypeName = "money")] 15 | public decimal? UnitPrice { get; set; } 16 | public bool Discontinued { get; set; } 17 | [Column(TypeName = "timestamp")] 18 | [DatabaseGenerated(DatabaseGeneratedOption.Computed)] 19 | [MaxLength(8)] 20 | public byte[] RowVersion { get; set; } 21 | 22 | public int? CategoryId { get; set; } 23 | [ForeignKey("CategoryId")] 24 | public Category Category { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Scaffolding.Handlebars.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | false 6 | latest 7 | 7cd5132a-1f06-4001-b62c-51cdcbe38dbf 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | all 24 | runtime; build; native; contentfiles; analyzers; buildtransitive 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Never 35 | 36 | 37 | Never 38 | 39 | 40 | Never 41 | 42 | 43 | Never 44 | 45 | 46 | Never 47 | 48 | 49 | Never 50 | 51 | 52 | Never 53 | 54 | 55 | Never 56 | 57 | 58 | PreserveNewest 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/Tests.ReadMe.md: -------------------------------------------------------------------------------- 1 | # Handlebars Scaffolding Tests 2 | 3 | ## Windows Intel Setup 4 | 5 | - Use SQL Server Management Studio to connect to SQL Server 6 | - The easiest is to use **LocalDb**, which is installed with Visual Studio. 7 | - Connect to: `(localdb)\MsSqlLocalDb`. 8 | 9 | ## MacOS arm64 Setup (M Series) 10 | 11 | - Install [Docker Desktop](https://www.docker.com/products/docker-desktop/) 12 | - Run Docker SQL Server instance for arm64 13 | 14 | ``` 15 | docker run -e "ACCEPT_EULA=1" -e "MSSQL_SA_PASSWORD=MyPass@word" -e "MSSQL_PID=Developer" -e "MSSQL_USER=SA" -p 1433:1433 -d --name=sql mcr.microsoft.com/azure-sql-edge 16 | ``` 17 | 18 | - Add VS Code [Extension for SQL Server](https://marketplace.visualstudio.com/items?itemName=ms-mssql.mssql) 19 | - Connect with username `sa` and password `MyPass@word` 20 | - Enable trust server certificate when prompted 21 | - See [here](https://learn.microsoft.com/en-us/sql/tools/visual-studio-code/sql-server-develop-use-vscode?view=sql-server-ver16) for help connecting and writing commands and queries 22 | - Set connection string with Secret Manager 23 | 24 | ``` 25 | dotnet user-secrets set "ConnectionStrings:NorthwindTestContext" "Server=localhost; Database=NorthwindTestDb; User ID=sa;Password=MyPass@word; TrustServerCertificate=True;" 26 | ``` 27 | -------------------------------------------------------------------------------- /test/Scaffolding.Handlebars.Tests/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "NorthwindTestContext": "Data Source=(localdb)\\MSSQLLocalDB; Initial Catalog=NorthwindTestDb; Integrated Security=True" 4 | } 5 | } --------------------------------------------------------------------------------