Documentation
¶
Overview ¶
Package uigen turns one resolved widget document into the files that make it a running widget: a templ view and a Go scaffold implementing the SDK's widget contract.
In memory, then to disk ¶
Generate returns artifacts — a path and its exact bytes — and writes nothing. Write is a separate call. That split is what makes the determinism claim cheap to check: a spec generates twice and compares two slices, with no temporary directory and no filesystem anywhere in the assertion. It is the shape pkg/gotth/internal/clientcodec already uses, for the same reason.
Determinism is not incidental here. Everything emitted is derived from the IR's ordered sequences, and nothing is derived from a map: the IR is ordered precisely so a render is byte-identical for equal state, and a generator that reintroduced iteration order would hand that property back.
What it emits, and what it refuses ¶
Every block of the dialect reaches the output: state, predicates, bindings, labels, chrome, roles, channels, placements, a scene of nodes, edges and orbits, motion, indicators, controls, events and streams. The three computed records reach it too — an edge's geometry becomes its transform, the legend is walked rather than re-derived from the channels, and the dirty projection becomes the widget's own dirty declaration.
Each generated definition has a default constructor and view, plus NewWidgetAt and WidgetViewAt forms that accept a host-assigned region. The region scopes the live root, accessible title and animated scene identities; the definition's name and event contracts remain shared. Hosts validate region syntax and uniqueness before exposing instances through their live configuration.
What is refused is listed by Refusals and is three shapes of one construct: a control whose trigger is change, input or submit. A control declares a caption, a trigger and an event, and nothing that says what kind of element it is — a click is a button and needs nothing more, while those three need a form control the dialect cannot describe. Binding one of them to a button would emit a binding that can never fire.
Refusing is the whole point of the boundary. A generator that silently omitted a construct, or emitted a plausible-looking approximation of one, would produce a widget that compiles, renders, and is not the widget the author wrote — which is the failure the dialect's validator exists to prevent one layer up, and it would be pointless to enforce there and abandon here.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNameCollision = errors.New("uigen: two document identifiers emit one Go identifier")
ErrNameCollision is returned when two document identifiers, distinct in the dialect's flat namespace, would emit one Go identifier.
The dialect's own namespace cannot prevent it: `statusText` and `StatusText` are two names there and one exported name here. Reporting it is what keeps the generator from emitting a file that will not compile and blaming templ for it.
var ErrPackage = errors.New("uigen: the output package name is not a Go identifier")
ErrPackage is returned for an output package name Go could not compile.
var ErrUnexportable = errors.New("uigen: a document identifier has no exported Go spelling")
ErrUnexportable is returned for a document identifier with no exported Go spelling — one beginning with an underscore, which the dialect's identifier pattern allows and Go's export rule does not.
var ErrUnsound = errors.New("uigen: the document is not sound; refuse its findings before generating")
ErrUnsound is returned for a document missing something the interpreter guarantees a sound one has.
It is a refusal rather than a nil dereference. The IR is returned whether or not a document validated, so a caller that generated without reading the findings hands this package a partial document, and saying so is more use than a stack trace naming a field.
Functions ¶
Types ¶
type Artifact ¶
type Artifact struct {
// Path is relative to the output directory and is part of the generated
// output: gen.sh compares it, so a renamed artifact is a diff rather than a
// silently orphaned file.
Path string
// Data is the file's exact bytes.
Data []byte
}
Artifact is one generated file: a path relative to the output directory and its exact bytes.
func Generate ¶
Generate produces every artifact for one resolved document, without writing anything.
The document must be sound: interpreting it must have produced no finding. Generating from an unsound document is generating from a guess, and this package has no way to tell the two apart — the IR is returned either way, so the caller holding the findings is the only one who can refuse.
type Options ¶
type Options struct {
// Package is the Go package name both emitted files declare.
Package string
}
Options are the decisions the document does not carry.
A widget document names no path, no package and no import, by construction — that is what makes one publishable — so the one thing generation needs and the document cannot supply is where the emitted Go belongs.
type UnsupportedError ¶
type UnsupportedError struct {
// Widget is the document's own name.
Widget string
// Constructs are the unsupported constructs, in the order [Refusals] lists
// them.
Constructs []string
}
UnsupportedError reports the constructs this generator does not yet emit. It names every one of them rather than the first, on the same argument the interpreter's findings are made on: an author who fixes one and re-runs to find the next learns the tool tells them a fraction of the truth.
func (*UnsupportedError) Error ¶
func (unsupportedError *UnsupportedError) Error() string