routetree

package
v0.5.21 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package routetree discovers a filesystem route tree and derives the stdlib ServeMux patterns, ancestor layout chains, and Go package names for it.

The tree is an opt-in directory (conventionally pages) whose subdirectories are both URL segments and Go packages. A directory name carries its own segment kind: a trailing underscore marks one dynamic segment, and two mark a catch-all. Bracketed spellings are impossible because a directory holding Go source must be a legal import path element; see the package documentation of ValidateDirName for what the toolchain accepts.

Index

Constants

View Source
const (
	PageComponentName     = "Page"
	LayoutComponentName   = "Layout"
	DocumentComponentName = "Document"
)

Reserved component names. decision:html-route-file-conventions ties each reserved file to one declaration name, so a handler can predict every symbol its route package exposes without opening the template.

View Source
const (
	RouteParamsType = "RouteParams"
	DecodeRouteFunc = "DecodeRoute"
)

Names of the symbols the default templates produce in a route package.

View Source
const (
	CodeInvalidPath  = "invalid_path_parameter"
	CodeInvalidQuery = "invalid_query_parameter"
	CodeMissingPath  = "missing_path_parameter"
)

Error codes the default decoder template reports.

View Source
const (
	NetHTTPCatchAllSuffix = "..."
	NetHTTPRootPattern    = "/{$}"
)

The pattern spellings net/http's ServeMux reads, which are the defaults.

View Source
const (
	DefaultDecoderOutput  = "route_gen.go"
	DefaultRegistryOutput = "routes_gen.go"
	// ComponentSuffix is appended to a template's base name to form its
	// generated file, so page.tb.html and layout.tb.html in one directory do not
	// claim the same output.
	ComponentSuffix = "_gen.go"
)

Default base names of the files Generate produces.

View Source
const (
	RegisterFunc   = "Register"
	MuxFunc        = "NewServeMux"
	TableVar       = "Routes"
	ActionTableVar = "Actions"
)

Default names of the registry's generated declarations.

View Source
const (
	DefaultPageFile     = "page.tb.html"
	DefaultLayoutFile   = "layout.tb.html"
	DefaultDocumentFile = "document.tb.html"
	DefaultLogicFile    = "page.go"
	DefaultRootDir      = "pages"
)

Default file names for the reserved roles of a route directory.

View Source
const (
	DefaultActionDeclarationImport  = "github.com/shibukawa/tinybind-go"
	DefaultActionDeclarationPackage = "httpbind"
	DefaultActionDeclarationName    = "ServerAction"
)

DefaultActionDeclarationImport and DefaultActionDeclarationName are the annotation this module ships. A framework declaring its own supplies its own pair through ActionDeclaration.

View Source
const ActionHashLength = 12

ActionHashLength is how many hexadecimal characters of the digest an endpoint carries. It is fixed rather than configurable.

View Source
const DefaultActionPrefix = "/_action"

DefaultActionPrefix is the reserved path every server function endpoint hangs below.

It is safe by construction only because Discover ignores directories beginning with an underscore, so a route tree can never produce this path. A configured prefix has no such guarantee, which is why ValidateActionPrefix takes the discovered routes.

View Source
const DefaultActionSelectorField = "_action"

DefaultActionSelectorField is the hidden field a generated form carries to name the handler a native submit is for.

View Source
const DefaultFastHTTPImport = "github.com/shibukawa/tinygodriver/fasthttp"

DefaultFastHTTPImport is the fasthttp package FastHTTPSymbols targets when given none. It is the fork tinygodriver ships, because that is the one fasthttpbind is built against; an application on upstream fasthttp names upstream instead.

View Source
const DefaultRenderWriterType = "io.Writer"

DefaultRenderWriterType is the writer the generated composer takes when Emitter.RenderWriterType is empty. It is an io.Writer rather than a ResponseWriter because a handler that renders into a buffer can still choose its status, which is what the script-free mode and a static export need.

View Source
const GeneratedHeader = "// Code generated by tinybind; DO NOT EDIT."

GeneratedHeader is the first line of every file this package emits by default. Emitter.GeneratedHeader replaces it.

View Source
const PageFuncName = "Load"

PageFuncName is the reserved name of the optional Go entry point beside a page template.

It is Load rather than Page because the template compiler already emits a func Page for the component into the same package, and two declarations cannot share a name. The file stays page.go and the component stays Page; only the Go entry point moves aside.

View Source
const RenderFunc = "Render"

RenderFunc is the name of the generated composer.

View Source
const SlotParamName = "children"

SlotParamName is the parameter a layout must declare to become a chain wrapper. The template compiler emits a Bind wrapper only for an exported component carrying an html parameter with this name, so the convention is the compiler's rather than this package's.

View Source
const TemplateComposer = "composer"

TemplateComposer is the name of the template that renders a route composer. Pass it to Emitter.Parse to replace the emitted shape.

View Source
const TemplateDecoder = "decoder"

TemplateDecoder is the name of the template that renders a route decoder. Pass it to Emitter.Parse to replace the emitted shape.

View Source
const TemplateRegistry = "registry"

TemplateRegistry is the name of the template that renders the integrated ServeMux. Pass it to Emitter.Parse to replace the emitted shape.

View Source
const TemplateRender = "render"

TemplateRender is the name of the block that writes the render call itself, in both the composer and the registry handler. Pass it to Emitter.Parse to send the request, or anything else in scope, to a framework's own entry:

e.Parse(routetree.TemplateRender,
	`web.WriteHTML({{ .Writer }}, {{ .Request }}, {{ .Chain }}, {{ .Leaf }})`)

The block writes an expression of type error, so the caller keeps deciding what a failure does. Its data is RenderCall.

An override may only name packages the generated file already imports: the runtime and error packages of Symbols, the request package, and io. Pointing Symbols.RuntimeImport at the package holding the entry is what covers the usual case, where the entry and the option type ship together.

Variables

This section is empty.

Functions

func ActionHash added in v0.2.3

func ActionHash(relDir, name string) string

ActionHash derives the stable half of an endpoint URL from the declaring package's route-relative directory and the handler name.

The mount prefix is deliberately not hashed, so remounting an application changes the URL without changing the identity underneath. There is no build salt either: regenerating an unchanged project reproduces the same value, so a client that cached the URL keeps working across a deploy.

The declaring directory rather than the serving route path is what goes in, because a layout is compiled once and its handler must have one URL no matter which page renders it.

func ActionPath added in v0.2.3

func ActionPath(prefix, hash, name string) string

ActionPath builds the endpoint path for one handler.

