Help us shape the future of Go! Take the 2026 Go Developer Survey

schemacompiler

package module
v0.0.0-...-bcd69c7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 4, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

README

schemacompiler Go Reference codecov alpha

Compiles JSON Schema Draft 2020-12 into an analyzed plan that a code generator (such as ogen) lowers into Go types, decoders, and validators.

Status: alpha. The API is unstable and the compiler targets a well-defined subset; unsupported constructs are reported as diagnostics rather than mis-compiled.

What it does

JSON Schema is a predicate language, not a type language: many schemas describe constraints an ordinary Go type cannot express, while others collapse into a direct type or a finite static dispatch. schemacompiler separates the four concerns and produces an analyzed plan.CompilationPlan rather than emitting Go directly:

  • Representation — the Go data shape (string, struct, union, …).
  • Validation — residual, kind-guarded predicates the type cannot enforce.
  • Dispatch — how a value selects among known alternatives (kind / literal / tagged property / match-count).
  • Resolution — how $ref / $dynamicRef targets are resolved.

Each plan is classified on a capability ladder, so a backend knows exactly how far a schema can be lowered soundly.

Capability Meaning
DirectGoType a plain Go type captures the value; no validator needed
GoTypeWithValidation known type plus residual predicates
StaticDispatch finite alternatives, discriminated at compile time
RawEvaluation the check needs the raw JSON, not just the decoded value
EvaluationStateValidation needs unevaluatedProperties / unevaluatedItems tracking
DynamicSchemaResolution target depends on runtime $dynamicRef scope
Unsupported no sound conversion

The compiler never generates an under-approximate type: when an exact representation is impossible it widens to a broad type plus an exact residual validator, and records a diagnostic explaining why.

Usage

res, err := schemacompiler.Compile(ctx, schemaBytes, schemacompiler.Options{})
if err != nil {
    // only malformed input fails; a dangling $ref is a diagnostic, not an error
}
fmt.Println(res.Capability, res.Diagnostics)
for _, d := range res.Diagnostics {
    fmt.Println(d.Severity, d.Position, d.Pointer, d.Message)
}

An OpenAPI 3.1 document already parsed by libopenapi is compiled without re-parsing:

doc := schemacompiler.Document{Schemas: model.Model.Components.Schemas}
res, err := schemacompiler.CompileDocument(ctx, doc, schemacompiler.Options{})
plan := res.Plans["/components/schemas/Pet"]

CompileDocument compiles the whole component set against one registry, so $refs between siblings resolve and recursion is classified across components; CompileSchema does the same for a single *base.SchemaProxy. libopenapi is otherwise isolated behind the internal frontend adapter.

Debugging: cmd/schemac

Inspect each stage of the pipeline for a schema:

go run ./cmd/schemac -all schema.json                     # IR, normalized IR, plan, graphs
go run ./cmd/schemac -graph schema.json | dot -Tsvg > refs.svg    # reference graph
go run ./cmd/schemac -plangraph schema.json | dot -Tsvg > plan.svg # dispatch tree
  • -graph renders the reference graph (solid = instance descent, dashed = logical edge; recursive components colored green = guarded, red = unguarded).
  • -plangraph renders the dispatch tree (how a value routes through kind/literal/ property dispatch to representations).

Architecture

load + resolve ──► semantic IR ──► normalize ──► plans + classify ──► Result
   (frontend)        (ir)           (norm)          (planner)

See docs/implementation.md for the design and invariants, docs/integration.md for how a generator consumes the plan, and the reference design in _ref/.

License

Apache-2.0 — see LICENSE.

Documentation

Overview

Package schemacompiler compiles JSON Schema Draft 2020-12 into an analyzed plan.CompilationPlan that a code generator lowers into Go types, decoders, and validators.

It is a frontend/analysis library: it stops at the analyzed plan and does not emit Go source. See docs/implementation.md for the architecture.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Document

type Document struct {
	// BaseURI is the retrieval URI of the document, used to resolve relative $ref/$id.
	// An empty value falls back to [Options.BaseURI].
	BaseURI string
	// Schemas is the document's `components.schemas`, already parsed by libopenapi.
	Schemas *orderedmap.Map[string, *base.SchemaProxy]
}

Document is an OpenAPI component schema set to compile as a whole.

type DocumentResult

type DocumentResult struct {
	// Plans holds one analyzed plan per named schema, keyed by its JSON Pointer
	// (`/components/schemas/<name>`), plus a plan for every other static $ref target
	// reachable from them. It is the document's reference graph: a
	// [plan.ReferenceRepresentation] name is a key into it, so every component plan is
	// [plan.FullyResolved] rather than carrying a graph of its own.
	Plans map[plan.SchemaID]plan.CompilationPlan
	// Capability is the worst capability level over every plan.
	Capability plan.CapabilityLevel
	// Requirements is what the document's plans ask of whatever lowers them, unioned
	// over every component and every reachable $ref target (design §25).
	Requirements plan.Requirements
	// Diagnostics explain what the compiler could not do, and what that costs: see
	// [plan.DiagnosticKind].
	Diagnostics []plan.Diagnostic
}

DocumentResult is the output of compiling a whole document (design §25).

func CompileDocument

func CompileDocument(ctx context.Context, doc Document, opts Options) (*DocumentResult, error)

CompileDocument compiles an OpenAPI document's component schemas as one unit: all of them share a single registry, so `$ref`s between siblings resolve and recursion is classified across component boundaries.

type Loader

type Loader func(ctx context.Context, uri *url.URL) ([]byte, error)

Loader fetches the raw bytes of an external schema document identified by uri (an absolute URI with the fragment removed). It is invoked lazily during reference resolution for any $ref whose target document is not the root schema. Callers supply the transport (filesystem, HTTP, an in-memory map, ...). A nil Options.Loader leaves external references unresolved and reported as diagnostics.

