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

schemaform

package
v1.21.83 Latest Latest
Warning

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

Go to latest
Published: Oct 25, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Overview

Package schemaform renders a JSON Schema as an interactive terminal form (charmbracelet/huh) with the semantics of clicky-ui's JsonSchemaForm: the same widget resolution, `x-*` extensions, `allOf` if/then/else branches, `x-discriminator` and `x-on-change`/`x-on-load` listeners. One schema therefore drives both the web form and the terminal form.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoInput = errors.New("input ended before the form was complete")

ErrNoInput is returned in accessible mode when the input ends before a required or invalid field has a valid answer.

Functions

func ApplyDefaults

func ApplyDefaults(schema *Schema, value map[string]any) map[string]any

ApplyDefaults fills missing values from `default` keywords. It walks fixed object properties recursively and re-evaluates if/then branches after each pass, so a defaulted discriminator can activate defaults in its selected branch. Existing values, including null and empty strings, are never replaced. value is not mutated.

func Run

func Run(ctx context.Context, raw json.RawMessage, opts Options) (map[string]any, error)

Run parses a JSON Schema and collects a value for it interactively. The result is JSON-shaped (numbers are float64), excludes empty values and the values of inactive branches, and satisfies every field's constraints.

func RunSchema

func RunSchema(ctx context.Context, schema *Schema, opts Options) (map[string]any, error)

RunSchema is Run for an already parsed schema.

Types

type ChangeActions

type ChangeActions struct {
	Hide     []string                   `json:"hide,omitempty"`
	Show     []string                   `json:"show,omitempty"`
	Enable   []string                   `json:"enable,omitempty"`
	Disable  []string                   `json:"disable,omitempty"`
	Require  []string                   `json:"require,omitempty"`
	Optional []string                   `json:"optional,omitempty"`
	Reset    []string                   `json:"reset,omitempty"`
	Set      map[string]any             `json:"set,omitempty"`
	Patch    map[string]json.RawMessage `json:"patch,omitempty"`
}

ChangeActions names what a listener does to sibling fields.

type Condition

type Condition struct {
	Predicate *Schema
	Expr      string
	HasExpr   bool
}

Condition is the if-style predicate (const/enum/not/properties/required) on the listener's subject, plus an optional CEL Expr; both must hold.

func (*Condition) UnmarshalJSON

func (c *Condition) UnmarshalJSON(data []byte) error

type Control

type Control struct {
	Kind    Kind
	Options []Option
	// Branch is the native schema a value-or-template union renders as.
	Branch *Schema
}

Control is a property resolved to a render-ready control.

func ResolveControl

func ResolveControl(prop *Schema) Control

ResolveControl infers the control from a property schema's keywords (never its name), first match wins — the same precedence as clicky-ui's resolveControl.

type Evaluator

type Evaluator func(ExprInput) (any, error)

Evaluator evaluates a `when.expr`; it must return a bool.

func FilterEvaluator

func FilterEvaluator() Evaluator

FilterEvaluator evaluates `when.expr` with the configured filter adapter (celfilter.Use or gomplatefilter.Use). Compiled predicates are cached.

type ExprInput

type ExprInput struct {
	Expr  string
	Key   string
	Value any
	Self  map[string]any
	Root  map[string]any
}

ExprInput is what a `when.expr` sees: the source key and its value, the object holding it (self) and the form's whole value (root).

type Help

type Help struct {
	Body string `json:"body,omitempty"`
}

Help is the `x-help` extension; Body is appended to the description.

type ItemSpec

type ItemSpec struct {
	Title      []string `json:"title,omitempty"`
	Fallback   string   `json:"fallback,omitempty"`
	Noun       string   `json:"noun,omitempty"`
	NounPlural string   `json:"nounPlural,omitempty"`
}

ItemSpec is the `x-item` row-summary extension of an array of objects.

type Kind

type Kind string

Kind is the control a property renders as.

const (
	KindString     Kind = "string"
	KindLookup     Kind = "lookup"
	KindJSON       Kind = "json"
	KindUnion      Kind = "union"
	KindEnum       Kind = "enum"
	KindDate       Kind = "date"
	KindTextarea   Kind = "textarea"
	KindMarkdown   Kind = "markdown"
	KindBoolean    Kind = "boolean"
	KindNumber     Kind = "number"
	KindTags       Kind = "tags"        // array of scalars: one tag list
	KindMultiEnum  Kind = "multi-enum"  // array of enum items: a list of choices
	KindObjectList Kind = "object-list" // array of objects: per-item sub-forms
	KindStringMap  Kind = "string-map"
	KindObject     Kind = "object"
)

type Listener

type Listener struct {
	ChangeActions
	When *Condition     `json:"when,omitempty"`
	Else *ChangeActions `json:"else,omitempty"`
}