func ActionWrapperName added in v0.5.10

func ActionWrapperName(goName string) string

ActionWrapperName is the entry point generated for a typed action.

This module owns the name because it is what the registry writes; the phase that emits the wrapper is told it rather than deriving its own, so the two cannot drift.

func EmitDecoder

func EmitDecoder(route Route, inputs []Value) ([]byte, error)

EmitDecoder renders the typed route decoder for one route using the default emitter. See Emitter.Decoder to customize the output.

func ExportedName

func ExportedName(name string) string

ExportedName converts a declared input name to its generated struct field name. It splits on underscores and case boundaries so id, user_id, and userID all reach the field a Go author would have written by hand.

func PackageName

func PackageName(dir string) string

PackageName derives the Go package clause for a route directory. A name that is already an identifier is used unchanged, which is what makes the common id_ form read naturally; anything else is sanitized, because a URL segment such as sign-in is legal on disk but not as a package clause.

func PublishedName added in v0.5.10

func PublishedName(name string) string

PublishedName derives the identifier client script calls an action through, from its Go name.

Go's export rule leaves no choice about the identifier, and a script writes actions.getUser, so the published name is a second name and something has to say what it is. This is the default; a declaration may override it.

The rule is the leading run of capitals lowercased, leaving the last of the run intact when a lowercase letter follows it:

GetUser -> getUser
GetURL  -> getURL
URLFor  -> urlFor
ID      -> id

That last clause is what separates the run that is an initialism from the one capital that starts the next word. It is deliberately not the lowerFirst rule the JSON field default uses, which lowercases one rune and so reads URLFor as uRLFor. The field rule is a shipped default whose change would move the wire under every existing project; a published action name has no installed base, so the better rule is affordable here and only here.

func SplitRegistry added in v0.5.10

func SplitRegistry(files []Generated) (before []Generated, registry []Generated)

SplitRegistry separates the files a caller writes before the binding phase from the registry it writes after, per Generated.Registry.

func ValidateActionPrefix added in v0.2.3

func ValidateActionPrefix(prefix string, tree *Tree) error

ValidateActionPrefix reports whether a configured endpoint prefix is usable with the discovered routes.

The default prefix cannot collide, because a route directory beginning with an underscore is ignored by discovery. A configured one has no such protection, so it is checked against every discovered pattern here rather than surfacing as a ServeMux panic at startup.

func ValidateDirName

func ValidateDirName(name string) error

ValidateDirName reports whether a directory name can hold Go source as part of this module.

A route directory is also a Go package, so its name must be a legal import path element. The Go toolchain rejects an illegal element while matching package patterns, before build constraints are considered, so a single offending directory breaks go build ./... for the whole module rather than for that package alone. That is why bracketed Next.js spellings such as [id] cannot be used here.

func Write

func Write(files []Generated) error

Write writes generated files to disk, creating directories as needed.

Types

type Action added in v0.2.3

type Action struct {
	// Name is the exported Go function name.
	Name string
	// RelDir is the declaring package's directory relative to the route root,
	// using slashes. The route root package itself has an empty RelDir.
	RelDir string
	// Package and ImportPath name the declaring Go package. ImportPath is empty
	// unless Config.ImportBase was set.
	Package    string
	ImportPath string
	// File and Line locate the declaration, for diagnostics.
	File string
	Line int
	// Hash is the first ActionHashLength hexadecimal characters of the digest of
	// the declaring directory and the name.
	Hash string
	// Path is the endpoint path, such as /_action/9f3c2ab1e4d7/Rename.
	Path string
	// NativeForm reports that a template in the declaring package names this
	// handler from a form element, so a browser can submit to it with no runtime
	// loaded. It is what puts a POST on the page's own pattern.
	//
	// An action named only from a bare button sets nothing: such an element has
	// no native submit channel to serve, so registering a POST for it would take
	// a path an application may want and buy nothing. Discovery cannot see this,
	// because it reads Go sources; the template compiler reports it.
	NativeForm bool
	// Published is the identifier client script calls this action through. It is
	// the Go name in initialism-aware lowerCamelCase unless a declaration
	// overrode it, and it is a wire name rather than a second identity: a Go
	// rename moves Name and leaves an overridden Published where it was.
	Published string
	// Typed records that this action was admitted by a declaration rather than
	// by its signature, and Signature is what that signature says.
	//
	// A handler-shaped function is an action by existing, because nothing else
	// has that shape. An arbitrary signature distinguishes nothing, so a
	// declaration is what says this one is an action. The two kinds share an
	// address space, a hash and a table; what differs is that a typed action is
	// reached only by a script, never by a template.
	Typed     bool
	Signature TypedSignature
	// Wrapper is the symbol the registry registers for this action.
	//
	// A raw handler is registered as itself: it is the whole response and
	// nothing is generated around it. A typed one is registered as the
	// generated entry point emitted beside it, which is what lets the declared
	// function be unexported and what makes its signature free.
	Wrapper string
}

Action is one server function reachable from client code.

Every exported function in a route package with the handler signature becomes one, whether or not a template references it. A route package is imported by nothing but the generated registry, so an exported symbol in it is that route's surface rather than a general API; lower-casing the function is what keeps it private, because generated code in another package cannot reach an unexported symbol.

func DiscoverActions added in v0.2.3

func DiscoverActions(dir, relDir, pkg, importPath, prefix string) ([]Action, error)

DiscoverActions reads the Go sources of one route or layout package and returns its server functions, ordered by name.

dir is the package directory, relDir its path relative to the route root, and prefix the reserved endpoint prefix; an empty prefix uses DefaultActionPrefix.

A server function is recognized by the same signature a rung 3 page is, so this reads the net/http shape. Use DiscoverActionsWith for a tree whose handlers are written against another transport.

func DiscoverActionsWith added in v0.5.2

func DiscoverActionsWith(dir, relDir, pkg, importPath, prefix string, shape HandlerShape) ([]Action, error)

DiscoverActionsWith is DiscoverActions against a named handler signature. A zero shape uses DefaultHandlerShape.

func (Action) Pattern added in v0.2.3

func (a Action) Pattern() string

Pattern returns the stdlib ServeMux pattern for the endpoint, which is always POST.

func (Action) Selector added in v0.5.8

func (a Action) Selector() string

Selector is the opaque value a native form submit carries so the page's own POST route can tell which handler it is for.

It is spelled as the hash and the handler name together, matching the tail of Action.Path, so a reader of the DOM or of a network trace sees which Go function runs. The whole string is compared as one key, so no mismatch between the two halves is representable, and naming the function changes no security property: the hash hides structure and grants nothing either way.

