formular

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: May 26, 2026 License: CC0-1.0 Imports: 7 Imported by: 0

README

formular

Formular is a JSON message DSL for backend-owned dynamic menus and forms that can be rendered by GUI, TUI, CLI, MCP, web, or other frontends.

JavaScript frontend

The npm package entry point is a single dependency-free browser file:

import { FormularMenu } from "@asciimoth/formular-menu";

const menu = new FormularMenu("root", "settings", (message) => {
  console.log("frontend message", message);
});

Run the local WASM demo:

pnpm install
pnpm run demo

The demo renders two independent frontends and a Go WASM backend connected by one merged JSON message channel.

License

Files in this repository are distributed under the CC0 license.

CC0
To the extent possible under law, ASCIIMoth has waived all copyright and related or neighboring rights to formular.

Documentation

Overview

Package formular defines wire types for the Formular JSON menu and form protocol.

Index

Constants

View Source
const (
	MessageMenuSnapshot        = "menu.snapshot"
	MessageBlockSnapshot       = "block.snapshot"
	MessageBlockDelete         = "block.delete"
	MessageFieldStatus         = "field.status"
	MessageAutocompleteHints   = "autocomplete.hints"
	MessageFieldUpdate         = "field.update"
	MessageFieldValidate       = "field.validate"
	MessageFormApply           = "form.apply"
	MessageButtonPress         = "button.press"
	MessageAutocompleteRequest = "autocomplete.request"
)

Message type constants used in Formular JSON envelopes.

View Source
const (
	ItemHeader      = "header"
	ItemLabel       = "label"
	ItemProgressbar = "progressbar"
	ItemLogs        = "logs"
	ItemButton      = "button"
	ItemField       = "field"
)

Item type constants used by menu and array element content.

View Source
const (
	FieldText     = "text"
	FieldInt      = "int"
	FieldFloat    = "float"
	FieldFile     = "file"
	FieldCheckbox = "checkbox"
	FieldRadio    = "radio"
	FieldRange    = "range"
	FieldArray    = "array"
)

Field kind constants supported by the base DSL.

View Source
const (
	TextPlain    = "plain"
	TextMarkdown = "markdown"
	TextCode     = "code"
)

Text format constants for label rendering.

View Source
const (
	LogTrace = "trace"
	LogDebug = "debug"
	LogInfo  = "info"
	LogWarn  = "warn"
	LogError = "error"
	LogPanic = "panic"
)

Log level constants for logs item rendering.

View Source
const (
	StatusUnset = "unset"
	StatusOK    = "ok"
	StatusWarn  = "warn"
	StatusError = "error"
)

Validation status constants set by a backend.

Variables

This section is empty.

Functions

func IsValidationError

func IsValidationError(err error) bool

IsValidationError reports whether err contains one or more Formular validation errors.

Types

type ArrayElement

type ArrayElement struct {
	// ID is unique within the owning array field.
	ID string `json:"id"`
	// Template names the template this element is based on.
	Template string `json:"template"`
	// Items is the element snapshot after backend defaults and status are applied.
	Items []Item `json:"items"`
	// Copyable declares optional text for a frontend copy action.
	Copyable *Copyable `json:"copyable,omitempty"`
}

ArrayElement is one concrete element inside an array field.

func (ArrayElement) Copy

func (e ArrayElement) Copy() ArrayElement

Copy returns a deep copy of e.

func (ArrayElement) Validate

func (e ArrayElement) Validate() error

Validate returns an error if e is not a valid array element.

type ArrayElementValue

type ArrayElementValue struct {
	// ID identifies the existing or frontend-created element.
	ID string `json:"id"`
	// Template names the template this value follows.
	Template string `json:"template"`
	// Values contains field values for this element.
	Values map[string]any `json:"values"`
}

ArrayElementValue is the wire value shape used when sending array field values.

func (ArrayElementValue) Copy

Copy returns a deep copy of v.

func (ArrayElementValue) Validate

func (v ArrayElementValue) Validate() error

Validate returns an error if v is not a valid array element value.

type ArrayTemplate

type ArrayTemplate struct {
	// Name is unique within the owning array field.
	Name string `json:"name"`
	// Label is optional display text for template selection.
	Label string `json:"label,omitempty"`
	// Items are labels, buttons, and fields allowed in elements of this template.
	Items []Item `json:"items"`
}

