Packages
oaspec
0.60.0
0.68.0
0.67.0
0.66.0
0.65.0
0.64.0
0.63.0
0.62.0
0.61.0
0.60.0
0.59.0
0.58.1
0.58.0
0.57.0
0.56.0
0.55.0
0.54.0
0.53.0
0.52.0
0.51.0
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.0
0.42.0
0.41.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.0
0.9.0
0.8.0
0.7.0
0.6.3
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.1.3
Generate Gleam code from OpenAPI 3.x specifications
Current section
Files
Jump to
Current section
Files
src/oaspec/internal/openapi/schema.gleam
import gleam/dict.{type Dict}
import gleam/list
import gleam/option.{type Option}
import gleam/result
import gleam/string
import oaspec/internal/openapi/value.{type JsonValue}
/// Origin of a schema — user-authored or hoisted during codegen.
/// Hoisted variants carry the call-site context so tooling can explain
/// where synthetic component schemas came from.
pub type OriginKind {
UserAuthored
HoistedProperty(parent: String, property: String)
HoistedArrayItem(parent: String)
HoistedOneOfVariant(parent: String, index: Int)
HoistedAnyOfVariant(parent: String, index: Int)
HoistedAllOfPart(parent: String, index: Int)
HoistedRequestBody(operation_id: String)
HoistedResponse(operation_id: String, status: String)
HoistedParameter(operation_id: String, name: String)
HoistedAdditionalProperties(parent: String)
}
/// Shared metadata for all schema types.
/// Extracted from variants to avoid duplication and ensure composition
/// schemas (allOf/oneOf/anyOf) don't lose these fields.
pub type SchemaMetadata {
SchemaMetadata(
description: Option(String),
nullable: Bool,
deprecated: Bool,
title: Option(String),
read_only: Bool,
write_only: Bool,
default: Option(JsonValue),
example: Option(JsonValue),
const_value: Option(JsonValue),
raw_type: Option(List(String)),
unsupported_keywords: List(String),
internal: Bool,
provenance: OriginKind,
)
}
/// Create default metadata with no description, not nullable, not deprecated.
pub fn default_metadata() -> SchemaMetadata {
SchemaMetadata(
description: option.None,
nullable: False,
deprecated: False,
title: option.None,
read_only: False,
write_only: False,
default: option.None,
example: option.None,
const_value: option.None,
raw_type: option.None,
unsupported_keywords: [],
internal: False,
provenance: UserAuthored,
)
}
/// How additionalProperties is modeled in the AST.
pub type AdditionalProperties {
/// additionalProperties: false (extra keys rejected)
Forbidden
/// additionalProperties: true (accept any JSON value, surfaced in
/// generated types as `Dict(String, Dynamic)`)
Untyped
/// additionalProperties: { schema } (typed dict in generated types)
Typed(SchemaRef)
/// additionalProperties key absent from the spec. Per JSON Schema
/// any extra keys are still permitted at runtime, but the generated
/// record does not surface them — users opt in by writing `true` or
/// a schema explicitly.
Unspecified
}
/// Represents a JSON Schema object within OpenAPI 3.x.
/// This is the core building block for all type generation.
/// All variants carry shared `metadata` for description, nullable, deprecated.
pub type SchemaObject {
StringSchema(
metadata: SchemaMetadata,
format: Option(String),
enum_values: List(String),
min_length: Option(Int),
max_length: Option(Int),
pattern: Option(String),
)
IntegerSchema(
metadata: SchemaMetadata,
format: Option(String),
minimum: Option(Int),
maximum: Option(Int),
exclusive_minimum: Option(Int),
exclusive_maximum: Option(Int),
multiple_of: Option(Int),
)
NumberSchema(
metadata: SchemaMetadata,
format: Option(String),
minimum: Option(Float),
maximum: Option(Float),
exclusive_minimum: Option(Float),
exclusive_maximum: Option(Float),
multiple_of: Option(Float),
)
BooleanSchema(metadata: SchemaMetadata)
ArraySchema(
metadata: SchemaMetadata,
items: SchemaRef,
min_items: Option(Int),
max_items: Option(Int),
unique_items: Bool,
)
ObjectSchema(
metadata: SchemaMetadata,
properties: Dict(String, SchemaRef),
required: List(String),
additional_properties: AdditionalProperties,
min_properties: Option(Int),
max_properties: Option(Int),
)
AllOfSchema(metadata: SchemaMetadata, schemas: List(SchemaRef))
OneOfSchema(
metadata: SchemaMetadata,
schemas: List(SchemaRef),
discriminator: Option(Discriminator),
)
AnyOfSchema(
metadata: SchemaMetadata,
schemas: List(SchemaRef),
discriminator: Option(Discriminator),
)
}
/// A reference to a schema, either inline or via $ref.
/// Reference carries both the full $ref string and the pre-extracted name
/// (last segment) to eliminate repeated string splitting in codegen.
pub type SchemaRef {
Inline(SchemaObject)
Reference(ref: String, name: String)
}
/// Create a Reference from a $ref string, auto-extracting the name.
pub fn make_reference(ref: String) -> SchemaRef {
let name = ref_to_schema_name(ref)
Reference(ref:, name:)
}
/// Extract the schema name from a $ref string (last path segment).
/// Example: "#/components/schemas/User" -> "User"
fn ref_to_schema_name(ref: String) -> String {
case string.split(ref, "/") {
[] -> "Unknown"
segments ->
list.last(segments)
|> result.unwrap("Unknown")
}
}
/// OpenAPI discriminator for oneOf/anyOf.
pub type Discriminator {
Discriminator(property_name: String, mapping: Dict(String, String))
}
/// Check if a schema is nullable.
pub fn is_nullable(schema: SchemaObject) -> Bool {
get_metadata(schema).nullable
}
/// Extract the shared metadata from any schema variant.
pub fn get_metadata(schema: SchemaObject) -> SchemaMetadata {
case schema {
StringSchema(metadata:, ..) -> metadata
IntegerSchema(metadata:, ..) -> metadata
NumberSchema(metadata:, ..) -> metadata
BooleanSchema(metadata:) -> metadata
ArraySchema(metadata:, ..) -> metadata
ObjectSchema(metadata:, ..) -> metadata
AllOfSchema(metadata:, ..) -> metadata
OneOfSchema(metadata:, ..) -> metadata
AnyOfSchema(metadata:, ..) -> metadata
}
}
/// Mark a schema as internal (not part of the public generated API).
pub fn set_internal(schema: SchemaObject) -> SchemaObject {
let meta = get_metadata(schema)
let meta = SchemaMetadata(..meta, internal: True)
set_metadata(schema, meta)
}
/// Stamp the origin of a hoisted schema onto its metadata so downstream
/// consumers (diagnostics, tooling) can distinguish user-authored schemas
/// from synthetic ones created during the hoist pass.
pub fn set_provenance(schema: SchemaObject, origin: OriginKind) -> SchemaObject {
let meta = get_metadata(schema)
let meta = SchemaMetadata(..meta, provenance: origin)
set_metadata(schema, meta)
}
/// Read the provenance of a schema. Unhoisted schemas return `UserAuthored`.
pub fn get_provenance(schema: SchemaObject) -> OriginKind {
get_metadata(schema).provenance
}
/// Replace the metadata on a schema object.
pub fn set_metadata(schema: SchemaObject, meta: SchemaMetadata) -> SchemaObject {
case schema {
StringSchema(format:, enum_values:, min_length:, max_length:, pattern:, ..) ->
StringSchema(
metadata: meta,
format:,
enum_values:,
min_length:,
max_length:,
pattern:,
)
IntegerSchema(
format:,
minimum:,
maximum:,
exclusive_minimum:,
exclusive_maximum:,
multiple_of:,
..,
) ->
IntegerSchema(
metadata: meta,
format:,
minimum:,
maximum:,
exclusive_minimum:,
exclusive_maximum:,
multiple_of:,
)
NumberSchema(
format:,
minimum:,
maximum:,
exclusive_minimum:,
exclusive_maximum:,
multiple_of:,
..,
) ->
NumberSchema(
metadata: meta,
format:,
minimum:,
maximum:,
exclusive_minimum:,
exclusive_maximum:,
multiple_of:,
)
BooleanSchema(..) -> BooleanSchema(metadata: meta)
ArraySchema(items:, min_items:, max_items:, unique_items:, ..) ->
ArraySchema(metadata: meta, items:, min_items:, max_items:, unique_items:)
ObjectSchema(
properties:,
required:,
additional_properties:,
min_properties:,
max_properties:,
..,
) ->
ObjectSchema(
metadata: meta,
properties:,
required:,
additional_properties:,
min_properties:,
max_properties:,
)
AllOfSchema(schemas:, ..) -> AllOfSchema(metadata: meta, schemas:)
OneOfSchema(schemas:, discriminator:, ..) ->
OneOfSchema(metadata: meta, schemas:, discriminator:)
AnyOfSchema(schemas:, discriminator:, ..) ->
AnyOfSchema(metadata: meta, schemas:, discriminator:)
}
}