type ActionDeclaration added in v0.5.10

type ActionDeclaration struct {
	// Import is the package path declaring the annotation.
	Import string
	// Package is the identifier that path is reached through when the file
	// imports it without an explicit alias.
	//
	// It has to be declared rather than derived, because a path's last element
	// is not always the package name: this module's own path ends in
	// tinybind-go and its package is httpbind. The handler shape check never
	// met that, resolving only net/http, where the two agree.
	Package string
	// Name is the function name within it.
	Name string
}

ActionDeclaration names the annotation that admits a typed server action.

The spelling belongs to whoever wraps this module: a framework writes pw.ServerAction(GetUser) and this module cannot fix that identifier. What it fixes is the shape it recognizes, which is a package-level declaration whose value is a call taking the function symbol and an optional published name.

func DefaultActionDeclaration added in v0.5.10

func DefaultActionDeclaration() ActionDeclaration

DefaultActionDeclaration is the annotation this module ships.

type Analysis

type Analysis struct {
	Route     Route
	Component ComponentSignature
	// Page describes the Go entry point. It is never nil; a route with no
	// page.go still reports RungTemplateOnly.
	Page *PageFunc
	// Inputs is what [Emitter.Decoder] binds for this route. Which declaration
	// supplies it depends on the rung; see [Analyze].
	Inputs []Value
}

Analysis is one route checked end to end: its template, its optional Go entry point, and the input list a generated decoder must bind.

func Analyze

func Analyze(route Route) (Analysis, error)

Analyze reads one route's template and logic file and checks them against each other.

The input list a decoder binds comes from a different declaration at each rung, because a different declaration is the thing the request reaches first:

  • RungTemplateOnly: the component parameters, since the request renders the component directly. first and the component parameters are that function's results.
  • RungHandlerPage: the route's dynamic segments as strings. The handler owns decoding, so the generated decoder is a convenience covering only what the filesystem already knows; anything else the handler reads itself.

Every problem found is reported, so one run surfaces more than the first.

It recognizes the net/http rung 3 signature. Use AnalyzeWith for a tree whose handlers are written against another transport.

func AnalyzeWith added in v0.5.2

func AnalyzeWith(route Route, shape HandlerShape, options ...htmlbind.AnalysisOption) (Analysis, error)

AnalyzeWith is Analyze against a named rung 3 signature. A zero shape uses DefaultHandlerShape.

type ComponentSignature

type ComponentSignature struct {
	Name string
	// Inputs are the ordinary parameters, in declaration order.
	Inputs []Value
	// Slots are the html parameters, which a wrapper fills rather than a
	// caller passing data.
	Slots []Value
}

ComponentSignature is one template declaration, split into the values a caller supplies and the slots composition fills.

func LayoutComponent

func LayoutComponent(path string, options ...htmlbind.AnalysisOption) (ComponentSignature, error)

LayoutComponent reads a layout template and returns its reserved declaration.

func PageComponent

func PageComponent(path string, options ...htmlbind.AnalysisOption) (ComponentSignature, error)

PageComponent reads a page template and returns its reserved declaration.

A tree whose templates read an implicit binding passes the same list its generate options carry, because a binding's name has to be known to analyze the template that reads it.

type ComposerArg

type ComposerArg struct {
	// Field is the layout parameter struct field.
	Field string
	// From is the route parameter struct field it reads.
	From string
}

ComposerArg is one layout input filled from the decoded route.

type ComposerLayout

type ComposerLayout struct {
	// Selector is the qualifier for symbols of this layout's package, such as
	// "users." It is empty when the layout lives in the page's own package.
	Selector string
	// Binder is the generated wrapper constructor, such as BindLayout.
	Binder string
	// ParamsType is the generated parameter struct, such as LayoutParams.
	ParamsType string
	// Args maps each declared layout input to the route field feeding it.
	Args []ComposerArg
}

ComposerLayout is one wrapper in a generated composer, already resolved to the selector, binder, and argument list the template writes.

type ComposerModel

type ComposerModel struct {
	Header     string
	Package    string
	Pattern    string
	Imports    []Import
	ParamsType string
	RenderFunc string
	// WriterType is the writer the generated composer takes.
	WriterType string
	// RequestParam is the request parameter name, empty when the composer
	// declares none.
	RequestParam string
	// Component is the page component name, which also prefixes its generated
	// parameter struct.
	Component string
	Layouts   []ComposerLayout
	Symbols   Symbols
}

ComposerModel is the data the composer template renders.

func (ComposerModel) Render added in v0.2.5

func (m ComposerModel) Render() RenderCall

Render describes the render call for this composer, which the template hands to the TemplateRender block.

type Config

type Config struct {
	// Root is the route root directory. Empty uses DefaultRootDir relative to
	// the working directory.
	Root string
	// ImportBase is the Go import path of the route root directory. Setting it
	// lets discovery compute an ImportPath for every route and layout, which is
	// what a generated registry needs to import them. It cannot be derived,
	// because the route root's position inside its module is not visible from
	// the directory alone.
	ImportBase string
	// PageFile, LayoutFile, DocumentFile, and LogicFile override the reserved
	// names. Empty values use the defaults.
	PageFile     string
	LayoutFile   string
	DocumentFile string
	LogicFile    string
}

Config selects the route root and the reserved file names. A zero Config uses the defaults.

type DecoderField

type DecoderField struct {
	// Go is the generated struct field name.
	Go string
	// Key is the path wildcard or query key it reads.
	Key string
	// Type is the declared Go type, which is a pointer when the input is
	// optional.
	Type string
	// Base is Type with the optional pointer removed, so it is the scalar the
	// parse call and the diagnostics name.
	Base string
	// Optional binds a pointer, left nil when the key is absent or its value is
	// empty. It is set for a query parameter only.
	Optional bool
	// IsQuery reads from the query string rather than the path.
	IsQuery bool
	// Required rejects an empty value. A catch-all is not required, because an
	// empty remainder is a legal match.
	Required bool
	// Parse is the call that converts raw into v, empty for a string.
	Parse string
	// Convert narrows the parse result, empty when the types already agree.
	Convert string
	// ErrCode and ErrMessage describe the failure of Parse.
	ErrCode    string
	ErrMessage string
	// MissingMessage describes an absent required path value.
	MissingMessage string
}

DecoderField is one input of a generated decoder, already lowered to everything the template needs to write it out.

type DecoderModel