ArrayTemplate defines one allowed element shape for an array field.

func (ArrayTemplate) Copy

func (t ArrayTemplate) Copy() ArrayTemplate

Copy returns a deep copy of t.

func (ArrayTemplate) Validate

func (t ArrayTemplate) Validate() error

Validate returns an error if t is not a valid array template.

type Autocomplete

type Autocomplete struct {
	// Enabled permits frontend autocomplete.request messages.
	Enabled bool `json:"enabled,omitempty"`
	// Tag is an application-defined completion namespace or hint.
	Tag string `json:"tag,omitempty"`
}

Autocomplete configures frontend completion behavior for a field.

func (Autocomplete) Copy

func (a Autocomplete) Copy() Autocomplete

Copy returns a deep copy of a.

func (Autocomplete) Validate

func (a Autocomplete) Validate() error

Validate returns an error if a is not a valid autocomplete configuration.

type AutocompleteHintsMessage

type AutocompleteHintsMessage struct {
	MessageBase
	// Field identifies the text field the hints belong to.
	Field FieldRef `json:"field"`
	// Prefix is the input prefix the backend used to compute hints.
	Prefix string `json:"prefix"`
	// Hints contains complete candidate values, not suffixes.
	Hints []string `json:"hints"`
}

AutocompleteHintsMessage is sent by a backend with possible completions.

func (AutocompleteHintsMessage) Copy

Copy returns a deep copy of m.

func (AutocompleteHintsMessage) Validate

func (m AutocompleteHintsMessage) Validate() error

Validate returns an error if m is not a valid autocomplete hints message.

type AutocompleteRequestMessage

type AutocompleteRequestMessage struct {
	MessageBase
	// Field identifies the focused field being completed.
	Field FieldRef `json:"field"`
	// Prefix is the current text input prefix.
	Prefix string `json:"prefix"`
}

AutocompleteRequestMessage is sent by a frontend to request completions.

func (AutocompleteRequestMessage) Copy

Copy returns a deep copy of m.

func (AutocompleteRequestMessage) Validate

func (m AutocompleteRequestMessage) Validate() error

Validate returns an error if m is not a valid autocomplete request message.

type Block

type Block struct {
	// ID is unique within one menu.
	ID string `json:"id"`
	// Order controls frontend display ordering.
	Order int `json:"order"`
	// Generation changes when block structure or item configuration changes.
	Generation uint64 `json:"generation"`
	// Form marks the block as applied as a whole instead of realtime field updates.
	Form bool `json:"form"`
	// Inactive disables all user input for the block.
	Inactive bool `json:"inactive,omitempty"`
	// Collapsible tells the frontend to expose collapse controls.
	Collapsible bool `json:"collapsible,omitempty"`
	// Collapsed is the initial collapsed state unless force-updated.
	Collapsed bool `json:"collapsed,omitempty"`
	// Copyable declares optional text for a frontend copy action.
	Copyable *Copyable `json:"copyable,omitempty"`
	// Items are headers, labels, fields, and buttons in display order.
	Items []Item `json:"items"`
}

Block is a backend-defined menu section with independent generation.

func (Block) Copy

func (b Block) Copy() Block

Copy returns a deep copy of b.

func (Block) Validate

func (b Block) Validate() error

Validate returns an error if b is not a valid block.

type BlockDeleteMessage

type BlockDeleteMessage struct {
	MessageBase
	// BlockID identifies the block to remove.
	BlockID string `json:"blockId"`
}

BlockDeleteMessage is sent by a backend to remove one block.

func (BlockDeleteMessage) Copy

Copy returns a deep copy of m.

func (BlockDeleteMessage) Validate

func (m BlockDeleteMessage) Validate() error

Validate returns an error if m is not a valid block delete message.

type BlockSnapshotMessage

type BlockSnapshotMessage struct {
	MessageBase
	// Block is the full current snapshot of the addressed block.
	Block Block `json:"block"`
}

BlockSnapshotMessage is sent by a backend to create or replace one block.

func (BlockSnapshotMessage) Copy

Copy returns a deep copy of m.

func (BlockSnapshotMessage) Validate

func (m BlockSnapshotMessage) Validate() error

Validate returns an error if m is not a valid block snapshot message.

type ButtonPressMessage

