-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathClientGeneratorBase.cs
192 lines (163 loc) · 8.55 KB
/
ClientGeneratorBase.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//-----------------------------------------------------------------------
// <copyright file="ClientGeneratorBase.cs" company="NSwag">
// Copyright (c) Rico Suter. All rights reserved.
// </copyright>
// <license>https://github.com/RicoSuter/NSwag/blob/master/LICENSE.md</license>
// <author>Rico Suter, [email protected]</author>
//-----------------------------------------------------------------------
using NJsonSchema;
using NJsonSchema.CodeGeneration;
using NSwag.CodeGeneration.Models;
namespace NSwag.CodeGeneration
{
/// <summary>The client generator base.</summary>
/// <typeparam name="TOperationModel">The type of the operation model.</typeparam>
/// <typeparam name="TParameterModel">The type of the parameter model.</typeparam>
/// <typeparam name="TResponseModel">The type of the response model.</typeparam>
/// <seealso cref="IClientGenerator" />
public abstract class ClientGeneratorBase<TOperationModel, TParameterModel, TResponseModel> : IClientGenerator
where TOperationModel : OperationModelBase<TParameterModel, TResponseModel>
where TResponseModel : ResponseModelBase
where TParameterModel : ParameterModelBase
{
private readonly OpenApiDocument _document;
/// <summary>Initializes a new instance of the <see cref="ClientGeneratorBase{TOperationModel, TParameterModel, TResponseModel}"/> class.</summary>
/// <param name="document">The document.</param>
/// <param name="settings">The code generator settings.</param>
/// <param name="resolver">The type resolver.</param>
protected ClientGeneratorBase(OpenApiDocument document, CodeGeneratorSettingsBase settings,
TypeResolverBase resolver)
{
_document = document;
Resolver = resolver;
settings.SchemaType = document.SchemaType; // enforce Swagger schema output
}
/// <summary>Gets the base settings.</summary>
public abstract ClientGeneratorBaseSettings BaseSettings { get; }
/// <summary>Gets the type resolver.</summary>
protected TypeResolverBase Resolver { get; }
/// <summary>Gets the type.</summary>
/// <param name="schema">The schema.</param>
/// <param name="isNullable">Specifies whether the type is nullable..</param>
/// <param name="typeNameHint">The type name hint.</param>
/// <returns>The type name.</returns>
public abstract string GetTypeName(JsonSchema schema, bool isNullable, string typeNameHint);
/// <summary>Gets the file response type name.</summary>
/// <returns>The type name.</returns>
public virtual string GetBinaryResponseTypeName()
{
return "FileResponse";
}
/// <summary>Generates the the whole file containing all needed types.</summary>
/// <returns>The code</returns>
public string GenerateFile()
{
return GenerateFile(ClientGeneratorOutputType.Full);
}
/// <summary>Generates the the whole file containing all needed types.</summary>
/// <param name="outputType">Type of the output.</param>
/// <returns>The code</returns>
public string GenerateFile(ClientGeneratorOutputType outputType)
{
var clientTypes = GenerateAllClientTypes();
var dtoTypes = BaseSettings.GenerateDtoTypes ? GenerateDtoTypes() : [];
clientTypes = outputType switch
{
ClientGeneratorOutputType.Full => clientTypes,
ClientGeneratorOutputType.Implementation => clientTypes.Where(t =>
t.Category != CodeArtifactCategory.Contract),
ClientGeneratorOutputType.Contracts => clientTypes.Where(t =>
t.Category == CodeArtifactCategory.Contract),
_ => []
};
dtoTypes = outputType is ClientGeneratorOutputType.Full or ClientGeneratorOutputType.Contracts
? dtoTypes
: [];
return GenerateFile(clientTypes, dtoTypes, outputType)
.Replace("\r", string.Empty)
.Replace("\n\n\n\n", "\n\n")
.Replace("\n\n\n", "\n\n");
}
/// <summary>Generates the file.</summary>
/// <param name="clientTypes">The client types.</param>
/// <param name="dtoTypes">The DTO types.</param>
/// <param name="outputType">Type of the output.</param>
/// <returns>The code.</returns>
protected abstract string GenerateFile(IEnumerable<CodeArtifact> clientTypes,
IEnumerable<CodeArtifact> dtoTypes, ClientGeneratorOutputType outputType);
/// <summary>Generates the client types.</summary>
/// <returns>The code artifact collection.</returns>
protected virtual IEnumerable<CodeArtifact> GenerateAllClientTypes()
{
var operations = GetOperations(_document);
var clientTypes = new List<CodeArtifact>();
if (BaseSettings.OperationNameGenerator.SupportsMultipleClients)
{
var controllerOperationsGroups = operations.GroupBy(o => o.ControllerName);
foreach (var controllerOperations in controllerOperationsGroups)
{
var controllerName = controllerOperations.Key;
var controllerClassName = BaseSettings.GenerateControllerName(controllerOperations.Key);
var clientType = GenerateClientTypes(controllerName, controllerClassName, [.. controllerOperations]);
clientTypes.AddRange(clientType);
}
}
else
{
var controllerName = string.Empty;
var controllerClassName = BaseSettings.GenerateControllerName(controllerName);
var clientType = GenerateClientTypes(controllerName, controllerClassName, operations);
clientTypes.AddRange(clientType);
}
return clientTypes;
}
/// <summary>Generates the client class.</summary>
/// <param name="controllerName">Name of the controller.</param>
/// <param name="controllerClassName">Name of the controller class.</param>
/// <param name="operations">The operations.</param>
/// <returns>The code.</returns>
protected abstract IEnumerable<CodeArtifact> GenerateClientTypes(string controllerName,
string controllerClassName, IEnumerable<TOperationModel> operations);
/// <summary>Generates all DTO types.</summary>
/// <returns>The code artifact collection.</returns>
protected abstract IEnumerable<CodeArtifact> GenerateDtoTypes();
/// <summary>Creates an operation model.</summary>
/// <param name="operation">The operation.</param>
/// <param name="settings">The settings.</param>
/// <returns>The operation model.</returns>
protected abstract TOperationModel CreateOperationModel(OpenApiOperation operation,
ClientGeneratorBaseSettings settings);
private List<TOperationModel> GetOperations(OpenApiDocument document)
{
document.GenerateOperationIds();
var result = new List<TOperationModel>();
foreach (var pair in document.Paths)
{
foreach (var p in pair.Value.ActualPathItem)
{
var path = pair.Key.TrimStart('/');
var httpMethod = p.Key;
var operation = p.Value;
var operationName =
BaseSettings.OperationNameGenerator.GetOperationName(document, path, httpMethod, operation);
if (operationName.Contains("."))
{
operationName = operationName.Replace(".", "_");
}
if (operationName.EndsWith("Async", StringComparison.Ordinal))
{
operationName = operationName.Substring(0, operationName.Length - "Async".Length);
}
var operationModel = CreateOperationModel(operation, BaseSettings);
operationModel.ControllerName =
BaseSettings.OperationNameGenerator.GetClientName(document, path, httpMethod, operation);
operationModel.Path = path;
operationModel.HttpMethod = httpMethod;
operationModel.OperationName = operationName;
result.Add(operationModel);
}
}
return result;
}
}
}