Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 36 additions & 36 deletions packages/documentation/src/app/overview/compatibility/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -244,42 +244,42 @@ openapi specification / json schema validation specifications.

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

| Attribute | Supported | Notes |
|:---------------------|:---------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------|
| title | __N/A__ | |
| multipleOf | ✅ | Applies to `type: number` |
| maximum | ✅ | Applies to `type: number` |
| exclusiveMaximum | ✅ | Applies to `type: number` |
| minimum | ✅ | Applies to `type: number` |
| exclusiveMinimum | ✅ | Applies to `type: number` |
| maxLength | ✅ | Applies to `type: string` |
| minLength | ✅ | Applies to `type: string` |
| pattern | ✅ | Support for `type: string` |
| maxItems | ✅ | Applies to `type: array` |
| minItems | ✅ | Applies to `type: array` |
| uniqueItems | ✅ | Applies to `type: array` |
| maxProperties | 🚫 | Not yet supported |
| minProperties | 🚫 | Not yet supported |
| required | ✅ | Controls whether `undefined` is allowed for each value in `properties` |
| enum | ✅ | Applies to `type: number`, `type: string` and `type: boolean` |
| type | ✅ | |
| not | 🚫 | Not yet supported |
| allOf | ✅ | Produces a intersection type like `A & B` |
| oneOf | ✅ | Produces a union type like `A \| B` |
| anyOf | ✅ | Produces a union type like `A \| B` |
| items | ✅ | Applies to `type: array` |
| properties | ✅ | Applies to `type: object` |
| additionalProperties | ✅ | Fairly comprehensive support, produces `Record<string, T>` or `unknown`/`any` (dependent on [`--ts-allow-any`](../reference/cli-options#--ts-allow-any)) |
| format | ✅/🚧 | Limited support for format `email` and `date-time` |
| default | ✅ | |
| nullable | ✅ | Also supports `type: null` as an alternative |
| discriminator | 🚫 | Ignored. Union / Intersection types are usd based on `anyOf` / `allOf` / `oneOf`. |
| readOnly | 🚫 | Not yet supported |
| writeOnly | 🚫 | Not yet supported |
| example | __N/A__ | Ignored |
| externalDocs | __N/A__ | Ignored |
| deprecated | 🚫 | Not yet supported |
| xml | 🚫 | Not yet supported |
| Attribute | Supported | Notes |
|:---------------------|:---------:|:---------------------------------------------------------------------------------------------------------------------------|
| title | __N/A__ | |
| multipleOf | ✅ | Applies to `type: number` |
| maximum | ✅ | Applies to `type: number` |
| exclusiveMaximum | ✅ | Applies to `type: number` |
| minimum | ✅ | Applies to `type: number` |
| exclusiveMinimum | ✅ | Applies to `type: number` |
| maxLength | ✅ | Applies to `type: string` |
| minLength | ✅ | Applies to `type: string` |
| pattern | ✅ | Support for `type: string` |
| maxItems | ✅ | Applies to `type: array` |
| minItems | ✅ | Applies to `type: array` |
| uniqueItems | ✅ | Applies to `type: array` |
| maxProperties | 🚫 | Not yet supported |
| minProperties | 🚫 | Not yet supported |
| required | ✅ | Controls whether `undefined` is allowed for each value in `properties` |
| enum | ✅ | Applies to `type: number`, `type: string` and `type: boolean` |
| type | ✅ | |
| not | 🚫 | Not yet supported |
| allOf | ✅ | Produces a intersection type like `A & B` |
| oneOf | ✅ | Produces a union type like `A \| B` |
| anyOf | ✅ | Produces a union type like `A \| B` |
| items | ✅ | Applies to `type: array` |
| properties | ✅ | Applies to `type: object` |
| additionalProperties | ✅ | Produces `Record<string, T>` or `unknown`/`any` (dependent on [`--ts-allow-any`](../reference/cli-options#--ts-allow-any)) |
| format | ✅/🚧 | Limited support for format `binary`, `email` and `date-time` |
| default | ✅ | |
| nullable | ✅ | Also supports `type: null` as an alternative |
| discriminator | 🚫 | Ignored. Union / Intersection types are usd based on `anyOf` / `allOf` / `oneOf`. |
| readOnly | 🚫 | Not yet supported |
| writeOnly | 🚫 | Not yet supported |
| example | __N/A__ | Ignored |
| externalDocs | __N/A__ | Ignored |
| deprecated | 🚫 | Not yet supported |
| xml | 🚫 | Not yet supported |

### Encoding Object
| Attribute | Supported | Notes |
Expand Down
2 changes: 1 addition & 1 deletion packages/openapi-code-generator/src/core/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class Input implements ISchemaProvider {
private loader: OpenapiLoader,
readonly config: InputConfig,
private readonly syntheticNameGenerator: SyntheticNameGenerator = defaultSyntheticNameGenerator,
private readonly schemaNormalizer = new SchemaNormalizer(config),
private readonly schemaNormalizer = new SchemaNormalizer(config, this),
private readonly parameterNormalizer = new ParameterNormalizer(
loader,
schemaNormalizer,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import {beforeEach, describe, expect, it, jest} from "@jest/globals"

Check failure on line 1 in packages/openapi-code-generator/src/core/normalization/parameter-normalizer.spec.ts

View workflow job for this annotation

GitHub Actions / build (24.x)

format

File content differs from formatting output

Check failure on line 1 in packages/openapi-code-generator/src/core/normalization/parameter-normalizer.spec.ts

View workflow job for this annotation

GitHub Actions / build (24.x)

assist/source/organizeImports

The imports and exports are not sorted.
import {irFixture as ir} from "../../test/ir-model.fixtures.test-utils"
import type {OpenapiLoader} from "../loaders/openapi-loader"
import type {Parameter} from "../openapi-types"
import {defaultSyntheticNameGenerator} from "../synthetic-name-generator"
import {ParameterNormalizer} from "./parameter-normalizer"
import {SchemaNormalizer} from "./schema-normalizer"
import { FakeSchemaProvider } from "../../test/fake-schema-provider"

describe("ParameterNormalizer", () => {
let loader: jest.Mocked<OpenapiLoader>
let fakeSchemaProvider: FakeSchemaProvider
let schemaNormalizer: SchemaNormalizer
let parameterNormalizer: ParameterNormalizer

Expand All @@ -18,10 +20,12 @@
addVirtualType: jest.fn(),
} as unknown as jest.Mocked<OpenapiLoader>

fakeSchemaProvider = new FakeSchemaProvider()

schemaNormalizer = new SchemaNormalizer({
extractInlineSchemas: true,
enumExtensibility: "open",
})
}, fakeSchemaProvider)

parameterNormalizer = new ParameterNormalizer(
loader,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import {describe, expect, it} from "@jest/globals"
import {beforeEach, describe, expect, it} from "@jest/globals"
import {FakeSchemaProvider} from "../../test/fake-schema-provider"
import {irFixture as ir} from "../../test/ir-model.fixtures.test-utils"
import {generationLib} from "../generation-lib"
import {SchemaNormalizer} from "./schema-normalizer"

describe("core/input - SchemaNormalizer", () => {
const schemaNormalizer = new SchemaNormalizer({
extractInlineSchemas: true,
enumExtensibility: "open",
let schemaProvider: FakeSchemaProvider
let schemaNormalizer: SchemaNormalizer

beforeEach(() => {
schemaProvider = new FakeSchemaProvider()
schemaNormalizer = new SchemaNormalizer(
{
extractInlineSchemas: true,
enumExtensibility: "open",
},
schemaProvider,
)
})

it("passes through $ref untouched", () => {
Expand Down Expand Up @@ -514,6 +524,135 @@ describe("core/input - SchemaNormalizer", () => {
})
})

describe("discriminator", () => {
describe("all alternatives are $ref of type: object", () => {
it("supports mapping", () => {
schemaProvider.registerTestRef(
ir.ref("/components/schemas/Foo"),
ir.object({properties: {type: ir.string()}}),
)
schemaProvider.registerTestRef(
ir.ref("/components/schemas/Bar"),
ir.object({properties: {type: ir.string()}}),
)

const actual = schemaNormalizer.normalize({
type: "object",
discriminator: {
propertyName: "type",
mapping: {
foo: "#/components/schemas/Foo",
bar: "#/components/schemas/Bar",
},
},
oneOf: [
{$ref: "#/components/schemas/Foo"},
{$ref: "#/components/schemas/Bar"},
],
})

expect(actual).toStrictEqual(
ir.union({
discriminator: {
propertyName: "type",
mapping: {
foo: ir.ref("/components/schemas/Foo"),
bar: ir.ref("/components/schemas/Bar"),
},
},
schemas: [
ir.ref("/components/schemas/Foo"),
ir.ref("/components/schemas/Bar"),
],
}),
)
})

it("infers a mapping when none provided", () => {
schemaProvider.registerTestRef(
ir.ref("/components/schemas/Foo"),
ir.object({properties: {type: ir.string()}}),
)
schemaProvider.registerTestRef(
ir.ref("/components/schemas/Bar"),
ir.object({properties: {type: ir.string()}}),
)

const actual = schemaNormalizer.normalize({
type: "object",
discriminator: {
propertyName: "type",
},
oneOf: [
{$ref: "#/components/schemas/Foo"},
{$ref: "#/components/schemas/Bar"},
],
})

expect(actual).toStrictEqual(
ir.union({
discriminator: {
propertyName: "type",
mapping: {
Foo: ir.ref("/components/schemas/Foo"),
Bar: ir.ref("/components/schemas/Bar"),
},
},
schemas: [
ir.ref("/components/schemas/Foo"),
ir.ref("/components/schemas/Bar"),
],
}),
)
})
})

it("ignores the discriminator property where some alternatives are not type: object", () => {})

it("ignores the discriminator property where no composition is defined", () => {
const actual = schemaNormalizer.normalize({
type: "object",
properties: {
name: {type: "string"},
type: {type: "string"},
},
discriminator: {
propertyName: "type",
mapping: {
foo: "#/components/schemas/Foo",
bar: "#/components/schemas/Bar",
},
},
})

expect(actual).toStrictEqual(
ir.object({properties: {name: ir.string(), type: ir.string()}}),
)
})

it("ignores the discriminator property where some alternatives are inline schemas", () => {
const actual = schemaNormalizer.normalize({
type: "object",
discriminator: {
propertyName: "type",
},
oneOf: [
{type: "object", properties: {type: {type: "string"}}},
{$ref: "#/components/schemas/Bar"},
],
})

expect(actual).toStrictEqual(
ir.union({
schemas: [
ir.object({properties: {type: ir.string()}}),
ir.ref("/components/schemas/Bar"),
],
}),
)
})
})

describe("empty schemas / additionalProperties", () => {
it("translates '{}' to an any", () => {
const actual = schemaNormalizer.normalize({})
Expand Down
Loading
Loading