type ButtonPressMessage struct {
	MessageBase
	// BlockID identifies the block that owns the button.
	BlockID string `json:"blockId"`
	// ElementPath identifies a nested array element button when present.
	ElementPath []ElementPathSegment `json:"elementPath,omitempty"`
	// ButtonID identifies the button inside the block or element.
	ButtonID string `json:"buttonId"`
}

ButtonPressMessage is sent by a frontend when a declared button is pressed.

func (ButtonPressMessage) Copy

Copy returns a deep copy of m.

func (ButtonPressMessage) Validate

func (m ButtonPressMessage) Validate() error

Validate returns an error if m is not a valid button press message.

type Copyable

type Copyable struct {
	// Text is placed on the system clipboard by frontend copy controls.
	Text string `json:"text"`
}

Copyable contains clipboard text for copyable blocks or array elements.

func (Copyable) Copy

func (c Copyable) Copy() Copyable

Copy returns a deep copy of c.

func (Copyable) Validate

func (c Copyable) Validate() error

Validate returns an error if c is not a valid copyable descriptor.

type ElementPathSegment

type ElementPathSegment struct {
	// ArrayFieldID identifies the array field containing the element.
	ArrayFieldID string `json:"arrayFieldId"`
	// ElementID identifies the array element inside ArrayFieldID.
	ElementID string `json:"elementId"`
}

ElementPathSegment identifies one array element nesting step.

func (ElementPathSegment) Copy

Copy returns a deep copy of s.

func (ElementPathSegment) Validate

func (s ElementPathSegment) Validate() error

Validate returns an error if s is not a valid element path segment.

type Field

type Field struct {
	// Kind selects the base input widget and value shape.
	Kind string `json:"kind"`
	// Value is the backend-provided default or current value.
	Value any `json:"value,omitempty"`
	// Placeholder is optional empty-state text for text-like inputs.
	Placeholder string `json:"placeholder,omitempty"`
	// Readonly prevents direct user editing when true.
	Readonly bool `json:"readonly,omitempty"`
	// Required means frontend apply is blocked while the value is empty.
	Required bool `json:"required,omitempty"`
	// Validation means frontend should send field.validate messages for changes.
	Validation bool `json:"validate,omitempty"`
	// Status is a backend-provided validation state.
	Status string `json:"status,omitempty"`
	// StatusText is optional explanatory text for Status.
	StatusText string `json:"statusText,omitempty"`
	// Secret requests hidden text entry.
	Secret bool `json:"secret,omitempty"`
	// Multiline allows newline-preserving text input.
	Multiline bool `json:"multiline,omitempty"`
	// Subtype refines text fields, for example email or filepath.
	Subtype string `json:"subtype,omitempty"`
	// Autocomplete configures optional completion requests for text fields.
	Autocomplete *Autocomplete `json:"autocomplete,omitempty"`
	// AllowedValues enumerates values the frontend may offer as choices.
	AllowedValues []any `json:"allowedValues,omitempty"`
	// Min is the optional numeric minimum for int, float, or range fields.
	Min *float64 `json:"min,omitempty"`
	// Max is the optional numeric maximum for int, float, or range fields.
	Max *float64 `json:"max,omitempty"`
	// Fraction is the optional number of fractional digits for floats.
	Fraction *uint `json:"fraction,omitempty"`
	// MaxBytes limits base64 file payload size before encoding.
	MaxBytes *uint64 `json:"maxBytes,omitempty"`
	// Accept lists MIME types accepted by file inputs.
	Accept []string `json:"accept,omitempty"`
	// Templates declares allowed element templates for array fields.
	Templates []ArrayTemplate `json:"templates,omitempty"`
	// Elements is the current array field element snapshot.
	Elements []ArrayElement `json:"elements,omitempty"`
	// Copyable declares optional text for a frontend copy action.
	Copyable *Copyable `json:"copyable,omitempty"`
}

Field contains input configuration for an Item with type field.

func (Field) Copy

func (f Field) Copy() Field

Copy returns a deep copy of f.

func (Field) Validate

func (f Field) Validate() error

Validate returns an error if f is not a valid field.

type FieldRef

