@kubb/plugin-oas 3.10.2 → 3.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/{OperationGenerator-DiF6WJNP.d.cts → OperationGenerator-BrnQyed_.d.cts} +9 -1
  2. package/dist/{OperationGenerator-DiF6WJNP.d.ts → OperationGenerator-BrnQyed_.d.ts} +9 -1
  3. package/dist/Schema-DTc2F3jG.d.cts +32 -0
  4. package/dist/Schema-Dhz38Get.d.ts +32 -0
  5. package/dist/{chunk-72MVTXCW.js → chunk-5JWN6NVC.js} +245 -133
  6. package/dist/chunk-5JWN6NVC.js.map +1 -0
  7. package/dist/{chunk-DUZZHEQI.cjs → chunk-ES7R7N34.cjs} +6 -6
  8. package/dist/chunk-ES7R7N34.cjs.map +1 -0
  9. package/dist/{chunk-BAU7PO7T.js → chunk-JNN4JPWK.js} +4 -4
  10. package/dist/chunk-JNN4JPWK.js.map +1 -0
  11. package/dist/{chunk-3Y4QGY6D.js → chunk-PORSNYI5.js} +3 -3
  12. package/dist/chunk-PORSNYI5.js.map +1 -0
  13. package/dist/{chunk-Q4HTTWL7.cjs → chunk-PSWNN6SJ.cjs} +245 -133
  14. package/dist/chunk-PSWNN6SJ.cjs.map +1 -0
  15. package/dist/{chunk-DN373TFU.js → chunk-RNF2QJEG.js} +4 -4
  16. package/dist/chunk-RNF2QJEG.js.map +1 -0
  17. package/dist/{chunk-KXB5DUFD.cjs → chunk-Z2NREI4X.cjs} +4 -4
  18. package/dist/chunk-Z2NREI4X.cjs.map +1 -0
  19. package/dist/{chunk-B7KP5ZFA.cjs → chunk-ZVFL3NXX.cjs} +3 -3
  20. package/dist/chunk-ZVFL3NXX.cjs.map +1 -0
  21. package/dist/components.cjs +4 -4
  22. package/dist/components.d.cts +2 -2
  23. package/dist/components.d.ts +2 -2
  24. package/dist/components.js +1 -1
  25. package/dist/generators.cjs +4 -4
  26. package/dist/generators.d.cts +1 -1
  27. package/dist/generators.d.ts +1 -1
  28. package/dist/generators.js +3 -3
  29. package/dist/hooks.cjs +9 -9
  30. package/dist/hooks.d.cts +2 -2
  31. package/dist/hooks.d.ts +2 -2
  32. package/dist/hooks.js +3 -3
  33. package/dist/index.cjs +11 -11
  34. package/dist/index.d.cts +2 -2
  35. package/dist/index.d.ts +2 -2
  36. package/dist/index.js +6 -6
  37. package/dist/utils.cjs +3 -3
  38. package/dist/utils.d.cts +10 -3
  39. package/dist/utils.d.ts +10 -3
  40. package/dist/utils.js +1 -1
  41. package/package.json +7 -7
  42. package/src/SchemaGenerator.ts +271 -132
  43. package/src/SchemaMapper.ts +1 -0
  44. package/src/components/Schema.tsx +13 -4
  45. package/src/generator.tsx +8 -1
  46. package/src/utils/getSchemaFactory.ts +10 -3
  47. package/dist/Schema-BbIxCfn7.d.ts +0 -23
  48. package/dist/Schema-Ds5f4y7m.d.cts +0 -23
  49. package/dist/chunk-3Y4QGY6D.js.map +0 -1
  50. package/dist/chunk-72MVTXCW.js.map +0 -1
  51. package/dist/chunk-B7KP5ZFA.cjs.map +0 -1
  52. package/dist/chunk-BAU7PO7T.js.map +0 -1
  53. package/dist/chunk-DN373TFU.js.map +0 -1
  54. package/dist/chunk-DUZZHEQI.cjs.map +0 -1
  55. package/dist/chunk-KXB5DUFD.cjs.map +0 -1
  56. package/dist/chunk-Q4HTTWL7.cjs.map +0 -1
@@ -2,7 +2,7 @@ import { BaseGenerator, type FileMetaBase } from '@kubb/core'
2
2
  import transformers, { pascalCase } from '@kubb/core/transformers'
3
3
  import { getUniqueName } from '@kubb/core/utils'
4
4
 
5
- import { isNullable, isReference } from '@kubb/oas'
5
+ import { isDiscriminator, isNullable, isReference } from '@kubb/oas'
6
6
  import { isDeepEqual, isNumber, uniqueWith } from 'remeda'