type DecoderModel struct {
	Header      string
	Package     string
	Pattern     string
	Imports     []Import
	ParamsType  string
	DecodeFunc  string
	Fields      []DecoderField
	HasQuery    bool
	MissingCode string
	Symbols     Symbols
}

DecoderModel is the data the decoder template renders.

type Emitter

type Emitter struct {
	// Symbols are the identities the templates call.
	Symbols Symbols
	// HandlerShape is the rung 3 signature [Generate] recognizes. The zero value
	// uses [DefaultHandlerShape].
	//
	// It sits beside Symbols rather than with the analysis entry points because
	// both name the same transport, and a build that emitted one transport while
	// admitting the other's handler shape would fail in generated source rather
	// than in configuration.
	HandlerShape HandlerShape
	// ParamsType, DecodeFunc, and RenderFunc name the generated declarations, so
	// a framework can publish its own vocabulary without replacing a template.
	ParamsType   string
	DecodeFunc   string
	RenderFunc   string
	RegisterFunc string
	MuxFunc      string
	TableVar     string
	// RenderWriterType is the writer the generated composer takes. Empty uses
	// [DefaultRenderWriterType], which is what keeps a rung 3 handler free to
	// render into a buffer. It must be qualified by io, by Symbols.HTTPAlias, or
	// by Symbols.RuntimeAlias, because those are the packages the composer
	// imports.
	RenderWriterType string
	// RenderRequestParam adds a request parameter to the generated composer under
	// this name, so a "render" block override has the request in scope there as
	// well as in the registry handler. Empty declares none.
	//
	// It is off by default because the composer's contract is a writer: a handler
	// rendering into a buffer to choose its status has no response to hand over.
	RenderRequestParam string
	// GeneratedHeader is the first line of every emitted file. Empty uses
	// [GeneratedHeader], and a framework branding its own output replaces it.
	//
	// A run that changes it must also name the new prefix to the discovery pass,
	// which recognizes this module's own header and nothing else. An
	// unrecognized generated registry is analyzed as if a user had written it,
	// and its page registrations become documented API routes. Keeping the
	// default line and adding a brand line below it needs no such registration.
	GeneratedHeader string
	// ActionPrefix is the reserved path every server function endpoint hangs
	// below. Empty uses [DefaultActionPrefix]. A framework mounting under a
	// sub-path or owning its own URL namespace sets it, which is why it is not
	// the fixed value the endpoint hash is.
	ActionPrefix string
	// ActionTableVar names the generated list of endpoints. Every server
	// function is reachable whether or not a template references it, so the
	// list is what makes that surface inspectable.
	ActionTableVar string
	// ActionAttr is the attribute a lowered server-action writes in compiled
	// templates. Empty uses the htmlbind default.
	ActionAttr string
	// ClientHandlerAttr is the attribute an on-prefixed handler lowers into, and
	// ComponentParameterAttr the one a component's emitted parameters are written
	// to. Empty uses the htmlbind defaults. A framework driving its own client
	// runtime points them at that runtime's vocabulary.
	ClientHandlerAttr      string
	ComponentParameterAttr string
	// ActionSelectorField is the hidden field a generated form carries to say
	// which server function a native submit is for. Empty uses
	// [DefaultActionSelectorField]. It is written into the form by the template
	// compiler and read back by the generated page POST, so one setting moves
	// both halves.
	ActionSelectorField string
	// contains filtered or unexported fields
}

Emitter renders generated Go source. Its zero value is not usable; build one with NewEmitter.

func NewEmitter

func NewEmitter() *Emitter

NewEmitter returns an emitter with the built-in templates and the httpbind symbols.

func NewFastHTTPEmitter added in v0.5.2

func NewFastHTTPEmitter(transportImport string) *Emitter

NewFastHTTPEmitter returns an emitter whose whole output targets fasthttp: the decoder's request type, the registered handler's parameter list, and the rung 3 signature discovery accepts. transportImport names the fasthttp package; empty uses DefaultFastHTTPImport.

It exists so a backend is one call rather than two settings that must agree.

func (*Emitter) Clone

func (e *Emitter) Clone() (*Emitter, error)

Clone returns an independent emitter, so one configured base can be specialized per generation run without sharing template state.

func (*Emitter) Composer

func (e *Emitter) Composer(route Route, layouts []ComponentSignature) ([]byte, error)

Composer renders the per-route Render function.

layouts must hold one signature per entry of route.Layouts, in the same order. A layout that declares no slot parameter is rejected, because the template compiler emits no wrapper binder for it and the generated call would not compile.

func (*Emitter) Decoder

func (e *Emitter) Decoder(route Route, inputs []Value) ([]byte, error)

Decoder renders the typed route decoder for one route.

inputs is the page's declared input list: the route's dynamic segments in order, followed by the query parameters, read from the component's parameter list. The caller has already checked the shape; Decoder assumes it.

func (*Emitter) GeneratedHeaderPrefix added in v0.2.6

func (e *Emitter) GeneratedHeaderPrefix() string

GeneratedHeaderPrefix returns what a discovery pass must recognize to skip the files this emitter writes, which is the header without its comment marker and without the conventional ending.

It is the pairing for Emitter.GeneratedHeader: a framework branding its output passes this to the generator options, so the registry it just wrote is not analyzed as if a user had written it. For the default header the value is already recognized, so passing it changes nothing.

func (*Emitter) Parse

func (e *Emitter) Parse(name, text string) error

Parse replaces one named template. It returns an error when the text does not parse, leaving the emitter unchanged.

The replacement is compiled into a copy of the template set, so a framework may override the whole file shape with TemplateDecoder or only one nested block such as "error", "convert", or TemplateRender.

func (*Emitter) Registry

func (e *Emitter) Registry(tree *Tree, rootPackage string, analyses []Analysis, layouts map[string]ComponentSignature, actions []Action) ([]byte, error)

Registry renders the integrated ServeMux for a whole tree, into the route root package.

Putting it in the root is what makes every generated import point down the tree: the registry reaches route and layout packages below it, and none of them reaches back up. A per-route composer in a leaf package would have to import its ancestors, which with a registry in the root is a cycle.

analyses must hold one entry per route of the tree, layouts maps a layout's RelDir to its signature, and actions are the server functions discovered across the tree.

type Error

type Error struct {
	// Path is the offending file or directory.
	Path string
	// Message states what is wrong and, where possible, what to do instead.
	Message string
}

Error is one discovery failure, anchored at the file or directory that caused it.

func (*Error) Error

func (e *Error) Error() string

type GenerateOptions

