htmlbind

package
v0.1.15 Latest Latest
Warning

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

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

Documentation

Overview

Package htmlbind is the rendering runtime for generated HTML templates.

Generation produces one immutable Plan per component: an ordered instruction list typed by that component's parameter struct. A shared coordinator walks the plan and writes HTML, so composition concerns such as slots, chain nesting, and document head merging live here rather than in generated code.

The package depends on the standard library only, and never on net/http, so generated code stays usable on TinyGo and WebAssembly targets. Response concerns such as content type and content encoding belong to the caller.

Index

Constants

This section is empty.

Variables

View Source
var ErrNilWrapper = errors.New("htmlbind: chain contains an unset wrapper")

ErrNilWrapper reports a wrapper that was left unset.

View Source
var ErrNoLeaf = errors.New("htmlbind: chain needs a leaf component")

ErrNoLeaf reports a chain assembled without an innermost component.

Functions

func Escape added in v0.1.15

func Escape(value string) string

Escape applies HTML text and attribute escaping. It is exported so generated helpers can reuse exactly the runtime's rules.

func MergeHead added in v0.1.15

func MergeHead(wrappers []Wrapper, leaf Fragment) []string

MergeHead collects head contributions in composition order, outermost first, dropping later duplicates so two components declaring the same stylesheet emit one tag.

func Render added in v0.1.15

func Render(w io.Writer, leaf Fragment) error

Render writes one component to w.

func RenderChain added in v0.1.15

func RenderChain(w io.Writer, wrappers []Wrapper, leaf Fragment) error

RenderChain writes a composed document to w. Wrappers apply outermost first, so RenderChain(w, []Wrapper{document, layout}, page) renders page inside layout inside document. An empty wrapper list renders the leaf alone.

Head contributions are merged before the first byte is written, so the shell can emit them without buffering the body. Assembly is validated up front, so a malformed chain cannot leave a partial response behind.

Types

type Builder added in v0.1.15

type Builder[P any] struct{}

Builder constructs instructions for one component. Generated code declares one per component so the parameter type is written once instead of on every instruction.

func (Builder[P]) Attr added in v0.1.15

func (Builder[P]) Attr(name string, value func(P) (string, bool)) Op[P]

Attr writes one attribute. The value arrives already escaped, because a mixed value concatenates author literals with escaped expressions and only the expressions may be escaped. present reports whether an optional value exists; an absent value omits the whole attribute.

func (Builder[P]) BoolAttr added in v0.1.15

func (Builder[P]) BoolAttr(name string, value func(P) bool) Op[P]

BoolAttr writes a bare attribute name when the value is true and omits it otherwise.

func (Builder[P]) Component added in v0.1.15

func (Builder[P]) Component(bind func(P) Fragment) Op[P]

Component renders another component. bind pairs the callee's plan with arguments derived from the caller's parameters.

func (Builder[P]) If added in v0.1.15

func (Builder[P]) If(condition func(P) bool, then, otherwise []Op[P]) Op[P]

If selects one of two instruction lists.

func (Builder[P]) MergedHead added in v0.1.15

func (Builder[P]) MergedHead() Op[P]

MergedHead writes every chain member's head contributions. The document shell places it inside its own head element.

func (Builder[P]) Raw added in v0.1.15

func (Builder[P]) Raw(value func(P) string) Op[P]

Raw writes a value that the template already marked trusted for its context.

func (Builder[P]) Slot added in v0.1.15

func (Builder[P]) Slot(value func(P) Fragment, fallback []Op[P]) Op[P]

Slot inserts a bound slot argument. When the argument is absent the fallback instructions run, which is how default slot content is expressed. An absent slot with no fallback emits nothing at all.

func (Builder[P]) Static added in v0.1.15

func (Builder[P]) Static(text string) Op[P]

Static writes literal markup. Adjacent literal output is coalesced at generation time, so one instruction covers a whole run.

func (Builder[P]) Text added in v0.1.15

func (Builder[P]) Text(value func(P) string) Op[P]

Text writes a value into child-node or attribute position with HTML escaping.

type Fragment added in v0.1.15

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

Fragment is a component with its parameters already bound. It is the runtime value behind the html template type, so a slot argument can be passed between components and across template files without either side naming the other's parameter struct.

The zero Fragment is absent, which is how an optional slot with no argument is represented.

func Bind added in v0.1.15

func Bind[P any](plan *Plan[P], params P) Fragment

Bind pairs a plan with parameters, producing the value a slot accepts.

func (Fragment) Head added in v0.1.15

func (f Fragment) Head() []string

Head returns the fragment's own head contributions.

func (Fragment) Present added in v0.1.15

func (f Fragment) Present() bool

Present reports whether the fragment carries content. An absent optional slot renders its default instead.

type Op added in v0.1.15

type Op[P any] interface {
	// Exec writes this instruction's output. Implementations are immutable and
	// safe to share across goroutines.
	Exec(r *Renderer, params P) error
}

Op is one instruction of a render plan. P is the parameter struct of the component the instruction belongs to, so every step stays statically typed and no reflection is needed.

func For added in v0.1.15

func For[P, E, S any](items func(P) []E, scope func(P, E, int) S, body []Op[S]) Op[P]

For repeats body once per item. scope builds the body's parameter value from the enclosing parameters, the item, and its index, so the loop variable stays statically typed instead of becoming an untyped lookup.

type Plan added in v0.1.15

type Plan[P any] struct {
	// Head holds this component's document head contributions as ready to
	// write HTML. They merge into the shell head before any body byte.
	Head []string
	// Ops is the instruction list executed in order.
	Ops []Op[P]
}

Plan is a component compiled to instructions. A plan is built once at package initialization and shared by every render.

func (*Plan[P]) Exec added in v0.1.15

func (p *Plan[P]) Exec(r *Renderer, params P) error

Exec runs the plan against params.

type Renderer added in v0.1.15

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

Renderer is the coordinator walking plans. It owns the output stream and the merged head, so instructions never touch either directly.

func (*Renderer) MergedHead added in v0.1.15

func (r *Renderer) MergedHead() []string

MergedHead returns the head contributions collected for this render.

func (*Renderer) Write added in v0.1.15

func (r *Renderer) Write(value string) error

Write emits raw bytes. Instructions call it after applying their own context-appropriate escaping.

type Wrapper added in v0.1.15

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

Wrapper is a component that renders another one into its unnamed slot. Generated code returns one from Bind<Name> for a component with a children parameter.

func BindWrapper added in v0.1.15

func BindWrapper[P any](plan *Plan[P], params P, setChildren func(*P, Fragment)) Wrapper

BindWrapper pairs a plan with parameters and the setter that installs the child fragment. Generated code supplies the setter because only it knows which field the unnamed slot binds to.

Jump to

Keyboard shortcuts

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