Skip to content

Commit c2b34a8

Browse files
authored
Merge pull request #2515 from malcolm-kee/fix/all-of-discriminator-extends
fix: handle discriminator could be extending it
2 parents 462412f + b81051e commit c2b34a8

File tree

8 files changed

+154
-43
lines changed

8 files changed

+154
-43
lines changed

.changeset/forty-seals-explode.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hey-api/openapi-ts": patch
3+
---
4+
5+
fix(parser): correctly handle schema extending discriminated schema

packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/discriminator-all-of/types.gen.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,24 @@ export type QuxMapped = FooMapped & {
4444
qux?: boolean;
4545
};
4646

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+
4765
export type ClientOptions = {
4866
baseUrl: `${string}://${string}` | (string & {});
4967
};

packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/discriminator-all-of/types.gen.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,24 @@ export type QuxMapped = FooMapped & {
4444
qux?: boolean;
4545
};
4646

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+
4765
export type ClientOptions = {
4866
baseUrl: `${string}://${string}` | (string & {});
4967
};

packages/openapi-ts-tests/specs/3.0.x/discriminator-all-of.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,29 @@ components:
6767
properties:
6868
qux:
6969
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'

packages/openapi-ts-tests/specs/3.1.x/discriminator-all-of.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,29 @@ components:
6767
properties:
6868
qux:
6969
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'

packages/openapi-ts/src/openApi/3.0.x/parser/schema.ts

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -372,29 +372,38 @@ const parseAllOf = ({
372372
const values = discriminatorValues(
373373
state.$ref,
374374
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,
375381
);
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);
396406
}
397-
schemaItems.push(irDiscriminatorSchema);
398407
}
399408

400409
if (!state.circularReferenceTracker.has(compositionSchema.$ref)) {

packages/openapi-ts/src/openApi/3.1.x/parser/schema.ts

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -405,29 +405,37 @@ const parseAllOf = ({
405405
const values = discriminatorValues(
406406
state.$ref,
407407
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,
408414
);
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);
429438
}
430-
schemaItems.push(irDiscriminatorSchema);
431439
}
432440

433441
if (!state.circularReferenceTracker.has(compositionSchema.$ref)) {

packages/openapi-ts/src/openApi/shared/utils/discriminator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { refToName } from '../../../utils/ref';
33
export const discriminatorValues = (
44
$ref: string,
55
mapping?: Record<string, string>,
6+
shouldUseRefAsValue?: () => boolean,
67
): ReadonlyArray<string> => {
78
const values: Array<string> = [];
89

@@ -12,7 +13,7 @@ export const discriminatorValues = (
1213
}
1314
}
1415

15-
if (!values.length) {
16+
if (!values.length && (!shouldUseRefAsValue || shouldUseRefAsValue())) {
1617
return [refToName($ref)];
1718
}
1819

0 commit comments

Comments
 (0)