Listener is one `x-on-change` / `x-on-load` entry: its actions apply while When holds (always, when omitted) and Else applies while it does not.

type Lookup

type Lookup func(ctx context.Context, req LookupRequest) (LookupResult, error)

Lookup resolves `x-clicky-lookup` options, e.g. by calling an operation's lookup endpoint (`__lookup_filter` / `__lookup_q`).

type LookupRequest

type LookupRequest struct {
	Path   []string
	Spec   LookupSpec
	Query  string
	Values map[string]any
}

LookupRequest asks for the options of an `x-clicky-lookup` field. Query is the search text (empty for the head set); Values is the form's current value, which scopes dependent lookups.

type LookupResult

type LookupResult struct {
	Options   []Option
	Multi     bool
	Truncated bool
	Total     int
}

LookupResult is a lookup's option set. Truncated means more options exist than were returned and the field should search as the user types.

type LookupSpec

type LookupSpec struct {
	Ref         string         `json:"$ref,omitempty"`
	URL         string         `json:"url,omitempty"`
	Filter      string         `json:"filter"`
	SearchParam string         `json:"searchParam,omitempty"`
	Multi       bool           `json:"multi,omitempty"`
	Scope       map[string]any `json:"scope,omitempty"`
}

LookupSpec is the `x-clicky-lookup` extension: options load from an operation's lookup endpoint.

type Option

type Option struct {
	Value string
	Label string
	Raw   any
	// Description explains the option (x-enum-descriptions, an item's
	// description); the form shows it for the highlighted and the chosen option.
	Description string
}

Option is one choice of an enum or lookup control. Value is the option's string form; Raw is the typed value written to the answer.

type Options

type Options struct {
	Title       string
	Description string
	// Default pre-fills the form; schema defaults fill what it leaves out.
	Default map[string]any
	// Lookup resolves x-clicky-lookup fields; required when the schema has any.
	Lookup Lookup
	// LoadSchema loads the schema of x-clicky-schema properties; required when the
	// schema has any.
	LoadSchema SchemaLoader
	// Evaluate evaluates listener `when.expr`; nil uses FilterEvaluator.
	Evaluate Evaluator
	Input    io.Reader
	Output   io.Writer
	// Accessible runs a line-based prompt per field (screen readers, piped
	// input, tests) instead of the full-screen form.
	Accessible bool
	// RequiredFirst floats required fields up within each object.
	RequiredFirst bool
	Theme         *huh.Theme
}

Options configures Run.

type ParamMeta

type ParamMeta struct {
	Role string `json:"role,omitempty"`
}

ParamMeta is the `x-clicky` parameter extension (e.g. role=filter).

type Properties

type Properties struct {
	Keys     []string
	Map      map[string]*Schema
	Required []string
}

Properties is the effective shape of an object: its properties in render order and the keys currently required.

func Effective

func Effective(schema *Schema, value map[string]any) Properties

Effective merges the schema's base properties with each `allOf` member's contribution: an if/then member contributes `then` when its `if` matches the current value and `else` otherwise; an unconditional member always contributes. Later members win on key collision (replacing the property wholesale); required is the union.

func (Properties) IsRequired

func (p Properties) IsRequired(key string) bool

IsRequired reports whether key is currently required.

type Schema