type Options

type Options struct {
	// BaseURI is the retrieval URI of the root schema, used to resolve relative $ref/$id.
	BaseURI string
	// ExpansionBudget bounds combinator expansion during normalization; when exceeded a
	// factored raw-evaluation form is preserved instead of exponential IR (design §21).
	// Zero selects a conservative default.
	ExpansionBudget int
	// Loader resolves external/remote $ref documents. When nil, only in-document references
	// resolve and external ones are reported as diagnostics.
	Loader Loader
}

Options configures a compilation.

type Result

type Result struct {
	// Plan is the analyzed compilation plan for the root schema.
	Plan plan.CompilationPlan
	// Capability mirrors Plan.Capability for convenience.
	Capability plan.CapabilityLevel
	// Requirements is what the plan asks of whatever lowers it (design §25).
	Requirements plan.Requirements
	// Diagnostics explain what the compiler could not do, and what that costs: see
	// [plan.DiagnosticKind].
	Diagnostics []plan.Diagnostic
}

Result is the public output of compilation (design §25).

func Compile

func Compile(ctx context.Context, data []byte, opts Options) (*Result, error)

Compile parses, resolves, normalizes, and analyzes a single JSON Schema document.

data is a standalone Draft 2020-12 schema (JSON or YAML). Callers that already hold a parsed libopenapi schema (e.g. ogen) should use CompileSchema or CompileDocument rather than re-serializing.

func CompileSchema

func CompileSchema(ctx context.Context, sp *base.SchemaProxy, opts Options) (*Result, error)

CompileSchema compiles a single already-parsed libopenapi schema, the join point for a caller that holds one component rather than a whole document (e.g. ogen). References to sibling components stay unresolved: use CompileDocument to resolve those.

Directories

Path Synopsis
cmd
schemac command
Command schemac is a debugging CLI for the schemacompiler pipeline.
Command schemac is a debugging CLI for the schemacompiler pipeline.
Package gogen lowers an analyzed plan.CompilationPlan into Go types.
Package gogen lowers an analyzed plan.CompilationPlan into Go types.
internal
dump
Package dump renders compiler pipeline stages (ir.Expr, plan.CompilationPlan) as deterministic, human-readable indented text trees, for debugging and golden tests.
Package dump renders compiler pipeline stages (ir.Expr, plan.CompilationPlan) as deterministic, human-readable indented text trees, for debugging and golden tests.
ecmaregex
Package ecmaregex matches JSON Schema patterns with the language JSON Schema writes them in.
Package ecmaregex matches JSON Schema patterns with the language JSON Schema writes them in.
frontend
Package frontend is the only package permitted to import the parser (libopenapi).
Package frontend is the only package permitted to import the parser (libopenapi).
gorun
Package gorun compiles a generated package and runs it.
Package gorun compiles a generated package and runs it.
gotypecheck
Package gotypecheck type-checks generated Go source.
Package gotypecheck type-checks generated Go source.
ir
Package ir is the semantic intermediate representation of a JSON Schema (design §5).
Package ir is the semantic intermediate representation of a JSON Schema (design §5).
jsonequal
Package jsonequal compares two JSON values for semantic equality (order-independent objects, exact numeric comparison via big.Rat).
Package jsonequal compares two JSON values for semantic equality (order-independent objects, exact numeric comparison via big.Rat).
nodetree
Package nodetree compiles a plan.CompilationPlan into a tree of executable nodes and validates raw JSON against it, without decoding the instance into `any`.
Package nodetree compiles a plan.CompilationPlan into a tree of executable nodes and validates raw JSON against it, without decoding the instance into `any`.
norm
Package norm normalizes the semantic IR (ir.Expr) toward a simplified, analyzable form while preserving exact JSON Schema semantics (design §15).
Package norm normalizes the semantic IR (ir.Expr) toward a simplified, analyzable form while preserving exact JSON Schema semantics (design §15).
planner
Package planner turns a normalized ir.Expr into an analyzed plan.CompilationPlan (design §21, §22): it infers a Go plan.Representation, extracts residual plan.ValidationPlan predicates, builds a plan.DispatchPlan for combinators, a plan.ResolutionPlan for references, and classifies the result into the plan.CapabilityLevel ladder while enforcing the v1 scope (docs/implementation.md).
Package planner turns a normalized ir.Expr into an analyzed plan.CompilationPlan (design §21, §22): it infers a Go plan.Representation, extracts residual plan.ValidationPlan predicates, builds a plan.DispatchPlan for combinators, a plan.ResolutionPlan for references, and classifies the result into the plan.CapabilityLevel ladder while enforcing the v1 scope (docs/implementation.md).
planterp
Package planterp interprets a plan.CompilationPlan as a JSON validator, for differential testing against the JSON-Schema-Test-Suite (issue #70).
Package planterp interprets a plan.CompilationPlan as a JSON validator, for differential testing against the JSON-Schema-Test-Suite (issue #70).
planwalk
Package planwalk is the single structural traversal of the plan types (issue #47).
Package planwalk is the single structural traversal of the plan types (issue #47).
scc
Package scc computes the strongly connected components of a directed graph.
Package scc computes the strongly connected components of a directed graph.
Package opt carries the three-state presence and nullability model JSON Schema needs (design §7.1, §12.2), for generated code to store fields in.
Package opt carries the three-state presence and nullability model JSON Schema needs (design §7.1, §12.2), for generated code to store fields in.
Package plan defines the analyzed compilation plan produced by schemacompiler and consumed by a code generator (ogen).
Package plan defines the analyzed compilation plan produced by schemacompiler and consumed by a code generator (ogen).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL