@@ -166,8 +166,43 @@ module.exports = class Operation {
166
166
}
167
167
168
168
async renderBodyParameterDescriptions ( ) {
169
- const bodyParamsObject = get ( this , 'requestBody.content.application/json.schema.properties' , { } )
170
- const requiredParams = get ( this , 'requestBody.content.application/json.schema.required' , [ ] )
169
+ let bodyParamsObject = get ( this , 'requestBody.content.application/json.schema.properties' , { } )
170
+ let requiredParams = get ( this , 'requestBody.content.application/json.schema.required' , [ ] )
171
+ const oneOfObject = get ( this , 'requestBody.content.application/json.schema.oneOf' , undefined )
172
+
173
+ // oneOf is an array of input parameter options, so we need to either
174
+ // use the first option or munge the options together.
175
+ if ( oneOfObject ) {
176
+ const firstOneOfObject = oneOfObject [ 0 ]
177
+ const allOneOfAreObjects = oneOfObject
178
+ . filter ( elem => elem . type === 'object' )
179
+ . length === oneOfObject . length
180
+
181
+ // TODO: Remove this check
182
+ // This operation shouldn't have a oneOf in this case, it needs to be
183
+ // removed from the schema in the github/github repo.
184
+ if ( this . operationId === 'checks/create' ) {
185
+ delete bodyParamsObject . oneOf
186
+ } else if ( allOneOfAreObjects ) {
187
+ // When all of the oneOf objects have the `type: object` we
188
+ // need to display all of the parameters.
189
+ // This merges all of the properties and required values into the
190
+ // first requestBody object.
191
+ for ( let i = 1 ; i < oneOfObject . length ; i ++ ) {
192
+ Object . assign ( firstOneOfObject . properties , oneOfObject [ i ] . properties )
193
+ requiredParams = firstOneOfObject . required
194
+ . concat ( oneOfObject [ i ] . required )
195
+ }
196
+ bodyParamsObject = firstOneOfObject . properties
197
+ } else if ( oneOfObject ) {
198
+ // When a oneOf exists but the `type` differs, the case has historically
199
+ // been that the alternate option is an array, where the first option
200
+ // is the array as a property of the object. We need to ensure that the
201
+ // first option listed is the most comprehensive and preferred option.
202
+ bodyParamsObject = firstOneOfObject . properties
203
+ requiredParams = firstOneOfObject . required
204
+ }
205
+ }
171
206
172
207
this . bodyParameters = await getBodyParams ( bodyParamsObject , requiredParams )
173
208
}
@@ -211,16 +246,57 @@ async function getBodyParams (paramsObject, requiredParams) {
211
246
param . rawType = param . type
212
247
param . rawDescription = param . description
213
248
214
- // e.g. array of strings
215
- param . type = param . type === 'array'
216
- ? `array of ${ param . items . type } s`
217
- : param . type
249
+ // Stores the types listed under the `Type` column in the `Parameters`
250
+ // table in the REST API docs. When the parameter contains oneOf
251
+ // there are multiple acceptable parameters that we should list.
252
+ const paramArray = [ ]
253
+
254
+ const oneOfArray = param . oneOf
255
+ const isOneOfObjectOrArray = oneOfArray
256
+ ? oneOfArray . filter ( elem => elem . type !== 'object' || elem . type !== 'array' )
257
+ : false
258
+
259
+ // When oneOf has the type array or object, the type is defined
260
+ // in a child object
261
+ if ( oneOfArray && isOneOfObjectOrArray . length > 0 ) {
262
+ // Store the defined types
263
+ paramArray . push ( oneOfArray
264
+ . filter ( elem => elem . type )
265
+ . map ( elem => elem . type )
266
+ )
267
+
268
+ // If an object doesn't have a description, it is invalid
269
+ const oneOfArrayWithDescription = oneOfArray . filter ( elem => elem . description )
270
+
271
+ // Use the parent description when set, otherwise enumerate each
272
+ // description in the `Description` column of the `Parameters` table.
273
+ if ( ! param . description && oneOfArrayWithDescription . length > 1 ) {
274
+ param . description = oneOfArray
275
+ . filter ( elem => elem . description )
276
+ . map ( elem => `**Type ${ elem . type } ** - ${ elem . description } ` )
277
+ . join ( '\n\n' )
278
+ } else if ( ! param . description && oneOfArrayWithDescription . length === 1 ) {
279
+ // When there is only on valid description, use that one.
280
+ param . description = oneOfArrayWithDescription [ 0 ] . description
281
+ }
282
+ }
283
+
284
+ // Arrays require modifying the displayed type (e.g., array of strings)
285
+ if ( param . type === 'array' ) {
286
+ if ( param . items . type ) paramArray . push ( `array of ${ param . items . type } s` )
287
+ if ( param . items . oneOf ) {
288
+ paramArray . push ( param . items . oneOf
289
+ . map ( elem => `array of ${ elem . type } s` )
290
+ )
291
+ }
292
+ } else if ( param . type ) {
293
+ paramArray . push ( param . type )
294
+ }
218
295
219
- // e.g. object or null
220
- param . type = param . nullable
221
- ? `${ param . type } or null`
222
- : param . type
296
+ if ( param . nullable ) paramArray . push ( 'nullable' )
223
297
298
+ param . type = paramArray . flat ( ) . join ( ' or ' )
299
+ param . description = param . description || ''
224
300
const isRequired = requiredParams && requiredParams . includes ( param . name )
225
301
const requiredString = isRequired ? '**Required**. ' : ''
226
302
param . description = await renderContent ( requiredString + param . description )
@@ -245,8 +321,9 @@ async function getBodyParams (paramsObject, requiredParams) {
245
321
}
246
322
247
323
async function getChildParamsGroup ( param ) {
248
- // only objects and arrays of objects ever have child params
249
- if ( ! ( param . rawType === 'array' || param . rawType === 'object' ) ) return
324
+ // only objects, arrays of objects, anyOf, allOf, and oneOf have child params
325
+ if ( ! ( param . rawType === 'array' || param . rawType === 'object' || param . oneOf ) ) return
326
+ if ( param . oneOf && ! param . oneOf . filter ( param => param . type === 'object' || param . type === 'array' ) ) return
250
327
if ( param . items && param . items . type !== 'object' ) return
251
328
252
329
const childParamsObject = param . rawType === 'array' ? param . items . properties : param . properties
0 commit comments