Skip to content

Commit 6a36dcc

Browse files
committed
feat: add discriminator to IRUnion
1 parent 84eac3b commit 6a36dcc

5 files changed

Lines changed: 77 additions & 3 deletions

File tree

packages/openapi-code-generator/src/core/normalization/schema-normalizer.spec.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,39 @@ describe("core/input - SchemaNormalizer", () => {
512512
}),
513513
)
514514
})
515+
516+
it("handles a discriminator", () => {
517+
const actual = schemaNormalizer.normalize({
518+
type: "object",
519+
discriminator: {
520+
propertyName: "type",
521+
mapping: {
522+
foo: "#/components/schemas/Foo",
523+
bar: "#/components/schemas/Bar",
524+
},
525+
},
526+
oneOf: [
527+
{$ref: "#/components/schemas/Foo"},
528+
{$ref: "#/components/schemas/Bar"},
529+
],
530+
})
531+
532+
expect(actual).toStrictEqual(
533+
ir.union({
534+
discriminator: {
535+
propertyName: "type",
536+
mapping: {
537+
foo: ir.ref("/components/schemas/Foo"),
538+
bar: ir.ref("/components/schemas/Bar"),
539+
},
540+
},
541+
schemas: [
542+
ir.ref("/components/schemas/Foo"),
543+
ir.ref("/components/schemas/Bar"),
544+
],
545+
}),
546+
)
547+
})
515548
})
516549

517550
describe("empty schemas / additionalProperties", () => {

packages/openapi-code-generator/src/core/normalization/schema-normalizer.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {generationLib} from "../generation-lib"
33
import type {InputConfig} from "../input"
44
import {logger} from "../logger"
55
import type {
6+
Discriminator,
67
Reference,
78
Schema,
89
SchemaNumber,
@@ -191,7 +192,11 @@ export class SchemaNormalizer {
191192
{...base, nullable},
192193
hasOwnProperties ? [...allOf, result] : allOf,
193194
)
194-
const maybeUnion = this.union({...base, nullable}, [...oneOf, ...anyOf])
195+
const maybeUnion = this.union(
196+
{...base, nullable},
197+
[...oneOf, ...anyOf],
198+
schemaObject.discriminator,
199+
)
195200

196201
if (maybeIntersection && maybeUnion) {
197202
return this.intersection({...base, nullable}, [
@@ -375,6 +380,29 @@ export class SchemaNormalizer {
375380
}
376381
}
377382

383+
private normalizeDiscriminator(
384+
discriminator: Discriminator | undefined,
385+
): IRModelUnion["discriminator"] | undefined {
386+
if (!discriminator) {
387+
return undefined
388+
}
389+
390+
if (!discriminator.mapping) {
391+
// todo: cna we support this if the discriminated property is an enum of one element?
392+
logger.warn("discriminators without a mapping are ignored.")
393+
return undefined
394+
}
395+
396+
return {
397+
propertyName: discriminator.propertyName,
398+
mapping: Object.fromEntries(
399+
Object.entries(discriminator.mapping).map(([key, value]) => {
400+
return [key, {$ref: value}]
401+
}),
402+
),
403+
}
404+
}
405+
378406
private normalizeComposition(
379407
items: (Schema | Reference)[] = [],
380408
parent: SchemaObject,
@@ -511,6 +539,7 @@ export class SchemaNormalizer {
511539
private union(
512540
base: IRModelBase,
513541
schemas: MaybeIRModel[],
542+
discriminator: Discriminator | undefined,
514543
): MaybeIRModel | IRModelUnion | undefined {
515544
// (A|B)|(C|D) is the same as (A|B|C|D)
516545
// todo: merge repeated in-line schemas
@@ -530,6 +559,7 @@ export class SchemaNormalizer {
530559
return {
531560
...base,
532561
type: "union",
562+
discriminator: this.normalizeDiscriminator(discriminator),
533563
schemas,
534564
}
535565
}

packages/openapi-code-generator/src/core/openapi-types-normalized.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ export interface IRModelUnion extends IRModelBase {
7979
// of this.
8080
type: "union"
8181
schemas: NonEmptyArray<MaybeIRModel>
82+
83+
discriminator?:
84+
| {
85+
propertyName: string
86+
mapping: {
87+
[propertyValue: string]: IRRef
88+
}
89+
//todo: support defaultMapping
90+
}
91+
| undefined
8292
}
8393

8494
export interface IRModelObject extends IRModelBase {

packages/openapi-code-generator/src/core/openapi-types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,8 +359,9 @@ export interface xInternalPreproccess {
359359
export interface Discriminator {
360360
propertyName: string
361361
mapping?: {
362-
[k: string]: string
362+
[propertyValue: string]: string
363363
}
364+
defaultMapping?: string
364365
}
365366

366367
export interface Example {

packages/openapi-code-generator/src/test/ir-model.fixtures.test-utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ const extension = {
115115
schemas: [base.any],
116116
nullable: false,
117117
default: undefined,
118+
discriminator: undefined,
118119
"x-internal-preprocess": undefined,
119120
} satisfies IRModelUnion,
120121
null: {
@@ -178,7 +179,6 @@ export const irFixture = {
178179
ref(path: string, file = ""): IRRef {
179180
return {
180181
$ref: `${file}#${path}`,
181-
"x-internal-preprocess": undefined,
182182
}
183183
},
184184
any(partial: Partial<IRModelAny> = {}): IRModelAny {

0 commit comments

Comments
 (0)