Packages
oaspec
0.65.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/codegen/ir.gleam
/// Gleam Code IR - intermediate representation for generated Gleam source files.
/// This separates schema semantics from text rendering, preventing the
/// duplication of logic across types/decoders/client generators.
import gleam/option.{type Option}
/// A complete generated Gleam source file.
///
/// Opaque: construct via `module/3`, read via `module_header/1`,
/// `module_imports/1`, and `module_declarations/1`. The internal shape
/// can then evolve (e.g. to track file-level doc comments) without
/// rippling into every renderer pass.
pub opaque type Module {
Module(
header: String,
imports: List(String),
declarations: List(Declaration),
header_records: List(ResponseHeaderRecord),
)
}
/// Construct a `Module` from its three component pieces.
pub fn module(
header header: String,
imports imports: List(String),
declarations declarations: List(Declaration),
) -> Module {
Module(header:, imports:, declarations:, header_records: [])
}
/// Construct a `Module` with header records.
pub fn module_with_header_records(
header header: String,
imports imports: List(String),
declarations declarations: List(Declaration),
header_records header_records: List(ResponseHeaderRecord),
) -> Module {
Module(header:, imports:, declarations:, header_records:)
}
/// Module imports, in the order they should be rendered.
pub fn module_imports(m: Module) -> List(String) {
m.imports
}
/// Top-level declarations inside the module.
pub fn module_declarations(m: Module) -> List(Declaration) {
m.declarations
}
/// A top-level declaration with optional doc comment.
///
/// Opaque: construct via `declaration/2`, read via `declaration_doc/1`
/// and `declaration_type_def/1`.
pub opaque type Declaration {
Declaration(doc: Option(String), type_def: TypeDef)
}
/// Construct a `Declaration` from its optional doc and type definition.
pub fn declaration(
doc doc: Option(String),
type_def type_def: TypeDef,
) -> Declaration {
Declaration(doc:, type_def:)
}
/// Optional doc comment attached to this declaration.
pub fn declaration_doc(d: Declaration) -> Option(String) {
d.doc
}
/// The type definition carried by this declaration.
pub fn declaration_type_def(d: Declaration) -> TypeDef {
d.type_def
}
/// The shapes of type definition that the OpenAPI generator produces.
pub type TypeDef {
/// `pub type Foo = Bar`
TypeAlias(name: String, target: String)
/// `pub type Foo { Foo(field1: Type1, field2: Type2) }`
RecordType(name: String, fields: List(Field))
/// `pub type Foo { FooBar(Bar) FooBaz(Baz) }`
UnionType(name: String, variants: List(Variant))
/// `pub type Status { StatusActive StatusInactive }`
EnumType(name: String, variants: List(String))
}
/// A named, typed field in a record constructor.
pub type Field {
Field(name: String, type_expr: String)
}
/// A variant in a union type.
pub type Variant {
/// Variant with a wrapped type: `FooBar(Bar)`
VariantWithType(name: String, inner_type: String)
/// Variant with no payload: `FooNone`
VariantEmpty(name: String)
/// Response variant carrying a body and a typed headers record:
/// `FooBar(Bar, FooBarHeaders)` (issue #306).
VariantWithTypeAndHeaders(
name: String,
inner_type: String,
headers_type: String,
)
/// Response variant carrying only a typed headers record (no body):
/// `FooBar(FooBarHeaders)` (issue #306).
VariantWithHeaders(name: String, headers_type: String)
/// Response variant for the OpenAPI `default` catch-all. Always
/// carries an Int status code as the first positional field, so
/// handlers can pick any 4xx/5xx for the catch-all branch instead
/// of the router pinning every response to 500. The body and
/// headers types are optional, mirroring the four shapes of the
/// other variant kinds (issue #483):
///
/// * neither → `FooDefault(Int)`
/// * body only → `FooDefault(Int, Body)`
/// * headers only → `FooDefault(Int, FooDefaultHeaders)`
/// * body + headers → `FooDefault(Int, Body, FooDefaultHeaders)`
VariantDefault(
name: String,
inner_type: Option(String),
headers_type: Option(String),
)
}
/// A typed record for response headers.
pub type ResponseHeaderRecord {
ResponseHeaderRecord(name: String, fields: List(Field))
}
/// Response header records inside the module.
pub fn module_header_records(m: Module) -> List(ResponseHeaderRecord) {
m.header_records
}