@@ -184,6 +184,68 @@ function createDiscriminatorEnum(
184
184
} ;
185
185
}
186
186
187
+ /** Adds or replaces the discriminator enum with the passed `values` in a schema defined by `ref` */
188
+ function patchDiscriminatorEnum (
189
+ schema : SchemaObject ,
190
+ ref : string ,
191
+ values : string [ ] ,
192
+ discriminator : DiscriminatorObject ,
193
+ discriminatorRef : string ,
194
+ options : OpenAPITSOptions ,
195
+ ) : boolean {
196
+ const resolvedSchema = resolveRef < SchemaObject > ( schema , ref , {
197
+ silent : options . silent ?? false ,
198
+ } ) ;
199
+
200
+ if ( resolvedSchema ?. allOf ) {
201
+ // if the schema is an allOf, we can append a new schema object to the allOf array
202
+ resolvedSchema . allOf . push ( {
203
+ type : "object" ,
204
+ // discriminator enum properties always need to be required
205
+ required : [ discriminator . propertyName ] ,
206
+ properties : {
207
+ [ discriminator . propertyName ] : createDiscriminatorEnum ( values ) ,
208
+ } ,
209
+ } ) ;
210
+
211
+ return true ;
212
+ } else if (
213
+ typeof resolvedSchema === "object" &&
214
+ "type" in resolvedSchema &&
215
+ resolvedSchema . type === "object"
216
+ ) {
217
+ // if the schema is an object, we can apply the discriminator enums to its properties
218
+ if ( ! resolvedSchema . properties ) {
219
+ resolvedSchema . properties = { } ;
220
+ }
221
+
222
+ // discriminator enum properties always need to be required
223
+ if ( ! resolvedSchema . required ) {
224
+ resolvedSchema . required = [ discriminator . propertyName ] ;
225
+ } else if ( ! resolvedSchema . required . includes ( discriminator . propertyName ) ) {
226
+ resolvedSchema . required . push ( discriminator . propertyName ) ;
227
+ }
228
+
229
+ // add/replace the discriminator enum property
230
+ resolvedSchema . properties [ discriminator . propertyName ] =
231
+ createDiscriminatorEnum (
232
+ values ,
233
+ resolvedSchema . properties [ discriminator . propertyName ] ,
234
+ ) ;
235
+
236
+ return true ;
237
+ }
238
+
239
+ warn (
240
+ `Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): ${ ref } => ${ values . join (
241
+ ", " ,
242
+ ) } (Discriminator: ${ discriminatorRef } )`,
243
+ options . silent ,
244
+ ) ;
245
+
246
+ return false ;
247
+ }
248
+
187
249
type InternalDiscriminatorMapping = Record <
188
250
string ,
189
251
{ inferred ?: string ; defined ?: string [ ] }
@@ -267,57 +329,18 @@ export function scanDiscriminators(
267
329
// the inferred enum values from the schema might not represent the actual enum values of the discriminator,
268
330
// so if we have defined values, use them instead
269
331
const mappedValues = defined ?? [ inferred ! ] ;
270
- const resolvedSchema = resolveRef < SchemaObject > ( schema , mappedRef , {
271
- silent : options . silent ?? false ,
272
- } ) ;
273
-
274
- if ( resolvedSchema ?. allOf ) {
275
- // if the schema is an allOf, we can append a new schema object to the allOf array
276
- resolvedSchema . allOf . push ( {
277
- type : "object" ,
278
- // discriminator enum properties always need to be required
279
- required : [ discriminator . propertyName ] ,
280
- properties : {
281
- [ discriminator . propertyName ] : createDiscriminatorEnum ( mappedValues ) ,
282
- } ,
283
- } ) ;
284
332
285
- refsHandled . push ( mappedRef ) ;
286
- } else if (
287
- typeof resolvedSchema === "object" &&
288
- "type" in resolvedSchema &&
289
- resolvedSchema . type === "object"
333
+ if (
334
+ patchDiscriminatorEnum (
335
+ schema ,
336
+ mappedRef ,
337
+ mappedValues ,
338
+ discriminator ,
339
+ ref ,
340
+ options ,
341
+ )
290
342
) {
291
- // if the schema is an object, we can apply the discriminator enums to its properties
292
- if ( ! resolvedSchema . properties ) {
293
- resolvedSchema . properties = { } ;
294
- }
295
-
296
- // discriminator enum properties always need to be required
297
- if ( ! resolvedSchema . required ) {
298
- resolvedSchema . required = [ discriminator . propertyName ] ;
299
- } else if (
300
- ! resolvedSchema . required . includes ( discriminator . propertyName )
301
- ) {
302
- resolvedSchema . required . push ( discriminator . propertyName ) ;
303
- }
304
-
305
- // add/replace the discriminator enum property
306
- resolvedSchema . properties [ discriminator . propertyName ] =
307
- createDiscriminatorEnum (
308
- mappedValues ,
309
- resolvedSchema . properties [ discriminator . propertyName ] ,
310
- ) ;
311
-
312
343
refsHandled . push ( mappedRef ) ;
313
- } else {
314
- warn (
315
- `Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): ${ mappedRef } => ${ mappedValues . join (
316
- ", " ,
317
- ) } (Discriminator: ${ ref } )`,
318
- options . silent ,
319
- ) ;
320
- continue ;
321
344
}
322
345
}
323
346
} ) ;
@@ -326,19 +349,48 @@ export function scanDiscriminators(
326
349
// (sometimes this mapping is implicit, so it can’t be done until we know
327
350
// about every discriminator in the document)
328
351
walk ( schema , ( obj , path ) => {
329
- for ( const key of [ "oneOf" , "anyOf" , "allOf" ] as const ) {
330
- if ( obj && Array . isArray ( obj [ key ] ) ) {
331
- for ( const item of ( obj as any ) [ key ] ) {
332
- if ( "$ref" in item ) {
333
- if ( objects [ item . $ref ] ) {
334
- objects [ createRef ( path ) ] = {
335
- ...objects [ item . $ref ] ,
336
- } ;
352
+ if ( ! obj || ! Array . isArray ( obj . allOf ) ) {
353
+ return ;
354
+ }
355
+
356
+ for ( const item of ( obj as any ) . allOf ) {
357
+ if ( "$ref" in item ) {
358
+ if ( ! objects [ item . $ref ] ) {
359
+ return ;
360
+ }
361
+
362
+ const ref = createRef ( path ) ;
363
+ const discriminator = objects [ item . $ref ] ;
364
+ const mappedValues : string [ ] = [ ] ;
365
+
366
+ if ( discriminator . mapping ) {
367
+ for ( const mappedValue in discriminator . mapping ) {
368
+ if ( discriminator . mapping [ mappedValue ] === ref ) {
369
+ mappedValues . push ( mappedValue ) ;
370
+ }
371
+ }
372
+
373
+ if ( mappedValues . length > 0 ) {
374
+ if (
375
+ patchDiscriminatorEnum (
376
+ schema ,
377
+ ref ,
378
+ mappedValues ,
379
+ discriminator ,
380
+ item . $ref ,
381
+ options ,
382
+ )
383
+ ) {
384
+ refsHandled . push ( ref ) ;
337
385
}
338
- } else if ( item . discriminator ?. propertyName ) {
339
- objects [ createRef ( path ) ] = { ...item . discriminator } ;
340
386
}
341
387
}
388
+
389
+ objects [ ref ] = {
390
+ ...objects [ item . $ref ] ,
391
+ } ;
392
+ } else if ( item . discriminator ?. propertyName ) {
393
+ objects [ createRef ( path ) ] = { ...item . discriminator } ;
342
394
}
343
395
}
344
396
} ) ;
0 commit comments