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 ¶
- Variables
- func ApplyDefaults(schema *Schema, value map[string]any) map[string]any
- func Run(ctx context.Context, raw json.RawMessage, opts Options) (map[string]any, error)
- func RunSchema(ctx context.Context, schema *Schema, opts Options) (map[string]any, error)
- type ChangeActions
- type Condition
- type Control
- type Evaluator
- type ExprInput
- type Help
- type ItemSpec
- type Kind
- type Listener
- type Lookup
- type LookupRequest
- type LookupResult
- type LookupSpec
- type Option
- type Options
- type ParamMeta
- type Properties
- type Schema
- type SchemaLoader
- type SchemaRequest
- type SchemaSource
- type State
- type TypeList
Constants ¶
This section is empty.
Variables ¶
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 ¶
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.
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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) Label ¶
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 ¶
PropertyOrder returns the property keys in document order.
func (*Schema) UnmarshalJSON ¶
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 ¶
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 ¶
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.
type TypeList ¶
type TypeList []string
TypeList is a JSON Schema `type`, which may be a single name or a list.