type Schema struct {
	Type        TypeList `json:"type,omitempty"`
	Title       *string  `json:"title,omitempty"`
	Description string   `json:"description,omitempty"`
	Format      string   `json:"format,omitempty"`
	Pattern     string   `json:"pattern,omitempty"`
	Enum        []any    `json:"enum,omitempty"`
	Const       any      `json:"const,omitempty"`
	Default     any      `json:"default,omitempty"`
	ReadOnly    bool     `json:"readOnly,omitempty"`
	WriteOnly   bool     `json:"writeOnly,omitempty"`

	Minimum    *float64 `json:"minimum,omitempty"`
	Maximum    *float64 `json:"maximum,omitempty"`
	MultipleOf *float64 `json:"multipleOf,omitempty"`
	MinLength  *int     `json:"minLength,omitempty"`
	MaxLength  *int     `json:"maxLength,omitempty"`
	MinItems   *int     `json:"minItems,omitempty"`
	MaxItems   *int     `json:"maxItems,omitempty"`

	UniqueItems       bool               `json:"uniqueItems,omitempty"`
	Items             *Schema            `json:"items,omitempty"`
	Properties        map[string]*Schema `json:"properties,omitempty"`
	Required          []string           `json:"required,omitempty"`
	PatternProperties map[string]*Schema `json:"patternProperties,omitempty"`
	PropertyNames     *Schema            `json:"propertyNames,omitempty"`
	AllOf             []*Schema          `json:"allOf,omitempty"`
	AnyOf             []*Schema          `json:"anyOf,omitempty"`
	OneOf             []*Schema          `json:"oneOf,omitempty"`
	If                *Schema            `json:"if,omitempty"`
	Then              *Schema            `json:"then,omitempty"`
	Else              *Schema            `json:"else,omitempty"`
	Not               *Schema            `json:"not,omitempty"`
	Ref               string             `json:"$ref,omitempty"`

	// AdditionalProperties is the value schema of an open map; AdditionalClosed
	// records an explicit `additionalProperties: false`.
	AdditionalProperties *Schema `json:"-"`
	AdditionalClosed     bool    `json:"-"`

	EnumLabels       map[string]string `json:"x-enum-labels,omitempty"`
	EnumDescriptions map[string]string `json:"x-enum-descriptions,omitempty"`
	EnumDisplay      string            `json:"x-enum-display,omitempty"`
	Hidden           bool              `json:"x-hidden,omitempty"`
	Disabled         bool              `json:"x-disabled,omitempty"`
	Order            []string          `json:"x-order,omitempty"`
	ClickyOrder      *float64          `json:"x-clicky-order,omitempty"`
	Lookup           *LookupSpec       `json:"x-clicky-lookup,omitempty"`
	Clicky           *ParamMeta        `json:"x-clicky,omitempty"`
	Placeholder      string            `json:"x-clicky-placeholder,omitempty"`
	Discriminator    string            `json:"x-discriminator,omitempty"`
	OnChange         []Listener        `json:"x-on-change,omitempty"`
	OnLoad           []Listener        `json:"x-on-load,omitempty"`
	Help             *Help             `json:"x-help,omitempty"`
	ArrayDisplay     string            `json:"x-array-display,omitempty"`
	Item             *ItemSpec         `json:"x-item,omitempty"`
	Unit             string            `json:"x-clicky-unit,omitempty"`
	// SchemaSource marks an object property whose schema is loaded at run time
	// from the values of its Scope (Options.LoadSchema).
	SchemaSource *SchemaSource `json:"x-clicky-schema,omitempty"`
	// contains filtered or unexported fields
}

Schema mirrors clicky-ui's JsonSchemaProperty: the subset of JSON Schema 2020-12 the form understands plus the `x-*` vocabulary it reads. Presentation-only keywords (x-layout, x-columns, x-classes, …) have no terminal meaning and are ignored.

func Parse

func Parse(raw json.RawMessage) (*Schema, error)

Parse decodes a schema document and resolves its local `$ref` pointers.

func (*Schema) HasConst

func (s *Schema) HasConst() bool

HasConst reports whether the schema declares `const` (possibly null).

func (*Schema) Helper

func (s *Schema) Helper() string

Helper is the description joined with the `x-help` body.

func (*Schema) Label

func (s *Schema) Label(key string) string

Label is the field label: the title, or the key when the title is absent. An explicit empty title means the field needs no label of its own.

func (*Schema) PropertyOrder

func (s *Schema) PropertyOrder() []string

PropertyOrder returns the property keys in document order.

func (*Schema) UnmarshalJSON

func (s *Schema) UnmarshalJSON(data []byte) error

UnmarshalJSON records, beyond the plain keywords, the property document order, const presence and the `additionalProperties` bool-or-schema form.

type SchemaLoader

type SchemaLoader func(ctx context.Context, req SchemaRequest) (json.RawMessage, error)

SchemaLoader answers a SchemaRequest with an object schema, or nil (or JSON null) when the values select nothing that takes input.

type SchemaRequest

type SchemaRequest struct {
	Source string
	Values map[string]any
}

SchemaRequest asks for the schema of an x-clicky-schema property: Source is its source, Values the current values of its scope keys.

type SchemaSource

type SchemaSource struct {
	Source string   `json:"source"`
	Scope  []string `json:"scope"`
}

SchemaSource is the `x-clicky-schema` extension: Source names what to load, Scope the sibling keys whose values it depends on.

type State

type State struct {
	// contains filtered or unexported fields
}

State is the form's live value. Every huh field reads and writes it through an accessor bound to a path, so conditionals, listeners and hide funcs all see the same value the user is typing.

func (*State) Err

func (s *State) Err() error

Err is the first schema/listener error raised while the form ran.

func (*State) Values

func (s *State) Values() map[string]any

Values returns the current value tree.

type TypeList

type TypeList []string

TypeList is a JSON Schema `type`, which may be a single name or a list.

func (TypeList) Has

func (t TypeList) Has(name string) bool

Has reports whether name is one of the listed types.

func (TypeList) MarshalJSON

func (t TypeList) MarshalJSON() ([]byte, error)

func (*TypeList) UnmarshalJSON

func (t *TypeList) UnmarshalJSON(data []byte) error

Jump to

Keyboard shortcuts

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