Skip to content

Commit 57b475d

Browse files
committed
wip
1 parent 6a36dcc commit 57b475d

10 files changed

Lines changed: 311 additions & 61 deletions

File tree

packages/documentation/src/app/overview/compatibility/page.mdx

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -244,42 +244,42 @@ openapi specification / json schema validation specifications.
244244

245245
Most notable exception is `readOnly` / `writeOnly` which are currently ignored, planned to be addressed prior to v1.
246246

247-
| Attribute | Supported | Notes |
248-
|:---------------------|:---------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------|
249-
| title | __N/A__ | |
250-
| multipleOf | ✅ | Applies to `type: number` |
251-
| maximum | ✅ | Applies to `type: number` |
252-
| exclusiveMaximum | ✅ | Applies to `type: number` |
253-
| minimum | ✅ | Applies to `type: number` |
254-
| exclusiveMinimum | ✅ | Applies to `type: number` |
255-
| maxLength | ✅ | Applies to `type: string` |
256-
| minLength | ✅ | Applies to `type: string` |
257-
| pattern | ✅ | Support for `type: string` |
258-
| maxItems | ✅ | Applies to `type: array` |
259-
| minItems | ✅ | Applies to `type: array` |
260-
| uniqueItems | ✅ | Applies to `type: array` |
261-
| maxProperties | 🚫 | Not yet supported |
262-
| minProperties | 🚫 | Not yet supported |
263-
| required | ✅ | Controls whether `undefined` is allowed for each value in `properties` |
264-
| enum | ✅ | Applies to `type: number`, `type: string` and `type: boolean` |
265-
| type | ✅ | |
266-
| not | 🚫 | Not yet supported |
267-
| allOf | ✅ | Produces a intersection type like `A & B` |
268-
| oneOf | ✅ | Produces a union type like `A \| B` |
269-
| anyOf | ✅ | Produces a union type like `A \| B` |
270-
| items | ✅ | Applies to `type: array` |
271-
| properties | ✅ | Applies to `type: object` |
272-
| additionalProperties | ✅ | Fairly comprehensive support, produces `Record<string, T>` or `unknown`/`any` (dependent on [`--ts-allow-any`](../reference/cli-options#--ts-allow-any)) |
273-
| format | ✅/🚧 | Limited support for format `email` and `date-time` |
274-
| default | ✅ | |
275-
| nullable | ✅ | Also supports `type: null` as an alternative |
276-
| discriminator | 🚫 | Ignored. Union / Intersection types are usd based on `anyOf` / `allOf` / `oneOf`. |
277-
| readOnly | 🚫 | Not yet supported |
278-
| writeOnly | 🚫 | Not yet supported |
279-
| example | __N/A__ | Ignored |
280-
| externalDocs | __N/A__ | Ignored |
281-
| deprecated | 🚫 | Not yet supported |
282-
| xml | 🚫 | Not yet supported |
247+
| Attribute | Supported | Notes |
248+
|:---------------------|:---------:|:---------------------------------------------------------------------------------------------------------------------------|
249+
| title | __N/A__ | |
250+
| multipleOf | ✅ | Applies to `type: number` |
251+
| maximum | ✅ | Applies to `type: number` |
252+
| exclusiveMaximum | ✅ | Applies to `type: number` |
253+
| minimum | ✅ | Applies to `type: number` |
254+
| exclusiveMinimum | ✅ | Applies to `type: number` |
255+
| maxLength | ✅ | Applies to `type: string` |
256+
| minLength | ✅ | Applies to `type: string` |
257+
| pattern | ✅ | Support for `type: string` |
258+
| maxItems | ✅ | Applies to `type: array` |
259+
| minItems | ✅ | Applies to `type: array` |
260+
| uniqueItems | ✅ | Applies to `type: array` |
261+
| maxProperties | 🚫 | Not yet supported |
262+
| minProperties | 🚫 | Not yet supported |
263+
| required | ✅ | Controls whether `undefined` is allowed for each value in `properties` |
264+
| enum | ✅ | Applies to `type: number`, `type: string` and `type: boolean` |
265+
| type | ✅ | |
266+
| not | 🚫 | Not yet supported |
267+
| allOf | ✅ | Produces a intersection type like `A & B` |
268+
| oneOf | ✅ | Produces a union type like `A \| B` |
269+
| anyOf | ✅ | Produces a union type like `A \| B` |
270+
| items | ✅ | Applies to `type: array` |
271+
| properties | ✅ | Applies to `type: object` |
272+
| additionalProperties | ✅ | Produces `Record<string, T>` or `unknown`/`any` (dependent on [`--ts-allow-any`](../reference/cli-options#--ts-allow-any)) |
273+
| format | ✅/🚧 | Limited support for format `binary`, `email` and `date-time` |
274+
| default | ✅ | |
275+
| nullable | ✅ | Also supports `type: null` as an alternative |
276+
| discriminator | 🚫 | Ignored. Union / Intersection types are usd based on `anyOf` / `allOf` / `oneOf`. |
277+
| readOnly | 🚫 | Not yet supported |
278+
| writeOnly | 🚫 | Not yet supported |
279+
| example | __N/A__ | Ignored |
280+
| externalDocs | __N/A__ | Ignored |
281+
| deprecated | 🚫 | Not yet supported |
282+
| xml | 🚫 | Not yet supported |
283283

284284
### Encoding Object
285285
| Attribute | Supported | Notes |

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export class Input implements ISchemaProvider {
4848
private loader: OpenapiLoader,
4949
readonly config: InputConfig,
5050
private readonly syntheticNameGenerator: SyntheticNameGenerator = defaultSyntheticNameGenerator,
51-
private readonly schemaNormalizer = new SchemaNormalizer(config),
51+
private readonly schemaNormalizer = new SchemaNormalizer(config, this),
5252
private readonly parameterNormalizer = new ParameterNormalizer(
5353
loader,
5454
schemaNormalizer,

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import type {Parameter} from "../openapi-types"
55
import {defaultSyntheticNameGenerator} from "../synthetic-name-generator"
66
import {ParameterNormalizer} from "./parameter-normalizer"
77
import {SchemaNormalizer} from "./schema-normalizer"
8+
import { FakeSchemaProvider } from "../../test/fake-schema-provider"
89

910
describe("ParameterNormalizer", () => {
1011
let loader: jest.Mocked<OpenapiLoader>
12+
let fakeSchemaProvider: FakeSchemaProvider
1113
let schemaNormalizer: SchemaNormalizer
1214
let parameterNormalizer: ParameterNormalizer
1315

@@ -18,10 +20,12 @@ describe("ParameterNormalizer", () => {
1820
addVirtualType: jest.fn(),
1921
} as unknown as jest.Mocked<OpenapiLoader>
2022

23+
fakeSchemaProvider = new FakeSchemaProvider()
24+
2125
schemaNormalizer = new SchemaNormalizer({
2226
extractInlineSchemas: true,
2327
enumExtensibility: "open",
24-
})
28+
}, fakeSchemaProvider)
2529

2630
parameterNormalizer = new ParameterNormalizer(
2731
loader,

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

Lines changed: 120 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
1-
import {describe, expect, it} from "@jest/globals"
1+
import {beforeEach, describe, expect, it} from "@jest/globals"
2+
import {FakeSchemaProvider} from "../../test/fake-schema-provider"
23
import {irFixture as ir} from "../../test/ir-model.fixtures.test-utils"
34
import {generationLib} from "../generation-lib"
45
import {SchemaNormalizer} from "./schema-normalizer"
56

67
describe("core/input - SchemaNormalizer", () => {
7-
const schemaNormalizer = new SchemaNormalizer({
8-
extractInlineSchemas: true,
9-
enumExtensibility: "open",
8+
let schemaProvider: FakeSchemaProvider
9+
let schemaNormalizer: SchemaNormalizer
10+
11+
beforeEach(() => {
12+
schemaProvider = new FakeSchemaProvider()
13+
schemaNormalizer = new SchemaNormalizer(
14+
{
15+
extractInlineSchemas: true,
16+
enumExtensibility: "open",
17+
},
18+
schemaProvider,
19+
)
1020
})
1121

1222
it("passes through $ref untouched", () => {
@@ -512,34 +522,130 @@ describe("core/input - SchemaNormalizer", () => {
512522
}),
513523
)
514524
})
525+
})
526+
527+
describe("discriminator", () => {
528+
describe("all alternatives are $ref of type: object", () => {
529+
it("supports mapping", () => {
530+
schemaProvider.registerTestRef(
531+
ir.ref("/components/schemas/Foo"),
532+
ir.object({properties: {type: ir.string()}}),
533+
)
534+
schemaProvider.registerTestRef(
535+
ir.ref("/components/schemas/Bar"),
536+
ir.object({properties: {type: ir.string()}}),
537+
)
538+
539+
const actual = schemaNormalizer.normalize({
540+
type: "object",
541+
discriminator: {
542+
propertyName: "type",
543+
mapping: {
544+
foo: "#/components/schemas/Foo",
545+
bar: "#/components/schemas/Bar",
546+
},
547+
},
548+
oneOf: [
549+
{$ref: "#/components/schemas/Foo"},
550+
{$ref: "#/components/schemas/Bar"},
551+
],
552+
})
553+
554+
expect(actual).toStrictEqual(
555+
ir.union({
556+
discriminator: {
557+
propertyName: "type",
558+
mapping: {
559+
foo: ir.ref("/components/schemas/Foo"),
560+
bar: ir.ref("/components/schemas/Bar"),
561+
},
562+
},
563+
schemas: [
564+
ir.ref("/components/schemas/Foo"),
565+
ir.ref("/components/schemas/Bar"),
566+
],
567+
}),
568+
)
569+
})
570+
571+
it("infers a mapping when none provided", () => {
572+
schemaProvider.registerTestRef(
573+
ir.ref("/components/schemas/Foo"),
574+
ir.object({properties: {type: ir.string()}}),
575+
)
576+
schemaProvider.registerTestRef(
577+
ir.ref("/components/schemas/Bar"),
578+
ir.object({properties: {type: ir.string()}}),
579+
)
580+
581+
const actual = schemaNormalizer.normalize({
582+
type: "object",
583+
discriminator: {
584+
propertyName: "type",
585+
},
586+
oneOf: [
587+
{$ref: "#/components/schemas/Foo"},
588+
{$ref: "#/components/schemas/Bar"},
589+
],
590+
})
515591

516-
it("handles a discriminator", () => {
592+
expect(actual).toStrictEqual(
593+
ir.union({
594+
discriminator: {
595+
propertyName: "type",
596+
mapping: {
597+
Foo: ir.ref("/components/schemas/Foo"),
598+
Bar: ir.ref("/components/schemas/Bar"),
599+
},
600+
},
601+
schemas: [
602+
ir.ref("/components/schemas/Foo"),
603+
ir.ref("/components/schemas/Bar"),
604+
],
605+
}),
606+
)
607+
})
608+
})
609+
610+
it("ignores the discriminator property where some alternatives are not type: object", () => {})
611+
612+
it("ignores the discriminator property where no composition is defined", () => {
517613
const actual = schemaNormalizer.normalize({
518614
type: "object",
615+
properties: {
616+
name: {type: "string"},
617+
type: {type: "string"},
618+
},
519619
discriminator: {
520620
propertyName: "type",
521621
mapping: {
522622
foo: "#/components/schemas/Foo",
523623
bar: "#/components/schemas/Bar",
524624
},
525625
},
626+
})
627+
628+
expect(actual).toStrictEqual(
629+
ir.object({properties: {name: ir.string(), type: ir.string()}}),
630+
)
631+
})
632+
633+
it("ignores the discriminator property where some alternatives are inline schemas", () => {
634+
const actual = schemaNormalizer.normalize({
635+
type: "object",
636+
discriminator: {
637+
propertyName: "type",
638+
},
526639
oneOf: [
527-
{$ref: "#/components/schemas/Foo"},
640+
{type: "object", properties: {type: {type: "string"}}},
528641
{$ref: "#/components/schemas/Bar"},
529642
],
530643
})
531644

532645
expect(actual).toStrictEqual(
533646
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-
},
541647
schemas: [
542-
ir.ref("/components/schemas/Foo"),
648+
ir.object({properties: {type: ir.string()}}),
543649
ir.ref("/components/schemas/Bar"),
544650
],
545651
}),

0 commit comments

Comments
 (0)