Skip to content

Feature/customize locations #212

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Jan 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f905d01
feat: introduce ContractsLocation & EndpointsLocation
davidkallesen Dec 21, 2024
2132159
feat: add NamespaceFactory
davidkallesen Dec 21, 2024
a795666
feat: add FileInfoFactory
davidkallesen Dec 21, 2024
dfda52f
feat: add StringExtensions with EnsureNamespaceFormat
davidkallesen Dec 21, 2024
561d670
feat: add client options for use-partial-class for contracts and endp…
davidkallesen Jan 6, 2025
5e3f257
feat: add options contract-locations
davidkallesen Jan 6, 2025
b054e06
chore: rename AccessModifiers to DeclarationModifiers and add a more …
davidkallesen Jan 7, 2025
1f1bf69
test: add FileInfoFactoryTests and NamespaceFactoryTests
davidkallesen Jan 7, 2025
5e6cd23
refactor: introduce GeneratorSettings in framework and map options to it
davidkallesen Jan 8, 2025
82fd2d5
refact: extend GeneratorSettings with Version, ProjectName and Projec…
davidkallesen Jan 8, 2025
7949960
chore: cleanup in css
davidkallesen Jan 9, 2025
111c43c
refactor: fix missing of NamespaceFactory.CreateFull & FileInfoFactor…
davidkallesen Jan 9, 2025
8f06295
wip: prepare namespace for apiGroupName template/location
davidkallesen Jan 10, 2025
1a51f18
test: add secnario "CodeStructure1"
davidkallesen Jan 11, 2025
59a9230
chore: cleanup (remove clientFolderName)
davidkallesen Jan 11, 2025
f3cf7f0
chore: ajust the ApiGeneratorOptions.json with missing properties
davidkallesen Jan 11, 2025
8bea084
docs: update readme
davidkallesen Jan 11, 2025
4080e59
test: add NamespaceFactoryTests
davidkallesen Jan 11, 2025
143614e
test: rename CodeStructure1 -> Structure1 due to "Filename too long"
davidkallesen Jan 11, 2025
24c697b
test: set Traits.Categories.Integration on FileInfoFactoryTests (wind…
davidkallesen Jan 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 8 additions & 1 deletion ApiGeneratorOptions.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
"swaggerThemeMode": "None",
"useRestExtended": true,
"includeDeprecated": false,
"projectSuffixName": "",
"contractsLocation": "Contracts.[[apiGroupName]]",
"endpointsLocation": "Endpoints.[[apiGroupName]]",
"handlersLocation": "Handlers.[[apiGroupName]]",
"usePartialClassForContracts": false,
"usePartialClassForEndpoints": false,
"removeNamespaceGroupSeparatorInGlobalUsings": false,
"request": {},
"response": {
"useProblemDetailsAsDefaultBody": false
Expand All @@ -16,5 +23,5 @@
"modelNameCasingStyle": "PascalCase",
"modelPropertyNameCasingStyle": "CamelCase"
},
"includeDeprecated": false
"includeDeprecatedOperations": false
}
1 change: 1 addition & 0 deletions Atc.Rest.Api.Generator.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Methode/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Usings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Versioning/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=WOPD/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Xunit/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
149 changes: 142 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
- [Option **generate server all -h**](#option-generate-server-all--h)
- [Command **options-file**](#command-options-file)
- [Default options-file - ApiGeneratorOptions.json](#default-options-file---apigeneratoroptionsjson)
- [Custom options-file - ApiGeneratorOptions.json](#custom-options-file---apigeneratoroptionsjson)
- [Options for locations explained](#options-for-locations-explained)
- [Syntax](#syntax)
- [Examples](#examples)
- [Other options explained](#other-options-explained)
- [PetStore Example](#petstore-example)
- [Security - supporting role-based security and custom authentication-schemes](#security---supporting-role-based-security-and-custom-authentication-schemes)
- [Roles and authentication-scheme validation](#roles-and-authentication-scheme-validation)
Expand Down Expand Up @@ -79,12 +84,12 @@ flowchart TB;

CLI --> ApiGenerator;
CLI --> CodingRules;

ApiGenerator --> ClientCSharp;
ApiGenerator --> ServerMvc;
ApiGenerator --> ServerMinimal;
ApiGenerator .-> Contracts;

ClientCSharp --> Framework;
ClientCSharp .-> Contracts;
ClientCSharp .-> CSharpGenerator;
Expand Down Expand Up @@ -181,6 +186,9 @@ COMMANDS:
```powershell
atc-rest-api-generator generate server all -h

DESCRIPTION:
Creates API, domain and host projects.

USAGE:
atc-rest-api-generator.exe generate server all [OPTIONS]

Expand All @@ -195,16 +203,24 @@ OPTIONS:
-s, --specificationPath <SPECIFICATIONPATH> Path to Open API specification (directory, file or url)
--optionsPath [OPTIONSPATH] Path to options json-file
--validate-strictMode Use strictmode
--validate-operationIdValidation Use operationId validation
--validate-operationIdCasingStyle [OPERATIONIDCASINGSTYLE] Set casingStyle for operationId. Valid values are: CamelCase (default), KebabCase, PascalCase, SnakeCase
--validate-modelNameCasingStyle [MODELNAMECASINGSTYLE] Set casingStyle for model name. Valid values are: CamelCase, KebabCase, PascalCase (default), SnakeCase
--validate-modelPropertyNameCasingStyle [MODELPROPERTYNAMECASINGSTYLE] Set casingStyle for model property name. Valid values are: CamelCase (default), KebabCase, PascalCase, SnakeCase
--useAuthorization Use authorization
-p, --projectPrefixName <PROJECTPREFIXNAME> Project prefix name (e.g. 'PetStore' becomes 'PetStore.Api.Generated')
--disableCodingRules Disable ATC-Coding-Rules
--useProblemDetailsAsDefaultResponseBody Use ProblemDetails as default responsen body
--endpointsLocation [ENDPOINTSLOCATION] If endpoints-localtion is provided, generated files will be placed here instead of the Endpoints folder
--contractsLocation [CONTRACTSLOCATION] If contracts-localtion is provided, generated files will be placed here instead of the Contracts folder
--handlersLocation [HANDLERSLOCATION] If handlers-localtion is provided, generated files will be placed here instead of the Handlers folder
--usePartialClassForContracts Use Partial-Class for contracts
--usePartialClassForEndpoints Use Partial-Class for endpoints
--removeNamespaceGroupSeparatorInGlobalUsings Remove space between namespace groups in GlobalUsing.cs
--aspnet-output-type [ASPNETOUTPUTTYPE] Set AspNet output type for the generated api. Valid values are: Mvc (default), MinimalApi
--swagger-theme [SWAGGERTHEME] Set Swagger theme for the hosting api. Valid values are: None, Default (default), Light, Dark
--outputSlnPath <OUTPUTSLNPATH> Path to solution file (directory or file)
--outputSrcPath <OUTPUTSRCPATH> Path to generated src projects (directory)
--outputTestPath [OUTPUTTESTPATH] Path to generated test projects (directory)
--disableCodingRules Disable ATC-Coding-Rules
--removeNamespaceGroupSeparatorInGlobalUsings Remove space between namespace groups in GlobalUsing.cs
```

#### Command **options-file**
Expand All @@ -225,27 +241,146 @@ COMMANDS:
validate Validate the options file 'ApiGeneratorOptions.json'
```

> **Note:** All values from the options-file will be overriden if pressent from the CLI options.
>
> **Example:** If the usePartialClassForContracts=false in the options-file and the CLI `--usePartialClassForContracts` options set, then the usePartialClassForContracts is true.

#### Default options-file - ApiGeneratorOptions.json

```json
{
"generator": {
"useAuthorization": false,
"aspNetOutputType": "Mvc",
"swaggerThemeMode": "None",
"useRestExtended": true,
"projectName": "",
"projectSuffixName": "",
"contractsLocation": "Contracts.[[apiGroupName]]",
"endpointsLocation": "Endpoints.[[apiGroupName]]",
"handlersLocation": "Handlers.[[apiGroupName]]",
"usePartialClassForContracts": false,
"usePartialClassForEndpoints": false,
"removeNamespaceGroupSeparatorInGlobalUsings": false,
"request": {},
"response": {
"useProblemDetailsAsDefaultBody": false
}
},
"validation": {
"strictMode": false,
"operationIdValidation": false,
"operationIdCasingStyle": "CamelCase",
"modelNameCasingStyle": "PascalCase",
"modelPropertyNameCasingStyle": "CamelCase"
}
},
"includeDeprecatedOperations": false
}
```

#### Custom options-file - ApiGeneratorOptions.json

```json
{
"generator": {
"aspNetOutputType": "MinimalApi",
"swaggerThemeMode": "Dark",
"useRestExtended": true,
"projectName": "",
"projectSuffixName": "",
"contractsLocation": "Contracts.[[apiGroupName]]",
"endpointsLocation": "Endpoints.[[apiGroupName]]",
"handlersLocation": "Handlers.[[apiGroupName]]",
"usePartialClassForContracts": false,
"usePartialClassForEndpoints": false,
"removeNamespaceGroupSeparatorInGlobalUsings": false,
"request": {},
"response": {
"useProblemDetailsAsDefaultBody": false,
"customErrorResponseModel": {
"name": "ErrorResponse",
"description": "Represents an error response.",
"schema": {
"status": {
"dataType": "string?",
"description": "Gets or sets the status of the error."
},
"message": {
"dataType": "string?",
"description": "Gets or sets the error message."
},
"readableMessage": {
"dataType": "string?",
"description": "Gets or sets the readable message."
},
"errorCode": {
"dataType": "string?",
"description": "Gets or sets the error code."
},
"context": {
"dataType": "object?",
"description": "Gets or sets the context information."
}
}
}
},
"client": {
"excludeEndpointGeneration": false,
"httpClientName": "My-ApiClient"
}
},
"validation": {
"strictMode": false,
"operationIdValidation": false,
"operationIdCasingStyle": "CamelCase",
"modelNameCasingStyle": "PascalCase",
"modelPropertyNameCasingStyle": "CamelCase"
},
"includeDeprecatedOperations": false
}
```

#### Options for locations explained

The following options control the file locations for generated files such as contracts, endpoints, and handlers.
You can use specific syntax to define and customize the output file structure.

##### Syntax

For options like `contractsLocation`, `endpointsLocation`, and `handlersLocation`,
you can define paths using placeholders and custom directory names.

The syntax is flexible and allows you to organize files based on grouping or specific requirements.

##### Examples

| Option-Name | Option-Value | Example-file | Generated-output |
|-------------|--------------|--------------|------------------|
| contractsLocation | Contracts | Account.cs | [Project-root]\Contracts\Accounts\Account.cs |
| contractsLocation | Contracts.[[apiGroupName]] | Account.cs | [Project-root]\Contracts\Accounts\Account.cs |
| contractsLocation | Contracts-[[apiGroupName]] | Account.cs | [Project-root]\Contracts\Accounts\Account.cs |
| contractsLocation | [[apiGroupName]].MyContracts | Account.cs | [Project-root]\Accounts\MyContracts\Account.cs |
| contractsLocation | [[apiGroupName]]-MyContracts | Account.cs | [Project-root]\Accounts\MyContracts\Account.cs |
| contractsLocation | [[apiGroupName]] | Account.cs | [Project-root]\Accounts\Account.cs |
| contractsLocation | . | Account.cs | [Project-root]\Account.cs |

> Placeholder Explanation:
>
> - [[apiGroupName]]: A placeholder replaced by the API group name during code generation. This allows grouping files dynamically based on your API structure.
> - [Project-root]: The root directory of your project where the generated files will be placed.

By using these options, you can effectively organize generated files into meaningful folder structures, ensuring clarity and scalability in your project layout.

#### Other options explained

The `projectSuffixName` extend `projectName` like the example:

| projectName | projectSuffixName | Generated project name | Reson |
|-------------|-------------------|------------------------|-------|
| PetStore | | PetStore.Api.Generated | default is `Api.Generated` |
| PetStore | MyApi | PetStore.MyApi | |
| PetStore | Foo.Api | PetStore.Foo.Api | |
| PetStore | Bar-Api | PetStore.Bar.Api | |

## PetStore Example

The following command will generate an API that implements the offcial Pet Store example from Swagger.
Expand Down
33 changes: 6 additions & 27 deletions src/Atc.CodeGeneration.CSharp/Content/AccessModifiers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,18 @@ public enum AccessModifiers
[Description("public")]
Public,

[Description("public async")]
PublicAsync,

[Description("public static")]
PublicStatic,

[Description("public static implicit operator")]
PublicStaticImplicitOperator,

[Description("public class")]
PublicClass,

[Description("public static class")]
PublicStaticClass,

[Description("public sealed class")]
PublicSealedClass,

[Description("public record")]
PublicRecord,

[Description("public record struct")]
PublicRecordStruct,

[Description("private")]
Private,

[Description("private async")]
PrivateAsync,

[Description("protected")]
Protected,

[Description("internal")]
Internal,

[Description("protected internal")]
ProtectedInternal,

[Description("private protected")]
PrivateProtected,
}
63 changes: 63 additions & 0 deletions src/Atc.CodeGeneration.CSharp/Content/DeclarationModifiers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
namespace Atc.CodeGeneration.CSharp.Content;

public enum DeclarationModifiers
{
None,

[Description("public")]
Public,

[Description("public async")]
PublicAsync,

[Description("public static")]
PublicStatic,

[Description("public static implicit operator")]
PublicStaticImplicitOperator,

[Description("public class")]
PublicClass,

[Description("public partial class")]
PublicPartialClass,

[Description("public static class")]
PublicStaticClass,

[Description("public sealed class")]
PublicSealedClass,

[Description("public interface")]
PublicInterface,

[Description("public partial interface")]
PublicPartialInterface,

[Description("public static interface")]
PublicStaticInterface,

[Description("public record")]
PublicRecord,

[Description("public record struct")]
PublicRecordStruct,

[Description("public partial record")]
PublicPartialRecord,

[Description("public partial record struct")]
PublicPartialRecordStruct,

[Description("private")]
Private,

[Description("private async")]
PrivateAsync,

[Description("protected")]
Protected,

[Description("internal")]
Internal,
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ public static ClassParameters Create(
string headerContent,
string @namespace,
AttributeParameters attribute,
string classTypeName)
string classTypeName,
bool usePartialClass = false)
=> new(
HeaderContent: headerContent,
Namespace: @namespace,
DocumentationTags: null,
Attributes: new List<AttributeParameters> { attribute },
AccessModifiers.PublicClass,
usePartialClass ? DeclarationModifiers.PublicPartialClass : DeclarationModifiers.PublicClass,
ClassTypeName: classTypeName,
GenericTypeName: null,
InheritedClassTypeName: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public static EnumParameters Create(
Namespace: @namespace,
DocumentationTags: documentationTags,
Attributes: attributes,
AccessModifier: AccessModifiers.Public,
DeclarationModifier: DeclarationModifiers.Public,
EnumTypeName: enumTypeName,
UseFlags: false,
EnumValuesParametersFactory.Create(enumNames));
Expand All @@ -31,7 +31,7 @@ public static EnumParameters Create(
Namespace: @namespace,
DocumentationTags: documentationTags,
Attributes: attributes,
AccessModifier: AccessModifiers.Public,
DeclarationModifier: DeclarationModifiers.Public,
EnumTypeName: enumTypeName,
UseFlags: DetermineIfFlagsAttributeShouldBeUsed(enumNameValues),
EnumValuesParametersFactory.Create(enumNameValues));
Expand Down
Loading
Loading