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
- func ActionHash(relDir, name string) string
- func ActionPath(prefix, hash, name string) string
- func EmitDecoder(route Route, inputs []Value) ([]byte, error)
- func ExportedName(name string) string
- func PackageName(dir string) string
- func Validate(route Route, fn *PageFunc, componentParams []Value) []error
- func ValidateActionPrefix(prefix string, tree *Tree) error
- func ValidateDirName(name string) error
- func Write(files []Generated) error
- type Action
- type Analysis
- type ComponentSignature
- type ComposerArg
- type ComposerLayout
- type ComposerModel
- type Config
- type DecoderField
- type DecoderModel
- type Emitter
- func (e *Emitter) Clone() (*Emitter, error)
- func (e *Emitter) Composer(route Route, layouts []ComponentSignature) ([]byte, error)
- func (e *Emitter) Decoder(route Route, inputs []Value) ([]byte, error)
- func (e *Emitter) GeneratedHeaderPrefix() string
- func (e *Emitter) Parse(name, text string) error
- func (e *Emitter) Registry(tree *Tree, rootPackage string, analyses []Analysis, ...) ([]byte, error)
- type Error
- type GenerateOptions
- type Generated
- type Import
- type Layout
- type Package
- type PageFunc
- type RegistryAction
- type RegistryModel
- type RegistryRoute
- type RenderCall
- type Route
- type Rung
- type Segment
- type SegmentKind
- type Symbols
- type Tree
- type Value
Constants ¶
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.
const ( RouteParamsType = "RouteParams" DecodeRouteFunc = "DecodeRoute" )
Names of the symbols the default templates produce in a route package.
const ( CodeInvalidPath = "invalid_path_parameter" CodeInvalidQuery = "invalid_query_parameter" CodeMissingPath = "missing_path_parameter" )
Error codes the default decoder template reports.
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.
const ( RegisterFunc = "Register" MuxFunc = "NewServeMux" TableVar = "Routes" ActionTableVar = "Actions" )
Default names of the registry's generated declarations.
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.
const ActionHashLength = 12
ActionHashLength is how many hexadecimal characters of the digest an endpoint carries. It is fixed rather than configurable.
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.
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.
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.
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.
const RenderFunc = "Render"
RenderFunc is the name of the generated composer.
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.
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.
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.
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.
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
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
ActionPath builds the endpoint path for one handler.
func EmitDecoder ¶
EmitDecoder renders the typed route decoder for one route using the default emitter. See Emitter.Decoder to customize the output.
func ExportedName ¶
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 ¶
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 Validate ¶
Validate cross-checks a typed Page against the route it serves. It returns every problem it finds so one run reports more than the first.
componentParams is the page component's declared parameter list, which a typed Page must reproduce as its results. Passing nil skips that half of the check, which is what a caller does before the template has been compiled.
func ValidateActionPrefix ¶ added in v0.2.3
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 ¶
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.
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
}
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
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.
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 ¶
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.
- RungTypedPage: the func Page parameters, since the request reaches Go 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.
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) (ComponentSignature, error)
LayoutComponent reads a layout template and returns its reserved declaration.
func PageComponent ¶
func PageComponent(path string) (ComponentSignature, error)
PageComponent reads a page template and returns its reserved declaration.
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
// 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
// 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 (*Emitter) Clone ¶
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 ¶
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. It is the component parameter list at RungTemplateOnly and the func Page parameter list at RungTypedPage. The caller has already checked the shape with Validate; Decoder assumes it.
func (*Emitter) GeneratedHeaderPrefix ¶ added in v0.2.6
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 ¶
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.
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)
}
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
}
Generated is one emitted file and where it belongs.
func Generate ¶
func Generate(options GenerateOptions) ([]Generated, error)
Generate discovers the tree and emits every file it needs: the compiled components for each template, a typed decoder per route, and one registry in the route root carrying the integrated ServeMux.
Nothing is written to disk; the caller owns that, which is what lets a framework post-process or redirect the output.
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
// Params and Results are populated at RungTypedPage only. Params excludes a
// leading context.Context and Results excludes the trailing error.
Params []Value
Results []Value
// TakesContext records that the declaration opened with a context.Context.
//
// It is trimmed out of Params rather than counted in them, so "Params are
// the URL inputs, in route order" stays true and neither the route-order
// check nor the generated decoder has to carry an offset. A context is not
// a URL input: it arrives from the request rather than from the address,
// which is why it cannot be spelled as one.
TakesContext bool
}
PageFunc describes the Go entry point of one route.
func InspectLogic ¶
InspectLogic reads one page.go and classifies its Page declaration. An empty path, or a file declaring no Page, yields RungTemplateOnly.
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
}
RegistryAction is one server function endpoint lowered to what the registry template writes.
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
}
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
// Call is set when a typed func Page must run before rendering.
Call bool
// CallResults is the assignment prefix for that call, such as "u, err :=".
CallResults string
// CallArgs is the argument list for that call, read from the decoded route.
CallArgs string
// PageFields fills the page component parameter struct.
PageFields []ComposerArg
// Layouts are the ancestor wrappers, outermost first.
Layouts []ComposerLayout
}
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) 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 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 ¶
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 // RungTypedPage is a Page taking the route's inputs and returning the // values the template renders, followed by an error. RungTypedPage // RungHandlerPage is a Page that is an ordinary http.HandlerFunc and owns // the whole response. RungHandlerPage )
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 ¶
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
// ErrorImport and ErrorAlias name the package providing the constructors
// below. 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 (w, r, err).
BadRequest string
Problem string
WriteError 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.
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 ¶
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
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.