type GenerateOptions struct {
	// Config selects the route root and reserved names.
	Config Config
	// RootPackage is the Go package clause of the route root directory, which is
	// where the registry is emitted. Empty derives it from the directory name.
	RootPackage string
	// Emitter renders the Go source. Nil uses [NewEmitter].
	Emitter *Emitter
	// ComponentSuffix, DecoderOutput, and RegistryOutput override the generated
	// file names.
	ComponentSuffix string
	DecoderOutput   string
	RegistryOutput  string
	// ActionResolver supplies the endpoint URL of a server action this tree does
	// not declare, so a framework can address a handler from its own route table.
	// A handler exported by the template's own route package always wins, which is
	// what keeps a resolver from silently retargeting a discovered action.
	ActionResolver func(name string) (url string, ok bool)
	// ScriptResolver reads the component script blocks of one template and
	// answers what each block exposes and which of the component's parameters to
	// emit onto its root element.
	//
	// It is how a framework that parses JavaScript supplies what this module
	// refuses to read. Configuring one costs a second parse of every template
	// carrying a block, because the blocks have to be reported before the compile
	// that consumes the answers can run; a tree with no resolver parses once, as
	// it always has.
	ScriptResolver func(path string, scripts []htmlbind.ComponentScript) (ScriptAnswers, error)
	// DataAttributePrefix is the boundary attribute prefix compiled into every
	// template in the tree. Empty uses the htmlbind default.
	//
	// A project configuring its runtime with a prefix of its own sets the same
	// value here. Without it a page tree takes the default while a registered
	// template takes the configured one, and two halves of one project disagree
	// about an attribute name they both have to read.
	DataAttributePrefix string
	// PublicURLBase is the URL prefix an extracted asset's reference is computed
	// against. Empty uses the htmlbind default.
	//
	// It has to name where the caller actually serves Result.Assets from, since
	// the URL it produces is written into the generated component and nothing
	// downstream can correct it.
	PublicURLBase string
	// ImplicitBindings are the names an embedder puts in every template's
	// scope, and Messages plus MessageContextBinding are the message symbol
	// table and the binding supplying those symbols' leading argument.
	//
	// They are here because a page tree is a second compile path: a seam filled
	// only where templates are compiled as a package would leave every
	// filesystem route without the feature, which is the shape of
	// .knowledge requirement:route-package-context-externals.
	ImplicitBindings      []htmlbind.ImplicitBinding
	Messages              map[string]htmlbind.MessageSymbol
	MessageContextBinding string
}

GenerateOptions configures one whole-tree generation run.

type Generated

type Generated struct {
	// Path is the absolute destination.
	Path string
	// Source is the formatted Go source.
	Source []byte
	// Registry marks the one file registering every route and endpoint.
	//
	// It is flagged because it is the one file whose write has an order. It
	// names the entry point of every typed server action, and those are emitted
	// by the binding phase, which runs after this one because it type-checks
	// each route package and a package does not type-check until the compiled
	// component is in it. Writing the registry first would leave the root
	// package naming a symbol nothing had written yet.
	//
	// Writing it last costs nothing: the binding phase is required to skip it
	// anyway, per rule:generated-source-not-discovered, so writing it earlier
	// only produces a file that phase must ignore.
	Registry bool
}

Generated is one emitted Go file and where it belongs.

func Generate

func Generate(options GenerateOptions) ([]Generated, error)

Generate discovers the tree and emits its Go files, discarding the public assets its templates extracted. Callers that write files use GenerateTree instead.

Discarding them is safe only for a tree whose templates declare no style or script block. One that does gets a generated component referencing an asset URL, and no bytes for anything to serve there.

type HandlerShape added in v0.5.2

type HandlerShape struct {
	// Import is the package path the parameter types come from. The check is
	// syntactic, so the qualifier is resolved from the file's own import of this
	// path rather than from type information.
	Import string
	// Types are the parameter types, in order, written without a qualifier and
	// with a leading * where the parameter is a pointer: ResponseWriter and
	// *Request name the net/http pair.
	Types []string
	// GeneratedHeaders names header prefixes, beside this module's own, whose
	// files action discovery must skip. A framework branding its generated
	// output writes a header nothing here recognizes on its own; this module's
	// own prefix is always recognized, so a caller never lists it.
	GeneratedHeaders []string
	// Declaration names the annotation that admits a typed server action, whose
	// signature this shape says nothing about. A zero value uses the annotation
	// this module ships.
	//
	// It sits here because the two admission rules are read together: a
	// function is an action by having this shape or by being declared, and a
	// caller configuring one transport configures both at once.
	Declaration ActionDeclaration
}

HandlerShape is the rung 3 signature a page function is recognized by: the transport package it names and the parameter types it takes from that package.

It is configuration rather than a constant because the shape is what a transport is, at this seam: net/http declares a writer and a request, and fasthttp declares one value carrying both. A recognizer keyed on net/http alone reads a fasthttp handler as a malformed typed page and reports a signature error for a declaration that is correct.

func DefaultHandlerShape added in v0.5.2

func DefaultHandlerShape() HandlerShape

DefaultHandlerShape is the ordinary http.HandlerFunc signature.

func FastHTTPHandlerShape added in v0.5.2

func FastHTTPHandlerShape(transportImport string) HandlerShape

FastHTTPHandlerShape is the fasthttp handler signature, where one value carries both halves and there is therefore one parameter rather than two. transportImport names the fasthttp package; empty uses DefaultFastHTTPImport.

type Import

type Import struct {
	Path  string
	Alias string
	// Group starts a new import group before this line, which is how the
	// standard library and the runtime end up separated.
	Group bool
}

Import is one import line of a generated file.

type Layout

type Layout struct {
	// RelDir is the layout directory relative to the route root, using slashes.
	// The root layout has an empty RelDir.
	RelDir string
	// File is the absolute path of the layout template.
	File string
	// Package is the Go package name of the layout directory.
	Package string
	// ImportPath is the Go import path of the layout directory. It is empty
	// unless Config.ImportBase was set.
	ImportPath string
	// Params are the dynamic segments in scope at this level, outermost first.
	// A layout may only depend on segments at or above its own directory.
	Params []Segment
}

Layout is one ancestor wrapper contributing to a page.

type Package added in v0.2.5

type Package struct {
	// RelDir is the directory relative to the route root, using slashes. The
	// route root package itself has an empty RelDir.
	RelDir string
	// Dir is the absolute directory.
	Dir string
	// Name is the Go package name.
	Name string
	// ImportPath is the Go import path. It is empty unless Config.ImportBase was
	// set.
	ImportPath string
}

Package is one Go package a route tree contains.