7
7
  import { isKeyword, schemaKeywords } from './SchemaMapper.ts'
8
8
  import { getSchemaFactory } from './utils/getSchemaFactory.ts'
@@ -59,7 +59,7 @@ export type SchemaGeneratorOptions = {
59
59
  export type SchemaGeneratorBuildOptions = Omit<OperationSchema, 'name' | 'schema'>
60
60
 
61
61
  type SchemaProps = {
62
- schema?: SchemaObject
62
+ schemaObject?: SchemaObject
63
63
  name?: string
64
64
  parentName?: string
65
65
  }
@@ -250,10 +250,10 @@ export class SchemaGenerator<
250
250
  /**
251
251
  * Recursively creates a type literal with the given props.
252
252
  */
253
- #parseProperties({ schema, name }: SchemaProps): Schema[] {
254
- const properties = schema?.properties || {}
255
- const additionalProperties = schema?.additionalProperties
256
- const required = schema?.required
253
+ #parseProperties({ schemaObject, name }: SchemaProps): Schema[] {
254
+ const properties = schemaObject?.properties || {}
255
+ const additionalProperties = schemaObject?.additionalProperties
256
+ const required = schemaObject?.required
257
257
 
258
258
  const propertiesSchemas = Object.keys(properties)
259
259
  .map((propertyName) => {
@@ -263,7 +263,7 @@ export class SchemaGenerator<
263
263
  const isRequired = Array.isArray(required) ? required?.includes(propertyName) : !!required
264
264
  const nullable = propertySchema.nullable ?? propertySchema['x-nullable'] ?? false
265
265
 
266
- validationFunctions.push(...this.parse({ schema: propertySchema, name: propertyName, parentName: name }))
266
+ validationFunctions.push(...this.parse({ schemaObject: propertySchema, name: propertyName, parentName: name }))
267
267
 
268
268
  validationFunctions.push({
269
269
  keyword: schemaKeywords.name,
@@ -286,8 +286,8 @@ export class SchemaGenerator<
286
286
  if (additionalProperties) {
287
287
  additionalPropertiesSchemas =
288
288
  additionalProperties === true || !Object.keys(additionalProperties).length
289
- ? [{ keyword: this.#getUnknownReturn({ schema, name }) }]
290
- : this.parse({ schema: additionalProperties as SchemaObject, parentName: name })
289
+ ? [{ keyword: this.#getUnknownReturn({ schemaObject, name }) }]
290
+ : this.parse({ schemaObject: additionalProperties as SchemaObject, parentName: name })
291
291
  }
292
292
 
293
293
  return [
@@ -304,26 +304,64 @@ export class SchemaGenerator<
304
304
  /**
305
305
  * Create a type alias for the schema referenced by the given ReferenceObject
306
306
  */
307
- #getRefAlias(obj: OpenAPIV3.ReferenceObject): Schema[] {
308
- const { $ref } = obj
309
- let ref = this.refs[$ref]
310
-
311
- const originalName = getUniqueName($ref.replace(/.+\//, ''), this.#usedAliasNames)
312
- const propertyName = this.context.pluginManager.resolveName({
313
- name: originalName,
314
- pluginKey: this.context.plugin.key,
315
- type: 'function',
316
- })
307
+ #getRefAlias(schemaObject: OpenAPIV3.ReferenceObject, name: string | undefined): Schema[] {
308
+ const { $ref } = schemaObject
309
+ const ref = this.refs[$ref]
317
310
 
318
311
  if (ref) {
312
+ const dereferencedSchema = this.context.oas.dereferenceWithRef(schemaObject)
313
+ // pass name to getRefAlias and use that to find in discriminator.mapping value
314
+
315
+ if (dereferencedSchema && isDiscriminator(dereferencedSchema)) {
316
+ const [key] = Object.entries(dereferencedSchema.discriminator.mapping || {}).find(([_key, value]) => value.replace(/.+\//, '') === name) || []
317
+
318
+ if (key) {
319
+ return [
320
+ {
321
+ keyword: schemaKeywords.and,
322
+ args: [
323
+ {
324
+ keyword: schemaKeywords.ref,
325
+ args: { name: ref.propertyName, $ref, path: ref.path, isImportable: !!this.context.oas.get($ref) },
326
+ },
327
+ {
328
+ keyword: schemaKeywords.object,
329
+ args: {
330
+ properties: {
331
+ [dereferencedSchema.discriminator.propertyName]: [
332
+ {
333
+ keyword: schemaKeywords.const,
334
+ args: {
335
+ name: key,
336
+ format: 'string',
337
+ value: key,
338
+ },
339
+ },
340
+ ],
341
+ },
342
+ },
343
+ },
344
+ ],
345
+ },
346
+ ] as Schema[]
347
+ }
348
+ }
349
+
319
350
  return [
320
351
  {
321
352
  keyword: schemaKeywords.ref,
322
- args: { name: ref.propertyName, path: ref.path, isImportable: !!this.context.oas.get($ref) },
353
+ args: { name: ref.propertyName, $ref, path: ref.path, isImportable: !!this.context.oas.get($ref) },
323
354
  },
324
355
  ]
325
356
  }
326
357
 
358
+ const originalName = getUniqueName($ref.replace(/.+\//, ''), this.#usedAliasNames)
359
+ const propertyName = this.context.pluginManager.resolveName({
360
+ name: originalName,
361
+ pluginKey: this.context.plugin.key,
362
+ type: 'function',
363
+ })
364
+
327
365
  const fileName = this.context.pluginManager.resolveName({
328
366
  name: originalName,
329
367
  pluginKey: this.context.plugin.key,
@@ -335,34 +373,86 @@ export class SchemaGenerator<
335
373
  extname: '.ts',
336
374
  })
337
375
 
338
- ref = this.refs[$ref] = {
376
+ this.refs[$ref] = {
339
377
  propertyName,
340
378
  originalName,
341
379
  path: file.path,
342
380
  }
343
381
 
344
- return [
345
- {
346
- keyword: schemaKeywords.ref,
347
- args: { name: ref.propertyName, path: ref?.path, isImportable: !!this.context.oas.get($ref) },
348
- },
349
- ]
382
+ return this.#getRefAlias(schemaObject, name)
350
383
  }
351
384
 
352
385
  #getParsedSchemaObject(schema?: SchemaObject) {
353
- const parsedSchema = getSchemaFactory(this.context.oas)(schema)
354
- return parsedSchema
386
+ return getSchemaFactory(this.context.oas)(schema)
387
+ }
388
+
389
+ #addDiscriminatorToSchema<TSchema extends Schema>({
390
+ schema,
391
+ schemaObject,
392
+ discriminator,
393
+ }: { schemaObject: SchemaObject; schema: TSchema; discriminator: OpenAPIV3.DiscriminatorObject }): TSchema {
394
+ if (!isKeyword(schema, schemaKeywords.union)) {
395
+ return schema
396
+ }
397
+
398
+ const objectPropertySchema = SchemaGenerator.find(this.parse({ schemaObject: schemaObject }), schemaKeywords.object)
399
+
400
+ return {
401
+ ...schema,
402
+ args: schema.args.map((arg) => {
403
+ const isRef = isKeyword(arg, schemaKeywords.ref)
404
+
405
+ if (isRef) {
406
+ const [key] = Object.entries(discriminator.mapping || {}).find(([_key, value]) => value === arg.args.$ref) || []
407
+
408
+ if (!key) {
409
+ throw new Error(`Can not find a key in discriminator ${JSON.stringify(schema)}`)
410
+ }
411
+
412
+ return {
413
+ keyword: schemaKeywords.and,
414
+ args: [
415
+ arg,
416
+ {
417
+ keyword: schemaKeywords.object,
418
+ args: {
419
+ properties: {
420
+ ...(objectPropertySchema?.args?.properties || {}),
421
+ [discriminator.propertyName]: [
422
+ {
423
+ keyword: schemaKeywords.const,
424
+ args: {
425
+ name: key,
426
+ format: 'string',
427
+ value: key,
428
+ },
429
+ },
430
+ //enum and literal will conflict
431
+ ...(objectPropertySchema?.args?.properties[discriminator.propertyName] || []),
432
+ ].filter((item) => !isKeyword(item, schemaKeywords.enum)),
433
+ },
434
+ },
435
+ },
436
+ ],
437
+ }
438
+ }
439
+
440
+ return arg
441
+ }),
442
+ }
355
443
  }
356
444
 
357
445
  /**
358
446
  * This is the very core of the OpenAPI to TS conversion - it takes a
359
447
  * schema and returns the appropriate type.
360
448
  */
361
- #parseSchemaObject({ schema: _schema, name, parentName }: SchemaProps): Schema[] {
362
- const options = this.#getOptions({ schema: _schema, name })
363
- const unknownReturn = this.#getUnknownReturn({ schema: _schema, name })
364
- const { schema, version } = this.#getParsedSchemaObject(_schema)
365
- if (!schema) {
449
+ #parseSchemaObject({ schemaObject: _schemaObject, name, parentName }: SchemaProps): Schema[] {
450
+ const { schemaObject, version } = this.#getParsedSchemaObject(_schemaObject)
451
+
452
+ const options = this.#getOptions({ schemaObject, name })
453
+ const unknownReturn = this.#getUnknownReturn({ schemaObject, name })
454
+
455
+ if (!schemaObject) {
366
456
  return [{ keyword: unknownReturn }]
367
457
  }
368
458
 
@@ -370,45 +460,45 @@ export class SchemaGenerator<
370
460
  {
371
461
  keyword: schemaKeywords.schema,
372
462
  args: {
373
- type: schema.type as any,
374
- format: schema.format,
463
+ type: schemaObject.type as any,
464
+ format: schemaObject.format,
375
465
  },
376
466
  },
377
467
  ]
378
- const min = schema.minimum ?? schema.minLength ?? schema.minItems ?? undefined
379
- const max = schema.maximum ?? schema.maxLength ?? schema.maxItems ?? undefined
380
- const nullable = isNullable(schema)
381
- const defaultNullAndNullable = schema.default === null && nullable
468
+ const min = schemaObject.minimum ?? schemaObject.minLength ?? schemaObject.minItems ?? undefined
469
+ const max = schemaObject.maximum ?? schemaObject.maxLength ?? schemaObject.maxItems ?? undefined
470
+ const nullable = isNullable(schemaObject)
471
+ const defaultNullAndNullable = schemaObject.default === null && nullable
382
472
 
383
- if (schema.default !== undefined && !defaultNullAndNullable && !Array.isArray(schema.default)) {
384
- if (typeof schema.default === 'string') {
473
+ if (schemaObject.default !== undefined && !defaultNullAndNullable && !Array.isArray(schemaObject.default)) {
474
+ if (typeof schemaObject.default === 'string') {
385
475
  baseItems.push({
386
476
  keyword: schemaKeywords.default,
387
- args: transformers.stringify(schema.default),
477
+ args: transformers.stringify(schemaObject.default),
388
478
  })
389
- } else if (typeof schema.default === 'boolean') {
479
+ } else if (typeof schemaObject.default === 'boolean') {
390
480
  baseItems.push({
391
481
  keyword: schemaKeywords.default,
392
- args: schema.default ?? false,
482
+ args: schemaObject.default ?? false,
393
483
  })
394
484
  } else {
395
485
  baseItems.push({
396
486
  keyword: schemaKeywords.default,
397
- args: schema.default,
487
+ args: schemaObject.default,
398
488
  })
399
489
  }
400
490
  }
401
491
 
402
- if (schema.deprecated) {
492
+ if (schemaObject.deprecated) {
403
493
  baseItems.push({
404
494
  keyword: schemaKeywords.deprecated,
405
495
  })
406
496
  }
407
497
 
408
- if (schema.description) {
498
+ if (schemaObject.description) {
409
499
  baseItems.push({
410
500
  keyword: schemaKeywords.describe,
411
- args: schema.description,
501
+ args: schemaObject.description,
412
502
  })
413
503
  }
414
504
 
@@ -424,59 +514,65 @@ export class SchemaGenerator<
424
514
  baseItems.push({ keyword: schemaKeywords.nullable })
425
515
  }
426
516
 
427
- if (schema.type && Array.isArray(schema.type)) {
428
- const [_schema, nullable] = schema.type
517
+ if (schemaObject.type && Array.isArray(schemaObject.type)) {
518
+ const [_schema, nullable] = schemaObject.type
429
519
 
430
520
  if (nullable === 'null') {
431
521
  baseItems.push({ keyword: schemaKeywords.nullable })
432
522
  }
433
523
  }
434
524
 
435
- if (schema.readOnly) {
525
+ if (schemaObject.readOnly) {
436
526
  baseItems.push({ keyword: schemaKeywords.readOnly })
437
527
  }
438
528
 
439
- if (schema.writeOnly) {
529
+ if (schemaObject.writeOnly) {
440
530
  baseItems.push({ keyword: schemaKeywords.writeOnly })
441
531
  }
442
532
 
443
- if (isReference(schema)) {
533
+ if (isReference(schemaObject)) {
444
534
  return [
445
- ...this.#getRefAlias(schema),
446
- schema.description && {
535
+ ...this.#getRefAlias(schemaObject, name),
536
+ schemaObject.description && {
447
537
  keyword: schemaKeywords.describe,
448
- args: schema.description,
538
+ args: schemaObject.description,
449
539
  },
450
540
  nullable && { keyword: schemaKeywords.nullable },
451
- schema.readOnly && { keyword: schemaKeywords.readOnly },
452
- schema.writeOnly && { keyword: schemaKeywords.writeOnly },
541
+ schemaObject.readOnly && { keyword: schemaKeywords.readOnly },
542
+ schemaObject.writeOnly && { keyword: schemaKeywords.writeOnly },
453
543
  {
454
544
  keyword: schemaKeywords.schema,
455
545
  args: {
456
- type: schema.type as any,
457
- format: schema.format,
546
+ type: schemaObject.type as any,
547
+ format: schemaObject.format,
458
548
  },
459
549
  },
460
550
  ].filter(Boolean)
461
551
  }
462
552
 
463
- if (schema.oneOf) {
553
+ if (schemaObject.oneOf) {
464
554
  // union
465
- const schemaWithoutOneOf = { ...schema, oneOf: undefined }
555
+ const schemaWithoutOneOf = { ...schemaObject, oneOf: undefined }
466
556
 
467
- const union: Schema = {
557
+ const union: SchemaKeywordMapper['union'] = {
468
558
  keyword: schemaKeywords.union,
469
- args: schema.oneOf
559
+ args: schemaObject.oneOf
470
560
  .map((item) => {
471
- return item && this.parse({ schema: item as SchemaObject, name, parentName })[0]
561
+ // first item, this will be ref
562
+ return item && this.parse({ schemaObject: item as SchemaObject, name, parentName })[0]
472
563
  })
473
564
  .filter(Boolean)
474
- .filter((item) => {
475
- return item && item.keyword !== unknownReturn
476
- }),
565
+ .filter((item) => !isKeyword(item, schemaKeywords.unknown)),
477
566
  }
567
+
568
+ const discriminator = this.context.oas.getDiscriminator(schemaObject)
569
+
570
+ if (discriminator) {
571
+ return [this.#addDiscriminatorToSchema({ schemaObject: schemaWithoutOneOf, schema: union, discriminator }), ...baseItems]
572
+ }
573
+
478
574
  if (schemaWithoutOneOf.properties) {
479
- const propertySchemas = this.parse({ schema: schemaWithoutOneOf, name, parentName })
575
+ const propertySchemas = this.parse({ schemaObject: schemaWithoutOneOf, name, parentName })
480
576
 
481
577
  union.args = [
482
578
  ...union.args.map((arg) => {
@@ -486,25 +582,26 @@ export class SchemaGenerator<
486
582
  }
487
583
  }),
488
584
  ]
585
+
586
+ return [union, ...baseItems]
489
587
  }
490
588
 
491
589
  return [union, ...baseItems]
492
590
  }
493
591
 
494
- if (schema.anyOf) {
592
+ if (schemaObject.anyOf) {
495
593
  // union
496
- const schemaWithoutAnyOf = { ...schema, anyOf: undefined }
594
+ const schemaWithoutAnyOf = { ...schemaObject, anyOf: undefined }
497
595
 
498
- const union: Schema = {
596
+ const union: SchemaKeywordMapper['union'] = {
499
597
  keyword: schemaKeywords.union,
500
- args: schema.anyOf
598
+ args: schemaObject.anyOf
501
599
  .map((item) => {
502
- return item && this.parse({ schema: item as SchemaObject, name, parentName })[0]
600
+ // first item, this will be ref
601
+ return item && this.parse({ schemaObject: item as SchemaObject, name, parentName })[0]
503
602
  })
504
603
  .filter(Boolean)
505
- .filter((item) => {
506
- return item && item.keyword !== unknownReturn
507
- })
604
+ .filter((item) => !isKeyword(item, schemaKeywords.unknown))
508
605
  .map((item) => {
509
606
  if (isKeyword(item, schemaKeywords.object)) {
510
607
  return {
@@ -518,31 +615,47 @@ export class SchemaGenerator<
518
615
  return item
519
616
  }),
520
617
  }
618
+
619
+ const discriminator = this.context.oas.getDiscriminator(schemaObject)
620
+
621
+ if (discriminator) {
622
+ return [this.#addDiscriminatorToSchema({ schemaObject: schemaWithoutAnyOf, schema: union, discriminator }), ...baseItems]
623
+ }
624
+
521
625
  if (schemaWithoutAnyOf.properties) {
522
- return [...this.parse({ schema: schemaWithoutAnyOf, name, parentName }), union, ...baseItems]
626
+ const propertySchemas = this.parse({ schemaObject: schemaWithoutAnyOf, name, parentName })
627
+
628
+ union.args = [
629
+ ...union.args.map((arg) => {
630
+ return {
631
+ keyword: schemaKeywords.and,
632
+ args: [arg, ...propertySchemas],
633
+ }
634
+ }),
635
+ ]
636
+
637
+ return [union, ...baseItems]
523
638
  }
524
639
 
525
640
  return [union, ...baseItems]
526
641
  }
527
- if (schema.allOf) {
642
+ if (schemaObject.allOf) {
528
643
  // intersection/add
529
- const schemaWithoutAllOf = { ...schema, allOf: undefined }
644
+ const schemaWithoutAllOf = { ...schemaObject, allOf: undefined }
530
645
 
531
646
  const and: Schema = {
532
647
  keyword: schemaKeywords.and,
533
- args: schema.allOf
648
+ args: schemaObject.allOf
534
649
  .map((item) => {
535
- return item && this.parse({ schema: item as SchemaObject, name, parentName })[0]
650
+ return item && this.parse({ schemaObject: item as SchemaObject, name, parentName })[0]
536
651
  })
537
652
  .filter(Boolean)
538
- .filter((item) => {
539
- return item && item.keyword !== unknownReturn
540
- }),
653
+ .filter((item) => !isKeyword(item, schemaKeywords.unknown)),
541
654
  }
542
655
 
543
656
  if (schemaWithoutAllOf.required) {
544
657
  // TODO use of Required ts helper instead
545
- const schemas = schema.allOf
658
+ const schemas = schemaObject.allOf
546
659
  .map((item) => {
547
660
  if (isReference(item)) {
548
661
  return this.context.oas.get(item.$ref) as SchemaObject
@@ -575,37 +688,37 @@ export class SchemaGenerator<
575
688
  })
576
689
  .filter(Boolean)
577
690
 
578
- and.args = [...(and.args || []), ...items.flatMap((item) => this.parse({ schema: item as SchemaObject, name, parentName }))]
691
+ and.args = [...(and.args || []), ...items.flatMap((item) => this.parse({ schemaObject: item as SchemaObject, name, parentName }))]
579
692
  }
580
693
 
581
694
  if (schemaWithoutAllOf.properties) {
582
- and.args = [...(and.args || []), ...this.parse({ schema: schemaWithoutAllOf, name, parentName })]
695
+ and.args = [...(and.args || []), ...this.parse({ schemaObject: schemaWithoutAllOf, name, parentName })]
583
696
  }
584
697
 
585
698
  return [and, ...baseItems]
586
699
  }
587
700
 
588
- if (schema.enum) {
701
+ if (schemaObject.enum) {
589
702
  if (options.enumSuffix === '') {
590
- throw new Error('EnumSuffix set to an empty string does not work')
703
+ this.context.pluginManager.logger.emit('info', 'EnumSuffix set to an empty string does not work')
591
704
  }
592
705
 
593
- const enumName = getUniqueName(pascalCase([parentName, name, options.enumSuffix].join(' ')), this.#getUsedEnumNames({ schema, name }))
706
+ const enumName = getUniqueName(pascalCase([parentName, name, options.enumSuffix].join(' ')), this.#getUsedEnumNames({ schemaObject, name }))
594
707
  const typeName = this.context.pluginManager.resolveName({
595
708
  name: enumName,
596
709
  pluginKey: this.context.plugin.key,
597
710
  type: 'type',
598
711
  })
599
712
 
600
- const nullableEnum = schema.enum.includes(null)
713
+ const nullableEnum = schemaObject.enum.includes(null)
601
714
  if (nullableEnum) {
602
715
  baseItems.push({ keyword: schemaKeywords.nullable })
603
716
  }
604
- const filteredValues = schema.enum.filter((value) => value !== null)
717
+ const filteredValues = schemaObject.enum.filter((value) => value !== null)
605
718
 
606
719
  // x-enumNames has priority
607
720
  const extensionEnums = ['x-enumNames', 'x-enum-varnames']
608
- .filter((extensionKey) => extensionKey in schema)
721
+ .filter((extensionKey) => extensionKey in schemaObject)
609
722
  .map((extensionKey) => {
610
723
  return [
611
724
  {
@@ -614,10 +727,10 @@ export class SchemaGenerator<
614
727
  name,
615
728
  typeName,
616
729
  asConst: false,
617
- items: [...new Set(schema[extensionKey as keyof typeof schema] as string[])].map((name: string | number, index) => ({
730
+ items: [...new Set(schemaObject[extensionKey as keyof typeof schemaObject] as string[])].map((name: string | number, index) => ({
618
731
  name: transformers.stringify(name),
619
- value: schema.enum?.[index] as string | number,
620
- format: isNumber(schema.enum?.[index]) ? 'number' : 'string',
732
+ value: schemaObject.enum?.[index] as string | number,
733
+ format: isNumber(schemaObject.enum?.[index]) ? 'number' : 'string',
621
734
  })),
622
735
  },
623
736
  },
@@ -627,7 +740,7 @@ export class SchemaGenerator<
627
740
  ]
628
741
  })
629
742
 
630
- if (schema.type === 'number' || schema.type === 'integer') {
743
+ if (schemaObject.type === 'number' || schemaObject.type === 'integer') {
631
744
  // we cannot use z.enum when enum type is number/integer
632
745
  const enumNames = extensionEnums[0]?.find((item) => isKeyword(item, schemaKeywords.enum)) as unknown as SchemaKeywordMapper['enum']
633
746
  return [
@@ -656,7 +769,7 @@ export class SchemaGenerator<
656
769
  ]
657
770
  }
658
771
 
659
- if (schema.type === 'boolean') {
772
+ if (schemaObject.type === 'boolean') {
660
773
  // we cannot use z.enum when enum type is boolean
661
774
  const enumNames = extensionEnums[0]?.find((item) => isKeyword(item, schemaKeywords.enum)) as unknown as SchemaKeywordMapper['enum']
662
775
  return [
@@ -707,10 +820,10 @@ export class SchemaGenerator<
707
820
  ]
708
821
  }
709
822
 
710
- if ('prefixItems' in schema) {
711
- const prefixItems = schema.prefixItems as SchemaObject[]
712
- const min = schema.minimum ?? schema.minLength ?? schema.minItems ?? undefined
713
- const max = schema.maximum ?? schema.maxLength ?? schema.maxItems ?? undefined
823
+ if ('prefixItems' in schemaObject) {
824
+ const prefixItems = schemaObject.prefixItems as SchemaObject[]
825
+ const min = schemaObject.minimum ?? schemaObject.minLength ?? schemaObject.minItems ?? undefined
826
+ const max = schemaObject.maximum ?? schemaObject.maxLength ?? schemaObject.maxItems ?? undefined
714
827
 
715
828
  return [
716
829
  {
@@ -720,7 +833,7 @@ export class SchemaGenerator<
720
833
  max,
721
834
  items: prefixItems
722
835
  .map((item) => {
723
- return this.parse({ schema: item, name, parentName })[0]
836
+ return this.parse({ schemaObject: item, name, parentName })[0]
724
837
  })
725
838
  .filter(Boolean),
726
839
  },
@@ -729,16 +842,16 @@ export class SchemaGenerator<
729
842
  ]
730
843
  }
731
844
 
732
- if (version === '3.1' && 'const' in schema) {
845
+ if (version === '3.1' && 'const' in schemaObject) {
733
846
  // const keyword takes precendence over the actual type.
734
- if (schema['const']) {
847
+ if (schemaObject['const']) {
735
848
  return [
736
849
  {
737
850
  keyword: schemaKeywords.const,
738
851
  args: {
739
- name: schema['const'],
740
- format: typeof schema['const'] === 'number' ? 'number' : 'string',
741
- value: schema['const'],
852
+ name: schemaObject['const'],
853
+ format: typeof schemaObject['const'] === 'number' ? 'number' : 'string',
854
+ value: schemaObject['const'],
742
855
  },
743
856
  },
744
857
  ...baseItems,
@@ -756,8 +869,8 @@ export class SchemaGenerator<
756
869
  *
757
870
  * see also https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.7
758
871
  */
759
- if (schema.format) {
760
- switch (schema.format) {
872
+ if (schemaObject.format) {
873
+ switch (schemaObject.format) {
761
874
  case 'binary':
762
875
  baseItems.push({ keyword: schemaKeywords.blob })
763
876
  return baseItems
@@ -834,21 +947,21 @@ export class SchemaGenerator<
834
947
  }
835
948
  }
836
949
 
837
- if (schema.pattern) {
950
+ if (schemaObject.pattern) {
838
951
  baseItems.unshift({
839
952
  keyword: schemaKeywords.matches,
840
- args: schema.pattern,
953
+ args: schemaObject.pattern,
841
954
  })
842
955
 
843
956
  return baseItems
844
957
  }
845
958
 
846
959
  // type based logic
847
- if ('items' in schema || schema.type === ('array' as 'string')) {
848
- const min = schema.minimum ?? schema.minLength ?? schema.minItems ?? undefined
849
- const max = schema.maximum ?? schema.maxLength ?? schema.maxItems ?? undefined
850
- const items = this.parse({ schema: 'items' in schema ? (schema.items as SchemaObject) : [], name, parentName })
851
- const unique = !!schema.uniqueItems
960
+ if ('items' in schemaObject || schemaObject.type === ('array' as 'string')) {
961
+ const min = schemaObject.minimum ?? schemaObject.minLength ?? schemaObject.minItems ?? undefined
962
+ const max = schemaObject.maximum ?? schemaObject.maxLength ?? schemaObject.maxItems ?? undefined
963
+ const items = this.parse({ schemaObject: 'items' in schemaObject ? (schemaObject.items as SchemaObject) : [], name, parentName })
964
+ const unique = !!schemaObject.uniqueItems
852
965
 
853
966
  return [
854
967
  {
@@ -864,19 +977,47 @@ export class SchemaGenerator<
864
977
  ]
865
978
  }
866
979
 
867
- if (schema.properties || schema.additionalProperties) {
868
- return [...this.#parseProperties({ schema, name }), ...baseItems]
980
+ if (schemaObject.properties || schemaObject.additionalProperties) {
981
+ if (isDiscriminator(schemaObject)) {
982
+ // override schema to set type to be based on discriminator mapping, use of enum to convert type string to type 'mapping1' | 'mapping2'
983
+ const schemaObjectOverriden = Object.keys(schemaObject.properties || {}).reduce((acc, propertyName) => {
984
+ if (acc.properties?.[propertyName] && propertyName === schemaObject.discriminator.propertyName) {
985
+ return {
986
+ ...acc,
987
+ properties: {
988
+ ...acc.properties,
989
+ [propertyName]: {
990
+ ...((acc.properties[propertyName] as any) || {}),
991
+ enum: schemaObject.discriminator.mapping ? Object.keys(schemaObject.discriminator.mapping) : undefined,
992
+ },
993
+ },
994
+ }
995
+ }
996
+
997
+ return acc
998
+ }, schemaObject || {}) as SchemaObject
999
+
1000
+ return [
1001
+ ...this.#parseProperties({
1002
+ schemaObject: schemaObjectOverriden,
1003
+ name,
1004
+ }),
1005
+ ...baseItems,
1006
+ ]
1007
+ }
1008
+
1009
+ return [...this.#parseProperties({ schemaObject, name }), ...baseItems]
869
1010
  }
870
1011
 
871
- if (schema.type) {
872
- if (Array.isArray(schema.type)) {
1012
+ if (schemaObject.type) {
1013
+ if (Array.isArray(schemaObject.type)) {
873
1014
  // OPENAPI v3.1.0: https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0
874
- const [type] = schema.type as Array<OpenAPIV3.NonArraySchemaObjectType>
1015
+ const [type] = schemaObject.type as Array<OpenAPIV3.NonArraySchemaObjectType>
875
1016
 
876
1017
  return [
877
1018
  ...this.parse({
878
- schema: {
879
- ...schema,
1019
+ schemaObject: {
1020
+ ...schemaObject,
880
1021
  type,
881
1022
  },
882
1023
  name,
@@ -886,12 +1027,12 @@ export class SchemaGenerator<
886
1027
  ].filter(Boolean)
887
1028
  }
888
1029
 
889
- if (!['boolean', 'object', 'number', 'string', 'integer', 'null'].includes(schema.type)) {
890
- this.context.pluginManager.logger.emit('warning', `Schema type '${schema.type}' is not valid for schema ${parentName}.${name}`)
1030
+ if (!['boolean', 'object', 'number', 'string', 'integer', 'null'].includes(schemaObject.type)) {
1031
+ this.context.pluginManager.logger.emit('warning', `Schema type '${schemaObject.type}' is not valid for schema ${parentName}.${name}`)
891
1032
  }
892
1033
 
893
1034
  // 'string' | 'number' | 'integer' | 'boolean'
894
- return [{ keyword: schema.type }, ...baseItems]
1035
+ return [{ keyword: schemaObject.type }, ...baseItems]
895
1036
  }
896
1037
 
897
1038
  return [{ keyword: unknownReturn }]
@@ -900,8 +1041,6 @@ export class SchemaGenerator<
900
1041
  async build(...generators: Array<Generator<TPluginOptions>>): Promise<Array<KubbFile.File<TFileMeta>>> {
901
1042
  const { oas, contentType, include } = this.context
902
1043
 
903
- oas.resolveDiscriminators()
904
-
905
1044
  const schemas = getSchemas({ oas, contentType, includes: include })
906
1045
 
907
1046
  const promises = Object.entries(schemas).reduce((acc, [name, value]) => {
@@ -920,7 +1059,7 @@ export class SchemaGenerator<
920
1059
  }
921
1060
 
922
1061
  generators?.forEach((generator) => {
923
- const tree = this.parse({ schema: value, name: name })
1062
+ const tree = this.parse({ schemaObject: value, name: name })
924
1063
 
925
1064
  const promise = generator.schema?.({
926
1065
  instance: this,