Merge commit '36c66dd290d3ce6eb1ccd310d0c658d4a32bb8eb' as 'repos/effect'
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
import * as JsonSchemaGenerator from "@effect/openapi-generator/JsonSchemaGenerator"
|
||||
import { describe, expect, it } from "@effect/vitest"
|
||||
|
||||
describe("JsonSchemaGenerator", () => {
|
||||
it("schema & no definitions", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { type: "string" })
|
||||
const definitions = {}
|
||||
const result = generator.generate("openapi-3.1", definitions, false)
|
||||
expect(result).toBe(`// schemas
|
||||
export type A = string
|
||||
export const A = Schema.String
|
||||
`)
|
||||
})
|
||||
|
||||
it("schema & definitions", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { $ref: "#/components/schemas/B" })
|
||||
const definitions = {
|
||||
B: { type: "string" }
|
||||
}
|
||||
const result = generator.generate("openapi-3.1", definitions, false)
|
||||
expect(result).toBe(`// non-recursive definitions
|
||||
export type B = string
|
||||
export const B = Schema.String
|
||||
// schemas
|
||||
export type A = B
|
||||
export const A = B
|
||||
`)
|
||||
})
|
||||
|
||||
it("onEnter strips specified keys", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { type: "string", description: "desc", examples: ["ex"] })
|
||||
const definitions = {}
|
||||
const result = generator.generate("openapi-3.1", definitions, false, {
|
||||
onEnter: (js) => {
|
||||
const out = { ...js }
|
||||
delete out.examples
|
||||
return out
|
||||
}
|
||||
})
|
||||
expect(result).toBe(`// schemas
|
||||
export type A = string
|
||||
export const A = Schema.String.annotate({ "description": "desc" })
|
||||
`)
|
||||
})
|
||||
|
||||
it("default preserves all annotations", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { type: "string", description: "desc", examples: ["ex"] })
|
||||
const definitions = {}
|
||||
const result = generator.generate("openapi-3.1", definitions, false)
|
||||
expect(result).toBe(`// schemas
|
||||
export type A = string
|
||||
export const A = Schema.String.annotate({ "description": "desc", "examples": ["ex"] })
|
||||
`)
|
||||
})
|
||||
|
||||
it("generateHttpApi emits explicit type and const declarations", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { type: "string" })
|
||||
generator.addSchema("B", {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: {
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
required: ["id"],
|
||||
additionalProperties: false
|
||||
})
|
||||
|
||||
const result = generator.generateHttpApi("openapi-3.1", {})
|
||||
|
||||
expect(result).toContain(`export type A = string
|
||||
export const A = Schema.String`)
|
||||
expect(result).toContain(`export type B = { readonly "id": string }
|
||||
export const B = Schema.Struct({ "id": Schema.String })`)
|
||||
expect(result).not.toContain("Schema.Class<")
|
||||
expect(result).not.toContain("Schema.Opaque<")
|
||||
})
|
||||
|
||||
it("recursive schema", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { $ref: "#/components/schemas/B" })
|
||||
const definitions = {
|
||||
B: {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"children": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/B"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"children"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
const result = generator.generate("openapi-3.1", definitions, false)
|
||||
expect(result).toBe(`// recursive definitions
|
||||
export type B = { readonly "name": string, readonly "children": ReadonlyArray<B> }
|
||||
export const B = Schema.Struct({ "name": Schema.String, "children": Schema.Array(Schema.suspend((): Schema.Codec<B> => B)) })
|
||||
// schemas
|
||||
export type A = B
|
||||
export const A = B
|
||||
`)
|
||||
})
|
||||
|
||||
it("hoists recursive definitions referenced by earlier recursive definitions", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { $ref: "#/components/schemas/ResourcesNetworkCard" })
|
||||
const definitions = {
|
||||
ResourcesNetworkCard: {
|
||||
type: "object",
|
||||
properties: {
|
||||
sriov: {
|
||||
$ref: "#/components/schemas/ResourcesNetworkCardSRIOV"
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
},
|
||||
ResourcesNetworkCardSRIOV: {
|
||||
type: "object",
|
||||
properties: {
|
||||
vfs: {
|
||||
type: "array",
|
||||
items: {
|
||||
$ref: "#/components/schemas/ResourcesNetworkCard"
|
||||
}
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
}
|
||||
|
||||
const result = generator.generate("openapi-3.1", definitions, false)
|
||||
const recursiveDeclaration =
|
||||
"export const ResourcesNetworkCardSRIOV = Schema.suspend((): Schema.Codec<ResourcesNetworkCardSRIOV> => __recursive_ResourcesNetworkCardSRIOV)"
|
||||
|
||||
expect(result).toContain(recursiveDeclaration)
|
||||
expect(result).toContain("const __recursive_ResourcesNetworkCardSRIOV =")
|
||||
expect(result.indexOf(recursiveDeclaration)).toBeLessThan(
|
||||
result.indexOf("export const ResourcesNetworkCard =")
|
||||
)
|
||||
expect(result.indexOf("export const ResourcesNetworkCard =")).toBeLessThan(
|
||||
result.indexOf("const __recursive_ResourcesNetworkCardSRIOV =")
|
||||
)
|
||||
})
|
||||
|
||||
it("renders recursive definitions before non-recursive references for runtime generation", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { $ref: "#/components/schemas/ErrorResponse" })
|
||||
const definitions = {
|
||||
InnerErrors: {
|
||||
type: "object",
|
||||
properties: {
|
||||
field: {
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
required: ["field"],
|
||||
additionalProperties: false
|
||||
},
|
||||
ErrorDetails: {
|
||||
oneOf: [
|
||||
{
|
||||
type: "object",
|
||||
additionalProperties: {
|
||||
$ref: "#/components/schemas/ErrorDetails"
|
||||
}
|
||||
},
|
||||
{
|
||||
$ref: "#/components/schemas/InnerErrors"
|
||||
}
|
||||
]
|
||||
},
|
||||
ErrorResponse: {
|
||||
type: "object",
|
||||
properties: {
|
||||
errors: {
|
||||
$ref: "#/components/schemas/ErrorDetails"
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
}
|
||||
|
||||
const runtimeResult = generator.generate("openapi-3.1", definitions, false)
|
||||
const recursiveDeclaration =
|
||||
"export const ErrorDetails = Schema.suspend((): Schema.Codec<ErrorDetails> => __recursive_ErrorDetails)"
|
||||
|
||||
expect(runtimeResult).toContain(recursiveDeclaration)
|
||||
expect(runtimeResult).toContain("const __recursive_ErrorDetails =")
|
||||
expect(runtimeResult.indexOf(recursiveDeclaration)).toBeLessThan(
|
||||
runtimeResult.indexOf("export const ErrorResponse =")
|
||||
)
|
||||
|
||||
const httpApiResult = generator.generateHttpApi("openapi-3.1", definitions)
|
||||
expect(httpApiResult).toContain(recursiveDeclaration)
|
||||
expect(httpApiResult).toContain("const __recursive_ErrorDetails =")
|
||||
expect(httpApiResult.indexOf(recursiveDeclaration)).toBeLessThan(
|
||||
httpApiResult.indexOf("export const ErrorResponse =")
|
||||
)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user