type FieldRef struct {
	// BlockID identifies the owning top-level block.
	BlockID string `json:"blockId"`
	// FieldID identifies the final field being addressed.
	FieldID string `json:"fieldId"`
	// ElementPath identifies nested array element ownership when present.
	ElementPath []ElementPathSegment `json:"elementPath,omitempty"`
}

FieldRef identifies a top-level or nested field in frontend messages.

func (FieldRef) Copy

func (r FieldRef) Copy() FieldRef

Copy returns a deep copy of r.

func (FieldRef) Validate

func (r FieldRef) Validate() error

Validate returns an error if r is not a valid field reference.

type FieldStatusMessage

type FieldStatusMessage struct {
	MessageBase
	// Field identifies the top-level or nested field being updated.
	Field FieldRef `json:"field"`
	// Status is the backend validation state to display.
	Status string `json:"status"`
	// StatusText is optional explanatory text for the status.
	StatusText string `json:"statusText,omitempty"`
	// Readonly optionally changes whether the field accepts user input.
	Readonly *bool `json:"readonly,omitempty"`
}

FieldStatusMessage is sent by a backend to update a field status or readonly flag.

func (FieldStatusMessage) Copy

Copy returns a deep copy of m.

func (FieldStatusMessage) Validate

func (m FieldStatusMessage) Validate() error

Validate returns an error if m is not a valid field status message.

type FieldUpdateMessage

type FieldUpdateMessage struct {
	MessageBase
	// Field identifies the field whose value changed.
	Field FieldRef `json:"field"`
	// Value is the current field value after frontend normalization.
	Value any `json:"value"`
}

FieldUpdateMessage is sent by a frontend for realtime field changes.

func (FieldUpdateMessage) Copy

Copy returns a deep copy of m.

func (FieldUpdateMessage) Validate

func (m FieldUpdateMessage) Validate() error

Validate returns an error if m is not a valid field update message.

type FieldValidateMessage

type FieldValidateMessage struct {
	MessageBase
	// Field identifies the field to validate.
	Field FieldRef `json:"field"`
	// Value is the current candidate field value.
	Value any `json:"value"`
}

FieldValidateMessage is sent by a frontend to request backend validation.

func (FieldValidateMessage) Copy

Copy returns a deep copy of m.

func (FieldValidateMessage) Validate

func (m FieldValidateMessage) Validate() error

Validate returns an error if m is not a valid field validate message.

type FieldValue

type FieldValue struct {
	// FieldID identifies the value owner.
	FieldID string `json:"fieldId"`
	// Value is the current field value.
	Value any `json:"value"`
}

FieldValue is a named field value used by clients that prefer ordered lists.

func (FieldValue) Copy

func (v FieldValue) Copy() FieldValue

Copy returns a deep copy of v.

func (FieldValue) Validate

func (v FieldValue) Validate() error

Validate returns an error if v is not a valid field value.

type FormApplyMessage

type FormApplyMessage struct {
	MessageBase
	// BlockID identifies the form block being applied.
	BlockID string `json:"blockId"`
	// Values contains all current field values in the block.
	Values map[string]any `json:"values"`
}

FormApplyMessage is sent by a frontend when a form block is applied.

func (FormApplyMessage) Copy

Copy returns a deep copy of m.

func (FormApplyMessage) Validate

func (m FormApplyMessage) Validate() error

Validate returns an error if m is not a valid form apply message.

type Item

type Item struct {
	// Type is one of header, label, progressbar, logs, button, or field.
	Type string `json:"type"`
	// ID is unique inside its owning block or array element.
	ID string `json:"id"`
	// Label is the user-facing caption for fields and buttons.
	Label string `json:"label,omitempty"`
	// Text is the user-facing body for labels and headers.
	Text string `json:"text,omitempty"`
	// Format controls label rendering for plain text, markdown, or code.
	Format string `json:"format,omitempty"`
	// Syntax optionally names a code syntax for highlighted labels.
	Syntax string `json:"syntax,omitempty"`
	// Help is an optional plaintext hint attached to the item.
	Help string `json:"help,omitempty"`
	// Progress is the percentage shown by progressbar items, from 0 to 100.
	Progress *uint `json:"progress,omitempty"`
	// Logs contains lines shown by logs items.
	Logs []LogLine `json:"logs,omitempty"`
	// Inactive disables a button.
	Inactive bool `json:"inactive,omitempty"`
	// Field contains field-specific configuration when Type is field.
	*Field `json:",omitempty"`
}