type PageFunc

type PageFunc struct {
	Rung Rung
	// File is the page.go path, empty at RungTemplateOnly with no file.
	File string
	// Line is the line of the func Page declaration, zero when absent.
	Line int
}

PageFunc describes the Go entry point of one route.

func InspectLogic

func InspectLogic(path string) (*PageFunc, error)

InspectLogic reads one page.go and classifies its Page declaration. An empty path, or a file declaring no Page, yields RungTemplateOnly.

It recognizes the net/http rung 3 signature. Use InspectLogicWith for a tree whose handlers are written against another transport.

func InspectLogicWith added in v0.5.2

func InspectLogicWith(path string, shape HandlerShape) (*PageFunc, error)

InspectLogicWith is InspectLogic against a named rung 3 signature. A zero shape uses DefaultHandlerShape.

type RegistryAction added in v0.2.3

type RegistryAction struct {
	Pattern string
	Path    string
	Hash    string
	Name    string
	RelDir  string
	// Selector qualifies the handler's package, such as "id_." It is empty for
	// a handler in the root package itself.
	Selector string
	// Symbol is what the registration names: the handler itself for a raw
	// action, the generated entry point for a typed one.
	Symbol string
	// Published is the identifier client script calls the action through, and
	// Typed reports which admission rule let it in.
	Published string
	Typed     bool
}

RegistryAction is one server function endpoint lowered to what the registry template writes.

type RegistryFormAction added in v0.5.8

type RegistryFormAction struct {
	// Selector is the opaque value the form's hidden field carries.
	Selector string
	// Package qualifies the handler symbol, such as "id_." It is empty for a
	// handler in the root package itself.
	Package string
	// Name is the exported Go function name.
	Name string
}

RegistryFormAction is one server function a page's POST route dispatches to.

type RegistryModel

type RegistryModel struct {
	Header         string
	Package        string
	Imports        []Import
	RegisterFunc   string
	MuxFunc        string
	TableVar       string
	ActionTableVar string
	DecodeFunc     string
	Routes         []RegistryRoute
	Actions        []RegistryAction
	Symbols        Symbols
	// ActionSelectorField is the hidden field the generated dispatcher reads the
	// selector out of. The template compiler wrote it into the form.
	ActionSelectorField string
}

RegistryModel is the data the registry template renders.

func (RegistryModel) Render added in v0.2.5

func (m RegistryModel) Render(route RegistryRoute) RenderCall

Render describes the render call of one route's generated handler, which the registry template hands to the TemplateRender block. The request is always in scope here, so an override reaches it without any setting.

type RegistryRoute

type RegistryRoute struct {
	Pattern string
	Path    string
	RelDir  string
	// ParamNames are the dynamic segment names, in route order.
	ParamNames []string
	// Selector qualifies symbols of the route's package, such as "id_." It is
	// empty for a route in the root package itself.
	Selector string
	// Raw registers the route's own handler directly and generates no body.
	Raw bool
	// PageFields fills the page component parameter struct.
	PageFields []ComposerArg
	// Layouts are the ancestor wrappers, outermost first.
	Layouts []ComposerLayout
	// PostPattern is the pattern the page's own POST route registers under,
	// empty where the route reaches no server function. A form carrying
	// server-action posts here rather than to the handler's own address, because
	// a form declaring no action submits to the document URL and that is what
	// carries the path parameters a handler serving /users/{id} needs.
	PostPattern string
	// FormActions are the server functions a native submit on this page can
	// reach: the ones declared in the route's own package and in every layout
	// wrapping it. One POST registration serves them all and the generated
	// dispatcher branches on the selector.
	FormActions []RegistryFormAction
}

RegistryRoute is one route lowered to what the registry template writes.

type RenderCall added in v0.2.5

type RenderCall struct {
	// Writer is the writer identifier, always present.
	Writer string
	// Request is the request identifier, empty where none is in scope. The
	// registry handler always has one; the composer has one only when
	// [Emitter.RenderRequestParam] declared it.
	Request string
	// Wrappers is the layout chain slice identifier, empty when the page has no
	// ancestor layout and renders on its own.
	Wrappers string
	// Leaf is the expression building the page fragment, such as Page(params).
	Leaf string
	// Options is the render option slice identifier, empty where none is in
	// scope.
	Options string
	// Symbols are the identities generated code calls.
	Symbols Symbols
}

RenderCall is the data the TemplateRender block renders. Every field but Symbols is the name of something already in scope at the call, so an override composes its own call out of them rather than guessing what it may reference.

func (RenderCall) Chain added in v0.2.5

func (c RenderCall) Chain() string

Chain is Wrappers, or nil when the page has no ancestor layout. It is what an entry point that always takes a chain argument writes, so such an override needs no branch of its own:

web.WriteHTML({{ .Writer }}, {{ .Request }}, {{ .Chain }}, {{ .Leaf }})

func (RenderCall) Context added in v0.5.2

func (c RenderCall) Context() string

Context is the expression yielding the request's context.Context, empty where no request is in scope. An override needing a context writes it rather than spelling a .Context() call, which is a method one transport has and the other does not need.

func (RenderCall) RenderOptions added in v0.3.7

func (c RenderCall) RenderOptions() string

RenderOptions is what the default render block passes: the caller's options, followed by the request's context when a request is in scope.

The context is what a synchronous external declaring one receives. A render given none falls back to background, so without this a page could name such an external, compile, and read a value belonging to no request — a silent wrong answer rather than the build error the missing option would otherwise be.

It goes last because the caller's options are installed once for the whole mux while this one is per request, so the specific value wins over the static one.

The caller's slice is copied rather than appended in place, because every handler closure shares it and two requests appending at once would write the same backing array slot.

type Result added in v0.5.6

type Result struct {
	// Files are the emitted Go sources: a compiled component per template, a
	// typed decoder per route, and one registry in the route root.
	Files []Generated
	// Assets are the stylesheets and component scripts the tree's templates
	// extracted, deduplicated across the tree. A file name carries the hash of
	// its own bytes, so two templates producing one name produced identical
	// content and the duplicate is dropped rather than returned twice.
	//
	// Nothing writes them. Each carries Base, Extension, Content, and the URL it
	// was compiled against, which is what a caller needs to put the file where
	// that URL resolves. A page declaring a script block whose asset is dropped
	// leaves a reference to a file that answers 404.
	Assets []htmlbind.Asset
	// Actions is every server function the tree discovered, raw and typed
	// alike, in the order the registry registers them.
	//
	// A caller needs the typed ones: the entry point each is registered under
	// is emitted by the binding phase, which runs after this, so the signature
	// read here has to reach that phase. The raw ones are reported beside them
	// because one table is what every other consumer already reads.
	Actions []Action
}

