fork of hey-api/openapi-ts because I need some additional things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #2515 from malcolm-kee/fix/all-of-discriminator-extends

fix: handle discriminator could be extending it

authored by

Lubos and committed by
GitHub
c2b34a8b 462412f0

+154 -43
+5
.changeset/forty-seals-explode.md
··· 1 + --- 2 + "@hey-api/openapi-ts": patch 3 + --- 4 + 5 + fix(parser): correctly handle schema extending discriminated schema
+18
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/discriminator-all-of/types.gen.ts
··· 44 44 qux?: boolean; 45 45 }; 46 46 47 + export type FooUnion = ({ 48 + id: 'bar'; 49 + } & BarUnion) | ({ 50 + id: 'baz'; 51 + } & BazUnion); 52 + 53 + export type BarUnion = { 54 + id?: string; 55 + bar?: string; 56 + }; 57 + 58 + export type BazUnion = { 59 + id?: string; 60 + baz?: string; 61 + }; 62 + 63 + export type QuxExtend = FooUnion; 64 + 47 65 export type ClientOptions = { 48 66 baseUrl: `${string}://${string}` | (string & {}); 49 67 };
+18
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/discriminator-all-of/types.gen.ts
··· 44 44 qux?: boolean; 45 45 }; 46 46 47 + export type FooUnion = ({ 48 + id: 'bar'; 49 + } & BarUnion) | ({ 50 + id: 'baz'; 51 + } & BazUnion); 52 + 53 + export type BarUnion = { 54 + id?: string; 55 + bar?: string; 56 + }; 57 + 58 + export type BazUnion = { 59 + id?: string; 60 + baz?: string; 61 + }; 62 + 63 + export type QuxExtend = FooUnion; 64 + 47 65 export type ClientOptions = { 48 66 baseUrl: `${string}://${string}` | (string & {}); 49 67 };
+26
packages/openapi-ts-tests/specs/3.0.x/discriminator-all-of.yaml
··· 67 67 properties: 68 68 qux: 69 69 type: boolean 70 + FooUnion: 71 + oneOf: 72 + - $ref: '#/components/schemas/BarUnion' 73 + - $ref: '#/components/schemas/BazUnion' 74 + discriminator: 75 + propertyName: id 76 + mapping: 77 + bar: '#/components/schemas/BarUnion' 78 + baz: '#/components/schemas/BazUnion' 79 + BarUnion: 80 + type: object 81 + properties: 82 + id: 83 + type: string 84 + bar: 85 + type: string 86 + BazUnion: 87 + type: object 88 + properties: 89 + id: 90 + type: string 91 + baz: 92 + type: string 93 + QuxExtend: # this is a schema that extends the FooUnion schema 94 + allOf: 95 + - $ref: '#/components/schemas/FooUnion'
+26
packages/openapi-ts-tests/specs/3.1.x/discriminator-all-of.yaml
··· 67 67 properties: 68 68 qux: 69 69 type: boolean 70 + FooUnion: 71 + oneOf: 72 + - $ref: '#/components/schemas/BarUnion' 73 + - $ref: '#/components/schemas/BazUnion' 74 + discriminator: 75 + propertyName: id 76 + mapping: 77 + bar: '#/components/schemas/BarUnion' 78 + baz: '#/components/schemas/BazUnion' 79 + BarUnion: 80 + type: object 81 + properties: 82 + id: 83 + type: string 84 + bar: 85 + type: string 86 + BazUnion: 87 + type: object 88 + properties: 89 + id: 90 + type: string 91 + baz: 92 + type: string 93 + QuxExtend: # this is a schema that extends the FooUnion schema 94 + allOf: 95 + - $ref: '#/components/schemas/FooUnion'
+30 -21
packages/openapi-ts/src/openApi/3.0.x/parser/schema.ts
··· 372 372 const values = discriminatorValues( 373 373 state.$ref, 374 374 ref.discriminator.mapping, 375 + // If the ref has oneOf, we only use the schema name as the value 376 + // only if current schema is part of the oneOf. Else it is extending 377 + // the ref schema 378 + ref.oneOf 379 + ? () => ref.oneOf!.some((o) => '$ref' in o && o.$ref === state.$ref) 380 + : undefined, 375 381 ); 376 - const valueSchemas: ReadonlyArray<IR.SchemaObject> = values.map( 377 - (value) => ({ 378 - const: value, 379 - type: 'string', 380 - }), 381 - ); 382 - const irDiscriminatorSchema: IR.SchemaObject = { 383 - properties: { 384 - [ref.discriminator.propertyName]: 385 - valueSchemas.length > 1 386 - ? { 387 - items: valueSchemas, 388 - logicalOperator: 'or', 389 - } 390 - : valueSchemas[0]!, 391 - }, 392 - type: 'object', 393 - }; 394 - if (ref.required?.includes(ref.discriminator.propertyName)) { 395 - irDiscriminatorSchema.required = [ref.discriminator.propertyName]; 382 + 383 + if (values.length > 0) { 384 + const valueSchemas: ReadonlyArray<IR.SchemaObject> = values.map( 385 + (value) => ({ 386 + const: value, 387 + type: 'string', 388 + }), 389 + ); 390 + const irDiscriminatorSchema: IR.SchemaObject = { 391 + properties: { 392 + [ref.discriminator.propertyName]: 393 + valueSchemas.length > 1 394 + ? { 395 + items: valueSchemas, 396 + logicalOperator: 'or', 397 + } 398 + : valueSchemas[0]!, 399 + }, 400 + type: 'object', 401 + }; 402 + if (ref.required?.includes(ref.discriminator.propertyName)) { 403 + irDiscriminatorSchema.required = [ref.discriminator.propertyName]; 404 + } 405 + schemaItems.push(irDiscriminatorSchema); 396 406 } 397 - schemaItems.push(irDiscriminatorSchema); 398 407 } 399 408 400 409 if (!state.circularReferenceTracker.has(compositionSchema.$ref)) {
+29 -21
packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts
··· 405 405 const values = discriminatorValues( 406 406 state.$ref, 407 407 ref.discriminator.mapping, 408 + // If the ref has oneOf, we only use the schema name as the value 409 + // only if current schema is part of the oneOf. Else it is extending 410 + // the ref schema 411 + ref.oneOf 412 + ? () => ref.oneOf!.some((o) => '$ref' in o && o.$ref === state.$ref) 413 + : undefined, 408 414 ); 409 - const valueSchemas: ReadonlyArray<IR.SchemaObject> = values.map( 410 - (value) => ({ 411 - const: value, 412 - type: 'string', 413 - }), 414 - ); 415 - const irDiscriminatorSchema: IR.SchemaObject = { 416 - properties: { 417 - [ref.discriminator.propertyName]: 418 - valueSchemas.length > 1 419 - ? { 420 - items: valueSchemas, 421 - logicalOperator: 'or', 422 - } 423 - : valueSchemas[0]!, 424 - }, 425 - type: 'object', 426 - }; 427 - if (ref.required?.includes(ref.discriminator.propertyName)) { 428 - irDiscriminatorSchema.required = [ref.discriminator.propertyName]; 415 + if (values.length > 0) { 416 + const valueSchemas: ReadonlyArray<IR.SchemaObject> = values.map( 417 + (value) => ({ 418 + const: value, 419 + type: 'string', 420 + }), 421 + ); 422 + const irDiscriminatorSchema: IR.SchemaObject = { 423 + properties: { 424 + [ref.discriminator.propertyName]: 425 + valueSchemas.length > 1 426 + ? { 427 + items: valueSchemas, 428 + logicalOperator: 'or', 429 + } 430 + : valueSchemas[0]!, 431 + }, 432 + type: 'object', 433 + }; 434 + if (ref.required?.includes(ref.discriminator.propertyName)) { 435 + irDiscriminatorSchema.required = [ref.discriminator.propertyName]; 436 + } 437 + schemaItems.push(irDiscriminatorSchema); 429 438 } 430 - schemaItems.push(irDiscriminatorSchema); 431 439 } 432 440 433 441 if (!state.circularReferenceTracker.has(compositionSchema.$ref)) {
+2 -1
packages/openapi-ts/src/openApi/shared/utils/discriminator.ts
··· 3 3 export const discriminatorValues = ( 4 4 $ref: string, 5 5 mapping?: Record<string, string>, 6 + shouldUseRefAsValue?: () => boolean, 6 7 ): ReadonlyArray<string> => { 7 8 const values: Array<string> = []; 8 9 ··· 12 13 } 13 14 } 14 15 15 - if (!values.length) { 16 + if (!values.length && (!shouldUseRefAsValue || shouldUseRefAsValue())) { 16 17 return [refToName($ref)]; 17 18 } 18 19