Item is a discriminated menu content item.

func (Item) Copy

func (i Item) Copy() Item

Copy returns a deep copy of i.

func (Item) Validate

func (i Item) Validate() error

Validate returns an error if i is not a valid item.

type LogLine

type LogLine struct {
	// Level controls the colored prefix shown before Text.
	Level string `json:"level"`
	// Text is the line body.
	Text string `json:"text"`
}

LogLine is one rendered line in a logs item.

func (LogLine) Copy

func (l LogLine) Copy() LogLine

Copy returns a deep copy of l.

func (LogLine) Validate

func (l LogLine) Validate() error

Validate returns an error if l is not a valid log line.

type MenuSnapshotMessage struct {
	MessageBase
	// Force tells the frontend to discard remembered state and reinitialize.
	Force bool `json:"force,omitempty"`
	// Blocks is the complete block list for this menu snapshot.
	Blocks []Block `json:"blocks"`
}

MenuSnapshotMessage is sent by a backend to initialize or replace a menu.

Copy returns a deep copy of m.

func (m MenuSnapshotMessage) Validate() error

Validate returns an error if m is not a valid menu snapshot message.

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

MenuSnapshotState keeps the latest menu.snapshot-equivalent state for menus.

It is intended for frontends and middleware that forward Formular messages and need to serve a newly connected frontend from locally cached menu state. It applies only messages that affect the observable menu snapshot. Ephemeral messages such as autocomplete hints and requests are ignored.

func NewMenuSnapshotState added in v0.2.0

func NewMenuSnapshotState() *MenuSnapshotState

NewMenuSnapshotState creates an empty menu snapshot state cache.

func (s *MenuSnapshotState) Apply(message any) bool

Apply applies one typed Formular message or map-shaped decoded JSON message.

func (s *MenuSnapshotState) ApplyJSON(data []byte) (bool, error)

ApplyJSON decodes and applies one Formular message.

func (s *MenuSnapshotState) ForceSnapshot(menuID string) (MenuSnapshotMessage, bool)

ForceSnapshot returns the cached snapshot with Force set for frontend reloads.

func (s *MenuSnapshotState) ForceSnapshots() []MenuSnapshotMessage

ForceSnapshots returns all cached snapshots sorted by menu id with Force set.

func (s *MenuSnapshotState) Snapshot(menuID string) (MenuSnapshotMessage, bool)

Snapshot returns the cached snapshot for one menu.

func (s *MenuSnapshotState) Snapshots() []MenuSnapshotMessage

Snapshots returns all cached snapshots sorted by menu id.

type MessageBase

type MessageBase struct {
	// Type identifies the concrete message shape.
	Type string `json:"type"`
	// MenuID identifies the menu instance the message belongs to.
	MenuID string `json:"menuId"`
	// MenuGeneration is the backend-assigned menu structure generation.
	MenuGeneration uint64 `json:"menuGeneration,omitempty"`
	// BlockGeneration is the backend-assigned block structure generation.
	BlockGeneration uint64 `json:"blockGeneration,omitempty"`
}

MessageBase contains fields common to all Formular protocol messages.

func (MessageBase) Copy

func (m MessageBase) Copy() MessageBase

Copy returns a deep copy of m.

func (MessageBase) Validate

func (m MessageBase) Validate() error

Validate returns an error if m is not a valid message base.

type ValidationError

type ValidationError struct {
	// Path identifies the invalid field or value.
	Path string
	// Message describes the validation failure.
	Message string
}

ValidationError describes one invalid field in a Formular structure.

func (ValidationError) Copy

Copy returns a deep copy of e.

func (ValidationError) Error

func (e ValidationError) Error() string

Error returns a human-readable validation error.

func (ValidationError) Validate

func (e ValidationError) Validate() error

Validate returns an error if e is not a valid validation error.

type ValidationErrors

type ValidationErrors []ValidationError

ValidationErrors is a collection of validation failures.

func (ValidationErrors) Error

func (e ValidationErrors) Error() string

Error returns all validation failures as one string.

func (ValidationErrors) Unwrap

func (e ValidationErrors) Unwrap() []error

Unwrap returns the validation failures for errors.Join-style inspection.

Directories

Path Synopsis
demo
backend command

Jump to

Keyboard shortcuts

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