Result is everything one whole-tree generation run produced.

Go sources and public assets are two lists rather than one tagged list because only one of them has a destination this package can compute. A generated component belongs beside the template that produced it; an extracted asset belongs wherever the caller serves PublicURLBase from, which is the caller's layout and not the tree's.

func GenerateTree added in v0.5.6

func GenerateTree(options GenerateOptions) (Result, error)

GenerateTree discovers the tree and emits everything it needs: the compiled components for each template, a typed decoder per route, one registry in the route root carrying the integrated ServeMux, and the public files the templates extracted.

Nothing is written to disk; the caller owns that, which is what lets a framework post-process or redirect the output.

type Route

type Route struct {
	// RelDir is the page directory relative to the route root, using slashes.
	// The root page has an empty RelDir.
	RelDir string
	// Dir is the absolute page directory.
	Dir string
	// PageFile is the absolute path of the page template.
	PageFile string
	// LogicFile is the absolute path of page.go, or empty when absent.
	LogicFile string
	// Package is the Go package name for the page directory.
	Package string
	// ImportPath is the Go import path of the page directory. It is empty
	// unless Config.ImportBase was set.
	ImportPath string
	// Path is the URL path pattern, such as /users/{id}.
	Path string
	// Segments are every directory from the route root to the page directory.
	Segments []Segment
	// Params are the dynamic and catch-all segments only, in route order.
	Params []Segment
	// Layouts are the ancestor layouts, outermost first.
	Layouts []Layout
}

Route is one discovered page.

func (Route) Pattern

func (r Route) Pattern() string

Pattern returns the stdlib ServeMux pattern for the page, which is always a GET route; see decision:route-handler-shape.

The root page registers as /{$} rather than /, because a bare / is a prefix pattern in the standard library and would answer every unmatched path instead of letting it be a 404.

type Rung

type Rung uint8

Rung is how much of the request path a route hands to Go, from a template with no Go file at all up to a plain net/http handler.

const (
	// RungTemplateOnly is a route with no page.go, or one declaring no Page.
	// The whole handler is generated and the template's own external calls
	// supply the data.
	RungTemplateOnly Rung = iota + 1
	// RungHandlerPage is a Page that is an ordinary http.HandlerFunc and owns
	// the whole response.
	RungHandlerPage
)

func (Rung) String

func (r Rung) String() string

type ScriptAnswers added in v0.5.8

type ScriptAnswers struct {
	Handlers   map[string]htmlbind.ClientHandlerSet
	Parameters map[string][]string
}

ScriptAnswers is what a GenerateOptions.ScriptResolver returns for one template: what each component's script block exposes, and which of each component's parameters to emit onto its root element.

Both maps are keyed by component declaration name, which is unique within one template module. A component absent from Handlers is unchecked, and one absent from Parameters emits nothing.

type Segment

type Segment struct {
	// Dir is the directory name exactly as it appears on disk.
	Dir string
	// Name is the parameter name for a dynamic or catch-all segment, and the
	// literal URL segment for a static one.
	Name string
	Kind SegmentKind
}

Segment is one directory of the route tree.

func ParseSegment

func ParseSegment(dir string) Segment

ParseSegment reads the segment kind and parameter name out of a directory name. Two trailing underscores mark a catch-all, one marks a dynamic segment, and anything else is static.

type SegmentKind

type SegmentKind uint8

SegmentKind classifies how a directory contributes to the URL.

const (
	// StaticSegment contributes the directory name literally.
	StaticSegment SegmentKind = iota
	// DynamicSegment binds one path element to a named parameter.
	DynamicSegment
	// CatchAllSegment binds the remainder of the path to a named parameter.
	CatchAllSegment
)

func (SegmentKind) String

func (k SegmentKind) String() string

type Symbols

type Symbols struct {
	// HTTPImport and HTTPAlias name the package providing Request and
	// PathValue. The alias is what generated source writes.
	HTTPImport string
	HTTPAlias  string
	// MuxImport and MuxAlias name the package providing the router the registry
	// installs on. They are separate from the pair above because the same alias
	// would otherwise supply both the router and Request: a framework wanting
	// only its own router would drag the request package along with it and be
	// left replacing the whole registry template.
	MuxImport string
	MuxAlias  string
	// MuxType is the router type the generated registration function takes, and
	// MuxConstructor the call that builds one. Both are written verbatim, so a
	// framework whose router is an interface writes no pointer. An empty
	// MuxConstructor omits the constructor function, which is what a router
	// needing arguments generated code cannot supply wants.
	//
	// Generated code registers through HandleFunc alone, so a one-method
	// interface is enough to satisfy either.
	MuxType        string
	MuxConstructor string
	// CatchAllSuffix is what the router spells inside a catch-all segment where
	// net/http spells "...", so {rest...} becomes {rest} plus this. Empty uses
	// net/http's own marker, which leaves the pattern as discovered.
	//
	// RootPattern is the path the tree root registers under. Empty uses
	// net/http's "/{$}", the exact-match marker that keeps the root from
	// matching every path below it.
	//
	// Both exist because a router that does not read Go 1.22 patterns does not
	// merely fail on these two: it reads "{rest...}" as a parameter named
	// "rest..." and "{$}" as one named "$", so the route is silently installed
	// somewhere else rather than rejected.
	//
	// Neither has an "unsupported" spelling. Unlike the transform's router
	// target, where every field is caller-declared and an unset one is genuinely
	// unknown, these default to a working router, so an unset field cannot be
	// told from a router that reads Go 1.22 syntax and needs no rewrite.
	CatchAllSuffix string
	RootPattern    string
	// RequestType is the type of the request value generated code receives,
	// written verbatim. Empty spells the net/http request from HTTPAlias.
	//
	// It is separate from HTTPAlias because an alias reaches the spelling of a
	// type and not its shape: a transport carrying the request and the response
	// in one value has one parameter where net/http has two, which no renaming
	// of the package can express.
	RequestType string
	// HandlerParams is the parameter list an emitted handler literal declares.
	// Empty spells the net/http pair from HTTPAlias.
	HandlerParams string
	// Writer and Request are the identifiers a generated handler body uses for
	// the response and the request. Empty uses w and r.
	//
	// They are the same identifier on a transport whose one value carries both,
	// which is what collapses a runtime call's leading arguments; see
	// [Symbols.TransportArgs].
	Writer  string
	Request string
	// RequestIsContext records that the request value is itself a
	// context.Context, as fasthttp's RequestCtx is. When false the context is
	// read with a .Context() call, which is the net/http spelling.
	RequestIsContext bool
	// ErrorImport and ErrorAlias name the package providing the constructors
	// below and the request accessors. An empty ErrorImport suppresses the
	// import, which is what a template that reports errors some other way wants.
	ErrorImport string
	ErrorAlias  string
	// BadRequest and Problem are selectors on ErrorAlias, naming the error value
	// a decoder builds. WriteError is the selector a generated handler writes a
	// failure through, taking the transport values followed by the error.
	BadRequest string
	Problem    string
	WriteError string
	// PathValue, QueryValues, and QueryLookup are selectors on ErrorAlias naming
	// the request accessors a generated decoder reads through.
	//
	// The decoder calls these rather than spelling methods on the request value
	// because fasthttp has no path routing of its own: its PathValue reads
	// whatever the router stored, so there is no method on the transport for a
	// method-shaped decoder to call. Routing both transports through the runtime
	// is what lets one decoder template serve either.
	PathValue   string
	QueryValues string
	QueryLookup string
	// ActionSelector and DispatchAction are selectors on ErrorAlias naming the
	// two halves of the page's own POST route: reading which server function a
	// native form submit named, and running it with the post-redirect-get default
	// applied when it writes nothing.
	//
	// They sit here for the same reason the accessors above do. Observing whether
	// a handler wrote a response means wrapping the transport's own writer, which
	// no template can spell portably.
	ActionSelector string
	DispatchAction string
	// StrconvImport is the package providing the scalar parsers. It is only
	// imported when a route actually declares a non-string input.
	StrconvImport string
	StrconvAlias  string
	// RuntimeImport and RuntimeAlias name the HTML rendering runtime the
	// composer calls.
	RuntimeImport string
	RuntimeAlias  string
}

