@kubb/plugin-oas 3.10.1 → 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.
- package/dist/{OperationGenerator-DiF6WJNP.d.cts → OperationGenerator-BrnQyed_.d.cts} +9 -1
- package/dist/{OperationGenerator-DiF6WJNP.d.ts → OperationGenerator-BrnQyed_.d.ts} +9 -1
- package/dist/Schema-DTc2F3jG.d.cts +32 -0
- package/dist/Schema-Dhz38Get.d.ts +32 -0
- package/dist/{chunk-72MVTXCW.js → chunk-5JWN6NVC.js} +245 -133
- package/dist/chunk-5JWN6NVC.js.map +1 -0
- package/dist/{chunk-DUZZHEQI.cjs → chunk-ES7R7N34.cjs} +6 -6
- package/dist/chunk-ES7R7N34.cjs.map +1 -0
- package/dist/{chunk-BAU7PO7T.js → chunk-JNN4JPWK.js} +4 -4
- package/dist/chunk-JNN4JPWK.js.map +1 -0
- package/dist/{chunk-3Y4QGY6D.js → chunk-PORSNYI5.js} +3 -3
- package/dist/chunk-PORSNYI5.js.map +1 -0
- package/dist/{chunk-Q4HTTWL7.cjs → chunk-PSWNN6SJ.cjs} +245 -133
- package/dist/chunk-PSWNN6SJ.cjs.map +1 -0
- package/dist/{chunk-DN373TFU.js → chunk-RNF2QJEG.js} +4 -4
- package/dist/chunk-RNF2QJEG.js.map +1 -0
- package/dist/{chunk-KXB5DUFD.cjs → chunk-Z2NREI4X.cjs} +4 -4
- package/dist/chunk-Z2NREI4X.cjs.map +1 -0
- package/dist/{chunk-B7KP5ZFA.cjs → chunk-ZVFL3NXX.cjs} +3 -3
- package/dist/chunk-ZVFL3NXX.cjs.map +1 -0
- package/dist/components.cjs +4 -4
- package/dist/components.d.cts +2 -2
- package/dist/components.d.ts +2 -2
- package/dist/components.js +1 -1
- package/dist/generators.cjs +4 -4
- package/dist/generators.d.cts +1 -1
- package/dist/generators.d.ts +1 -1
- package/dist/generators.js +3 -3
- package/dist/hooks.cjs +9 -9
- package/dist/hooks.d.cts +2 -2
- package/dist/hooks.d.ts +2 -2
- package/dist/hooks.js +3 -3
- package/dist/index.cjs +11 -11
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -6
- package/dist/utils.cjs +3 -3
- package/dist/utils.d.cts +10 -3
- package/dist/utils.d.ts +10 -3
- package/dist/utils.js +1 -1
- package/package.json +7 -7
- package/src/SchemaGenerator.ts +271 -132
- package/src/SchemaMapper.ts +1 -0
- package/src/components/Schema.tsx +13 -4
- package/src/generator.tsx +8 -1
- package/src/utils/getSchemaFactory.ts +10 -3
- package/dist/Schema-BbIxCfn7.d.ts +0 -23
- package/dist/Schema-Ds5f4y7m.d.cts +0 -23
- package/dist/chunk-3Y4QGY6D.js.map +0 -1
- package/dist/chunk-72MVTXCW.js.map +0 -1
- package/dist/chunk-B7KP5ZFA.cjs.map +0 -1
- package/dist/chunk-BAU7PO7T.js.map +0 -1
- package/dist/chunk-DN373TFU.js.map +0 -1
- package/dist/chunk-DUZZHEQI.cjs.map +0 -1
- package/dist/chunk-KXB5DUFD.cjs.map +0 -1
- package/dist/chunk-Q4HTTWL7.cjs.map +0 -1
package/src/SchemaGenerator.ts
CHANGED
|
@@ -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
|
-
|
|
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({
|
|
254
|
-
const properties =
|
|
255
|
-
const additionalProperties =
|
|
256
|
-
const 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({
|
|
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({
|
|
290
|
-
: this.parse({
|
|
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(
|
|
308
|
-
const { $ref } =
|
|
309
|
-
|
|
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
|
-
|
|
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
|
-
|
|
354
|
-
|
|
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({
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
const {
|
|
365
|
-
|
|
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:
|
|
374
|
-
format:
|
|
463
|
+
type: schemaObject.type as any,
|
|
464
|
+
format: schemaObject.format,
|
|
375
465
|
},
|
|
376
466
|
},
|
|
377
467
|
]
|
|
378
|
-
const min =
|
|
379
|
-
const max =
|
|
380
|
-
const nullable = isNullable(
|
|
381
|
-
const defaultNullAndNullable =
|
|
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 (
|
|
384
|
-
if (typeof
|
|
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(
|
|
477
|
+
args: transformers.stringify(schemaObject.default),
|
|
388
478
|
})
|
|
389
|
-
} else if (typeof
|
|
479
|
+
} else if (typeof schemaObject.default === 'boolean') {
|
|
390
480
|
baseItems.push({
|
|
391
481
|
keyword: schemaKeywords.default,
|
|
392
|
-
args:
|
|
482
|
+
args: schemaObject.default ?? false,
|
|
393
483
|
})
|
|
394
484
|
} else {
|
|
395
485
|
baseItems.push({
|
|
396
486
|
keyword: schemaKeywords.default,
|
|
397
|
-
args:
|
|
487
|
+
args: schemaObject.default,
|
|
398
488
|
})
|
|
399
489
|
}
|
|
400
490
|
}
|
|
401
491
|
|
|
402
|
-
if (
|
|
492
|
+
if (schemaObject.deprecated) {
|
|
403
493
|
baseItems.push({
|
|
404
494
|
keyword: schemaKeywords.deprecated,
|
|
405
495
|
})
|
|
406
496
|
}
|
|
407
497
|
|
|
408
|
-
if (
|
|
498
|
+
if (schemaObject.description) {
|
|
409
499
|
baseItems.push({
|
|
410
500
|
keyword: schemaKeywords.describe,
|
|
411
|
-
args:
|
|
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 (
|
|
428
|
-
const [_schema, nullable] =
|
|
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 (
|
|
525
|
+
if (schemaObject.readOnly) {
|
|
436
526
|
baseItems.push({ keyword: schemaKeywords.readOnly })
|
|
437
527
|
}
|
|
438
528
|
|
|
439
|
-
if (
|
|
529
|
+
if (schemaObject.writeOnly) {
|
|
440
530
|
baseItems.push({ keyword: schemaKeywords.writeOnly })
|
|
441
531
|
}
|
|
442
532
|
|
|
443
|
-
if (isReference(
|
|
533
|
+
if (isReference(schemaObject)) {
|
|
444
534
|
return [
|
|
445
|
-
...this.#getRefAlias(
|
|
446
|
-
|
|
535
|
+
...this.#getRefAlias(schemaObject, name),
|
|
536
|
+
schemaObject.description && {
|
|
447
537
|
keyword: schemaKeywords.describe,
|
|
448
|
-
args:
|
|
538
|
+
args: schemaObject.description,
|
|
449
539
|
},
|
|
450
540
|
nullable && { keyword: schemaKeywords.nullable },
|
|
451
|
-
|
|
452
|
-
|
|
541
|
+
schemaObject.readOnly && { keyword: schemaKeywords.readOnly },
|
|
542
|
+
schemaObject.writeOnly && { keyword: schemaKeywords.writeOnly },
|
|
453
543
|
{
|
|
454
544
|
keyword: schemaKeywords.schema,
|
|
455
545
|
args: {
|
|
456
|
-
type:
|
|
457
|
-
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 (
|
|
553
|
+
if (schemaObject.oneOf) {
|
|
464
554
|
// union
|
|
465
|
-
const schemaWithoutOneOf = { ...
|
|
555
|
+
const schemaWithoutOneOf = { ...schemaObject, oneOf: undefined }
|
|
466
556
|
|
|
467
|
-
const union:
|
|
557
|
+
const union: SchemaKeywordMapper['union'] = {
|
|
468
558
|
keyword: schemaKeywords.union,
|
|
469
|
-
args:
|
|
559
|
+
args: schemaObject.oneOf
|
|
470
560
|
.map((item) => {
|
|
471
|
-
|
|
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({
|
|
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 (
|
|
592
|
+
if (schemaObject.anyOf) {
|
|
495
593
|
// union
|
|
496
|
-
const schemaWithoutAnyOf = { ...
|
|
594
|
+
const schemaWithoutAnyOf = { ...schemaObject, anyOf: undefined }
|
|
497
595
|
|
|
498
|
-
const union:
|
|
596
|
+
const union: SchemaKeywordMapper['union'] = {
|
|
499
597
|
keyword: schemaKeywords.union,
|
|
500
|
-
args:
|
|
598
|
+
args: schemaObject.anyOf
|
|
501
599
|
.map((item) => {
|
|
502
|
-
|
|
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
|
-
|
|
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 (
|
|
642
|
+
if (schemaObject.allOf) {
|
|
528
643
|
// intersection/add
|
|
529
|
-
const schemaWithoutAllOf = { ...
|
|
644
|
+
const schemaWithoutAllOf = { ...schemaObject, allOf: undefined }
|
|
530
645
|
|
|
531
646
|
const and: Schema = {
|
|
532
647
|
keyword: schemaKeywords.and,
|
|
533
|
-
args:
|
|
648
|
+
args: schemaObject.allOf
|
|
534
649
|
.map((item) => {
|
|
535
|
-
return item && this.parse({
|
|
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 =
|
|
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({
|
|
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({
|
|
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 (
|
|
701
|
+
if (schemaObject.enum) {
|
|
589
702
|
if (options.enumSuffix === '') {
|
|
590
|
-
|
|
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({
|
|
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 =
|
|
713
|
+
const nullableEnum = schemaObject.enum.includes(null)
|
|
601
714
|
if (nullableEnum) {
|
|
602
715
|
baseItems.push({ keyword: schemaKeywords.nullable })
|
|
603
716
|
}
|
|
604
|
-
const filteredValues =
|
|
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
|
|
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(
|
|
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:
|
|
620
|
-
format: isNumber(
|
|
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 (
|
|
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 (
|
|
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
|
|
711
|
-
const prefixItems =
|
|
712
|
-
const min =
|
|
713
|
-
const max =
|
|
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({
|
|
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
|
|
845
|
+
if (version === '3.1' && 'const' in schemaObject) {
|
|
733
846
|
// const keyword takes precendence over the actual type.
|
|
734
|
-
if (
|
|
847
|
+
if (schemaObject['const']) {
|
|
735
848
|
return [
|
|
736
849
|
{
|
|
737
850
|
keyword: schemaKeywords.const,
|
|
738
851
|
args: {
|
|
739
|
-
name:
|
|
740
|
-
format: typeof
|
|
741
|
-
value:
|
|
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 (
|
|
760
|
-
switch (
|
|
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 (
|
|
950
|
+
if (schemaObject.pattern) {
|
|
838
951
|
baseItems.unshift({
|
|
839
952
|
keyword: schemaKeywords.matches,
|
|
840
|
-
args:
|
|
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
|
|
848
|
-
const min =
|
|
849
|
-
const max =
|
|
850
|
-
const items = this.parse({
|
|
851
|
-
const unique = !!
|
|
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 (
|
|
868
|
-
|
|
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 (
|
|
872
|
-
if (Array.isArray(
|
|
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] =
|
|
1015
|
+
const [type] = schemaObject.type as Array<OpenAPIV3.NonArraySchemaObjectType>
|
|
875
1016
|
|
|
876
1017
|
return [
|
|
877
1018
|
...this.parse({
|
|
878
|
-
|
|
879
|
-
...
|
|
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(
|
|
890
|
-
this.context.pluginManager.logger.emit('warning', `Schema type '${
|
|
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:
|
|
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({
|
|
1062
|
+
const tree = this.parse({ schemaObject: value, name: name })
|
|
924
1063
|
|
|
925
1064
|
const promise = generator.schema?.({
|
|
926
1065
|
instance: this,
|