1
1
using System ;
2
2
using System . Collections . Generic ;
3
3
using System . Linq ;
4
+ using System . Text ;
4
5
using System . Text . RegularExpressions ;
5
6
using Humanizer ;
6
7
using Humanizer . Inflections ;
8
+ using Microsoft . OpenApi . Hidi . Extensions ;
7
9
using Microsoft . OpenApi . Models ;
8
10
using Microsoft . OpenApi . Services ;
9
11
@@ -29,7 +31,7 @@ static PowerShellFormatter()
29
31
Vocabularies . Default . AddSingular ( "(statistics)$" , "$1" ) ;
30
32
}
31
33
32
- //TODO: FHL for PS
34
+ //TODO: FHL taks for PS
33
35
// Fixes (Order matters):
34
36
// 1. Singularize operationId operationIdSegments.
35
37
// 2. Add '_' to verb in an operationId.
@@ -50,9 +52,9 @@ public override void Visit(OpenApiSchema schema)
50
52
51
53
public override void Visit ( OpenApiPathItem pathItem )
52
54
{
53
- if ( pathItem . Operations . ContainsKey ( OperationType . Put ) )
55
+ if ( pathItem . Operations . TryGetValue ( OperationType . Put , out var value ) )
54
56
{
55
- var operationId = pathItem . Operations [ OperationType . Put ] . OperationId ;
57
+ var operationId = value . OperationId ;
56
58
pathItem . Operations [ OperationType . Put ] . OperationId = ResolvePutOperationId ( operationId ) ;
57
59
}
58
60
@@ -61,55 +63,38 @@ public override void Visit(OpenApiPathItem pathItem)
61
63
62
64
public override void Visit ( OpenApiOperation operation )
63
65
{
64
- if ( operation . OperationId == null )
66
+ if ( string . IsNullOrWhiteSpace ( operation . OperationId ) )
65
67
throw new ArgumentNullException ( nameof ( operation . OperationId ) , $ "OperationId is required { PathString } ") ;
66
68
67
69
var operationId = operation . OperationId ;
70
+ var operationTypeExtension = operation . Extensions . GetExtension ( "x-ms-docs-operation-type" ) ;
71
+ if ( operationTypeExtension . IsEquals ( "function" ) )
72
+ operation . Parameters = ResolveFunctionParameters ( operation . Parameters ) ;
68
73
74
+ // Order matters. Resolve operationId.
69
75
operationId = RemoveHashSuffix ( operationId ) ;
76
+ if ( operationTypeExtension . IsEquals ( "action" ) || operationTypeExtension . IsEquals ( "function" ) )
77
+ operationId = RemoveKeyTypeSegment ( operationId , operation . Parameters ) ;
78
+ operationId = SingularizeAndDeduplicateOperationId ( operationId . SplitByChar ( '.' ) ) ;
70
79
operationId = ResolveODataCastOperationId ( operationId ) ;
71
80
operationId = ResolveByRefOperationId ( operationId ) ;
72
-
73
-
74
- var operationIdSegments = operationId . Split ( new char [ ] { '.' } , StringSplitOptions . RemoveEmptyEntries ) . ToList ( ) ;
75
- operationId = SingularizeAndDeduplicateOperationId ( operationIdSegments ) ;
81
+ // Verb segment resolution should always be last. user.get -> user_Get
82
+ operationId = ResolveVerbSegmentInOpertationId ( operationId ) ;
76
83
77
84
operation . OperationId = operationId ;
78
85
base . Visit ( operation ) ;
79
86
}
80
87
81
- private void AddAddtionalPropertiesToSchema ( OpenApiSchema schema )
88
+ private static string ResolveVerbSegmentInOpertationId ( string operationId )
82
89
{
83
- if ( schema != null && ! _schemaLoop . Contains ( schema ) && "object" . Equals ( schema ? . Type , StringComparison . OrdinalIgnoreCase ) )
84
- {
85
- schema . AdditionalProperties = new OpenApiSchema ( ) { Type = "object" } ;
86
-
87
- /* Because 'additionalProperties' are now being walked,
88
- * we need a way to keep track of visited schemas to avoid
89
- * endlessly creating and walking them in an infinite recursion.
90
- */
91
- _schemaLoop . Push ( schema . AdditionalProperties ) ;
92
- }
93
- }
94
-
95
- private static void ResolveOneOfSchema ( OpenApiSchema schema )
96
- {
97
- if ( schema . OneOf ? . Any ( ) ?? false )
98
- {
99
- var newSchema = schema . OneOf . FirstOrDefault ( ) ;
100
- schema . OneOf = null ;
101
- FlattenSchema ( schema , newSchema ) ;
102
- }
103
- }
104
-
105
- private static void ResolveAnyOfSchema ( OpenApiSchema schema )
106
- {
107
- if ( schema . AnyOf ? . Any ( ) ?? false )
108
- {
109
- var newSchema = schema . AnyOf . FirstOrDefault ( ) ;
110
- schema . AnyOf = null ;
111
- FlattenSchema ( schema , newSchema ) ;
112
- }
90
+ var charPos = operationId . LastIndexOf ( '.' , operationId . Length - 1 ) ;
91
+ if ( operationId . Contains ( '_' ) || charPos < 0 )
92
+ return operationId ;
93
+ // TODO: Optimize this call.
94
+ var newOperationId = new StringBuilder ( operationId ) ;
95
+ newOperationId [ charPos ] = '_' ;
96
+ operationId = newOperationId . ToString ( ) ;
97
+ return operationId ;
113
98
}
114
99
115
100
private static string ResolvePutOperationId ( string operationId )
@@ -158,6 +143,79 @@ private static string RemoveHashSuffix(string operationId)
158
143
return s_hashSuffixRegex . Match ( operationId ) . Value ;
159
144
}
160
145
146
+ private static string RemoveKeyTypeSegment ( string operationId , IList < OpenApiParameter > parameters )
147
+ {
148
+ var segments = operationId . SplitByChar ( '.' ) ;
149
+ foreach ( var parameter in parameters )
150
+ {
151
+ var keyTypeExtension = parameter . Extensions . GetExtension ( "x-ms-docs-key-type" ) ;
152
+ if ( keyTypeExtension != null )
153
+ {
154
+ if ( operationId . Contains ( keyTypeExtension ) )
155
+ {
156
+ segments . Remove ( keyTypeExtension ) ;
157
+ }
158
+ }
159
+ }
160
+ return string . Join ( "." , segments ) ;
161
+ }
162
+
163
+ private static IList < OpenApiParameter > ResolveFunctionParameters ( IList < OpenApiParameter > parameters )
164
+ {
165
+ foreach ( var parameter in parameters )
166
+ {
167
+ if ( parameter . Content ? . Any ( ) ?? false )
168
+ {
169
+ // Replace content with a schema object of type array
170
+ // for structured or collection-valued function parameters
171
+ parameter . Content = null ;
172
+ parameter . Schema = new OpenApiSchema
173
+ {
174
+ Type = "array" ,
175
+ Items = new OpenApiSchema
176
+ {
177
+ Type = "string"
178
+ }
179
+ } ;
180
+ }
181
+ }
182
+ return parameters ;
183
+ }
184
+
185
+ private void AddAddtionalPropertiesToSchema ( OpenApiSchema schema )
186
+ {
187
+ if ( schema != null && ! _schemaLoop . Contains ( schema ) && "object" . Equals ( schema ? . Type , StringComparison . OrdinalIgnoreCase ) )
188
+ {
189
+ schema . AdditionalProperties = new OpenApiSchema ( ) { Type = "object" } ;
190
+
191
+ /* Because 'additionalProperties' are now being walked,
192
+ * we need a way to keep track of visited schemas to avoid
193
+ * endlessly creating and walking them in an infinite recursion.
194
+ */
195
+ _schemaLoop . Push ( schema . AdditionalProperties ) ;
196
+ }
197
+ }
198
+
199
+ private static void ResolveOneOfSchema ( OpenApiSchema schema )
200
+ {
201
+ if ( schema . OneOf ? . Any ( ) ?? false )
202
+ {
203
+ var newSchema = schema . OneOf . FirstOrDefault ( ) ;
204
+ schema . OneOf = null ;
205
+ FlattenSchema ( schema , newSchema ) ;
206
+ }
207
+ }
208
+
209
+ private static void ResolveAnyOfSchema ( OpenApiSchema schema )
210
+ {
211
+ if ( schema . AnyOf ? . Any ( ) ?? false )
212
+ {
213
+ var newSchema = schema . AnyOf . FirstOrDefault ( ) ;
214
+ schema . AnyOf = null ;
215
+ FlattenSchema ( schema , newSchema ) ;
216
+ }
217
+ }
218
+
161
219
private static void FlattenSchema ( OpenApiSchema schema , OpenApiSchema newSchema )
162
220
{
163
221
if ( newSchema != null )
0 commit comments