Symbols names the identities generated code calls. Repointing them is the cheap half of customization: a framework that only wants its own error constructor changes these and keeps every default template.

func DefaultSymbols

func DefaultSymbols() Symbols

DefaultSymbols targets the httpbind runtime this module ships.

func FastHTTPSymbols added in v0.5.2

func FastHTTPSymbols(transportImport string) Symbols

FastHTTPSymbols targets the fasthttpbind runtime this module ships. transportImport names the fasthttp package; empty uses DefaultFastHTTPImport.

The runtime is imported under the httpbind alias whichever package it is, so every selector a generated body writes is the one the net/http output writes. What differs is the request type, the handler parameter list, and the identifier both halves collapse onto.

MuxType is a one-method interface rather than a concrete type because fasthttp ships no router: naming one here would decide which third-party package an application depends on. Any router declaring HandleFunc satisfies it, and MuxConstructor is empty because this package cannot build a router it does not name.

func (Symbols) ContextOf added in v0.5.2

func (s Symbols) ContextOf(ident string) string

ContextOf is the expression yielding the context.Context of the request value named ident. A transport whose request value is already a context is that value; otherwise it is read with a call.

It takes the identifier rather than reading Request because the composer's request parameter is named by Emitter.RenderRequestParam and need not be the one a handler body uses.

func (Symbols) RoutePath added in v0.5.2

func (s Symbols) RoutePath(route Route) string

RoutePath spells one route's path for the configured router. Only the catch-all marker and the tree root differ between the routers this seam has met; every other segment is spelled {name} by all of them, which is why a route carries over verbatim.

func (Symbols) RoutePattern added in v0.5.2

func (s Symbols) RoutePattern(route Route) string

RoutePattern is Symbols.RoutePath with the method the tree serves, which is what the registry registers under.

func (Symbols) RoutePostPattern added in v0.5.8

func (s Symbols) RoutePostPattern(route Route) string

RoutePostPattern is the same address registered for the page's own POST route, which a native form submit reaches. A page carries GET for itself and POST for its server functions, and no other method.

func (Symbols) TransportArgs added in v0.5.2

func (s Symbols) TransportArgs() string

TransportArgs is the leading argument list of a runtime call taking both the writer and the request, such as WriteError. Where one value carries both it is that value written once, which is how a two-argument call on net/http becomes a one-argument call on fasthttp without the template branching.

type Tree

type Tree struct {
	// Root is the absolute route root directory.
	Root string
	// ImportBase is the Go import path of Root, copied from the Config so a
	// caller reading the tree back needs no second source for it. It is empty
	// unless Config.ImportBase was set.
	ImportBase string
	// DocumentFile is the absolute path of the root document shell, or empty.
	DocumentFile string
	// Routes are the discovered pages, ordered by path.
	Routes []Route
}

Tree is a discovered route tree.

func Discover

func Discover(cfg Config) (*Tree, error)

Discover walks the configured route root and returns its routes. Every problem it finds is reported; the returned error joins them so one run surfaces more than the first mistake. A non-nil Tree is still returned alongside errors so a caller may report and continue.

func (*Tree) Packages added in v0.2.5

func (t *Tree) Packages() []Package

Packages lists every Go package the tree contains: the route root, every route directory, and every layout directory. The root comes first and the rest are ordered by directory.

It is what a caller runs the binder generator over, which is what makes httpbind.Bind work inside a page or a server action. A binder is generated per package from the Bind call sites inside it, so a route package nobody analyzes has nothing to dispatch through at runtime. Run it after the tree's own generated files are on disk, because analysis type-checks the package.

Doing so puts no page route and no action endpoint into an OpenAPI document: the only registrations are in the generated registry, and discovery skips what tinybind generated.

type TypedSignature added in v0.5.10

type TypedSignature struct {
	// Params are the declared inputs, in order, after any leading context has
	// been trimmed. Each carries its name and the source text of its type.
	Params []Value
	// TakesContext records that the declaration opened with a context.Context,
	// on the terms the typed page entry point already reads one.
	TakesContext bool
	// Result is the type of the single non-error result, empty when the
	// function returns only an error.
	Result string
}

TypedSignature is what a declared function's signature says, read as source text rather than resolved.

Nothing here needs a type checker. The address, the published name and the argument list are all readable from the declaration, and the phase that builds the argument struct and its codec does type-check, so resolving a parameter's type is that phase's job rather than this one's.

type Value

type Value struct {
	// Name is the declared identifier. A result is usually unnamed, leaving
	// this empty.
	Name string
	// Type is the source text of the type expression, such as string or
	// []Order.
	Type string
}

Value is one declared parameter or result of a typed Page.

Jump to

Keyboard shortcuts

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