Documentation
¶
Overview ¶
Package gsx is the runtime that gsx-generated code calls to stream HTML to an io.Writer. It is dependency-free (standard library only).
Index ¶
- func AttrString(v any) (string, error)
- func Class(s string) conditionalPart
- func ClassIf(s string, on bool) conditionalPart
- func ClassJoin(parts ...conditionalPart) string
- func ClassString(merge func(classes []string) string, parts ...conditionalPart) string
- func DefaultClassMerge(classes []string) string
- func EscapeJSRegexp(s string) string
- func EscapeJSStr(s string) string
- func EscapeJSTmpl(s string) string
- func EscapeJSVal(v any) string
- func FilterCSS(s string) string
- func NonceFromContext(ctx context.Context) string
- func Style(s string) conditionalPart
- func StyleIf(s string, on bool) conditionalPart
- func StyleString(parts ...conditionalPart) string
- func StyleValue(v any) string
- func URLPrefixMatch(key string, prefixes []string) bool
- func URLSuffixMatch(key string, suffixes []string) bool
- func WithNonce(ctx context.Context, nonce string) context.Context
- type Attr
- type AttrMap
- type AttrSinks
- type Attrs
- func (a Attrs) Class() string
- func (a Attrs) Get(key string) (any, bool)
- func (a Attrs) GetFold(key string) (any, bool)
- func (a Attrs) Has(key string) bool
- func (a Attrs) Merge(other Attrs) Attrs
- func (a Attrs) Style() string
- func (a Attrs) Take(key string) (any, Attrs)
- func (a Attrs) Without(keys ...string) Attrs
- func (a Attrs) WithoutFold(keys ...string) Attrs
- func (a Attrs) WithoutFunc(drop func(key string) bool) Attrs
- type Func
- type Node
- type RawCSS
- type RawJS
- type RawURL
- type Toggle
- type Writer
- func (gw *Writer) AttrAny(v any)
- func (gw *Writer) AttrAnyToggle(name string, v any)
- func (gw *Writer) AttrValue(s string)
- func (gw *Writer) BoolAttr(name string, on bool)
- func (gw *Writer) CSS(s string)
- func (gw *Writer) Class(merge func(classes []string) string, parts ...conditionalPart)
- func (gw *Writer) ClassMerged(merge func(classes []string) string, extra string, parts ...conditionalPart)
- func (gw *Writer) Err() error
- func (gw *Writer) FloatInto(buf []byte, f float64)
- func (gw *Writer) IntInto(buf []byte, n int64)
- func (gw *Writer) JSRegexp(s string)
- func (gw *Writer) JSRegexpAttr(s string)
- func (gw *Writer) JSStr(s string)
- func (gw *Writer) JSStrAttr(s string)
- func (gw *Writer) JSTmpl(s string)
- func (gw *Writer) JSTmplAttr(s string)
- func (gw *Writer) JSVal(v any)
- func (gw *Writer) JSValAttr(v any)
- func (gw *Writer) Node(ctx context.Context, n Node)
- func (gw *Writer) NodeResult(err error)
- func (gw *Writer) Nonce(ctx context.Context)
- func (gw *Writer) PIName(s string)
- func (gw *Writer) RefreshContent(s string)
- func (gw *Writer) RefreshContentVal(v any)
- func (gw *Writer) S(s string)
- func (gw *Writer) Spread(ctx context.Context, tag string, a Attrs, sinks AttrSinks, excluded []string)
- func (gw *Writer) Srcset(s string)
- func (gw *Writer) SrcsetVal(v any)
- func (gw *Writer) Style(parts ...conditionalPart)
- func (gw *Writer) StyleMerged(rootStyle, bagStyle string)
- func (gw *Writer) Text(s string)
- func (gw *Writer) TextAny(v any)
- func (gw *Writer) URL(s string)
- func (gw *Writer) URLImage(s string)
- func (gw *Writer) URLImageVal(v any)
- func (gw *Writer) URLVal(v any)
- func (gw *Writer) UintInto(buf []byte, n uint64)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AttrString ¶
AttrString converts a dynamically typed renderable value to the same raw string used by AttrAny before HTML attribute escaping.
func Class ¶
func Class(s string) conditionalPart
Class is an unconditional class contribution used by generated code.
func ClassJoin ¶
func ClassJoin(parts ...conditionalPart) string
ClassJoin flattens the on, non-empty parts into a single class string, applying only the built-in structural last-wins dedup (NOT the configured ClassMerger). It is for placing a composable class into an Attrs bag (the "class" entry a child component receives as fallthrough): the consuming root applies the configured merger exactly once over the root's own classes plus this bag string (Attrs.Class()), so running the configured merger here too would be redundant — and, with an expensive Tailwind-style merger, double the per-element cost.
The structural dedup is kept (cheap, no merger call) so a composable class with repeated tokens resolves to the same string whether it sits on a root or is forwarded to a child — matching DefaultClassMerge's "keep last occurrence" rule for the common (default-merger) case.
func ClassString ¶
ClassString returns the merged class string for parts, run through merge (the value form of gw.Class), so generated code can place a composed class into an Attrs map. merge receives the raw, un-split on-class strings.
func DefaultClassMerge ¶
DefaultClassMerge is the built-in class-merge strategy. It receives the raw, un-split class strings of each on source (static parts, toggles, and the caller's fallthrough class) in source order, and resolves cross-source conflicts by keeping the LAST occurrence of each token (caller/last-wins), preserving surviving tokens in source order, e.g. ["a b", "a"] -> "b a".
A single source is returned verbatim — there is nothing to merge across, so the author's (or caller's) class string is preserved exactly. This makes the common component-root case (one static class, no fallthrough) allocation-free. Generated code passes this as the merge function when no class_merger is configured.
func EscapeJSRegexp ¶
EscapeJSRegexp returns s escaped for a JavaScript regular-expression literal.
func EscapeJSStr ¶
EscapeJSStr returns s escaped for the interior of a JavaScript string literal.
func EscapeJSTmpl ¶
EscapeJSTmpl returns s escaped for the text portion of a JavaScript template literal.
func EscapeJSVal ¶
EscapeJSVal returns v escaped for a JavaScript value context.
func FilterCSS ¶
FilterCSS returns s when it is a safe CSS value, else a harmless inert placeholder. Generated code wraps each DYNAMIC composed-style declaration value in FilterCSS so untrusted data cannot inject declarations or break out of the style attribute. A trusted string-literal declaration is emitted without it.
func NonceFromContext ¶
NonceFromContext returns the nonce stored by WithNonce, or "" when absent.
func Style ¶
func Style(s string) conditionalPart
Style is an unconditional style contribution used by generated code.
func StyleString ¶
func StyleString(parts ...conditionalPart) string
StyleString returns the merged style declaration string for parts (the value form of gw.Style), so generated code can pass a composed root style to StyleMerged. Like gw.Style it includes only on-parts and joins with "; ", but does NOT attr-escape (the caller escapes).
A part's trailing ';' is trimmed so joining cannot produce a doubled separator; its internal ';' separators are left as the author wrote them.
func StyleValue ¶
StyleValue renders a composed-style part's value: a gsx.RawCSS value is the author's vouch and is emitted verbatim; any other value is CSS-value-filtered (cssValueFilter) so untrusted data cannot inject declarations or break out. Used by generated code for the dynamic parts of a composed style={ … }.
func URLPrefixMatch ¶
URLPrefixMatch reports whether key (Unicode-lowercased) begins with any of the prefixes, which must already be lowercase. See URLSuffixMatch for the end-anchored form; both route a matched bag key through the strict navigational URL sink.
func URLSuffixMatch ¶
URLSuffixMatch reports whether key (Unicode-lowercased) ends with any of the suffixes, which must already be lowercase. It serves the `*-url` naming convention, which a prefix rule cannot express.
func WithNonce ¶
WithNonce returns a context carrying the per-request CSP nonce. Generated code adds nonce="<value>" to every <script> and <style> open tag rendered with the returned context; an author-written nonce attribute (or a spread bag carrying a "nonce" key) wins and suppresses the automatic one. gsx does not generate nonce values and does not build the Content-Security-Policy header — both remain the server's job.
Types ¶
type Attr ¶
Attr is one ordered attribute pair. Value is rendered like any attribute value: a bool toggles a bare boolean attribute; anything else is stringified (toStr) and attribute-escaped.
type AttrMap ¶
AttrMap is a map-form attribute bag for ergonomic Go literals; convert it to Attrs explicitly with ToAttrs before passing/spreading in templates. A map has no order, so ToAttrs sorts keys ascending to keep output deterministic.
type AttrSinks ¶
type AttrSinks struct {
Image []string // → URLImageVal
Srcset []string // → SrcsetVal
Refresh []string // → RefreshContentVal
Prefixes []string // name prefixes → URLVal (strict)
Suffixes []string // name suffixes → URLVal (strict)
}
AttrSinks carries a project's OWN attribute-classification delta for a spread: the url_attrs rules from gsx.toml, plus any preset they enabled. The built-in floor and its tag scoping are not repeated here — Spread applies those itself from the table above — so a project that configures nothing passes the zero value and generated code stays free of the built-in name list.
Nav/Image/Srcset/Refresh are sets of lowercase attribute names naming the sink they leave through. Prefixes and Suffixes match a name's start or end instead, and always take the strict navigational sink (a project rule never earns the image-sink allowance).
The zero value adds nothing to the floor. A new sink is a new field: existing generated code, which writes only the fields it needs, keeps compiling and keeps rendering identically.
type Attrs ¶
type Attrs []Attr
Attrs is gsx's attribute bag: an insertion-ordered, duplicate-tolerant slice of pairs. It is the type of the implicit fallthrough bag, every declared bag prop, the {{ "k": v }} literal, and conditional-attr bags. Spread renders it in SLICE ORDER (no sort) so callers control attribute order (e.g. Datastar data-* directives); duplicate scalar keys are last-wins, matching JSX-style override order.
Security contract: keys are HTML attribute NAMES emitted (after a validity check, see Spread) without entity-encoding — they must come from generated code or trusted developer input, never from untrusted strings. Values are HTML-attribute- escaped.
URL sanitization happens at EVERY element spread `{ x... }` — top-level, derived (e.g. a.Without(...)), or nested inside a conditional-attr group — regardless of the bag's provenance (the implicit fallthrough bag, a byo component's declared Attrs field, a generated component's own named Attrs param, a local variable, a function call's result, or any other gsx.Attrs value). Generated code lowers every such spread to one Spread call that, in a single ordered walk, routes each URL-classified attribute name (built-in urlAttrs table + gsx.toml rules + gen.WithURLAttrs, resolved at generate time) through the same tag-aware sink a static attribute of that name would use (URLVal for navigational, URLImageVal for image resources) and writes everything else as a plain attribute-escaped value — see Spread for the full algorithm. A gsx.RawURL value is the author's per-value vouch and is passed through the sink verbatim; there is no other opt-out and no unsanitizing spread primitive — every spread goes through Spread. See composition.md §Precedence for the full forwarding-element rule.
func AttrsCond ¶
AttrsCond selects one of two attribute-bag thunks for a conditional component attribute: it calls and returns then() when cond is true, otherwise els(). The branches are THUNKS so the untaken branch is never evaluated — mirroring a real Go if/else, where the untaken block's expressions (e.g. u.Name when u == nil) never run. The thunks return (Attrs, error) so a branch body may hoist (T, error) values (e.g. a pipeline stage that can fail) and propagate the error; the generated call site unwraps it like any other (T, error) value. els may be nil (no else branch); an untaken or nil branch yields (nil, nil).
func ConcatAttrs ¶
ConcatAttrs concatenates bags in order into one new bag, preserving every pair (duplicates included). It does NOT dedupe or class-merge: rendering resolves duplicates at the leaf (Spread is last-wins on scalar keys and aggregates class/style), and Get/Has are last-wins by contract — so concatenation is observably equivalent to eager Merge for every consumer of the documented Attrs semantics. Generated call sites use it instead of .Merge() chains (one allocation instead of one per link). nil segments are skipped; a zero-entry result is nil.
func (Attrs) Class ¶
Class returns the bag's class string. DUPLICATE-KEY RULE: it AGGREGATES — the values of ALL "class" pairs are joined (space-separated, each trimmed), so no class is silently dropped. It does NOT merge/dedupe tokens; the single outer codegen-emitted class site applies the configured merger exactly once over this plus the root's parts.
func (Attrs) Get ¶
Get returns the value for key and whether it was present.
DUPLICATE-KEY RULE: LAST occurrence wins for scalar keys, matching JSX-style override order — EXCEPT "class" and "style", which COLLAPSE. A bag has one class and one style, so Get returns the aggregate (Class()/Style()), agreeing with what renders and with Merge. Last-wins there would report only the final contribution and read as though the earlier ones had been dropped, even though every one of them renders.
func (Attrs) GetFold ¶
GetFold is Get with Unicode simple-fold key matching through strings.EqualFold (last occurrence wins). key must already be lowercase. Exported for any caller — hand-written bag manipulation, tests — that needs to look up a bag key the same case-insensitive way a sanitizing sink does (a case-variant key like HREF must not smuggle an unsanitized value past it); Spread itself folds case via its own attrNameExcluded helper rather than calling GetFold.
func (Attrs) Has ¶
Has reports whether key is present. It scans directly rather than delegating to Get: Get collapses class/style by calling Class()/Style(), and routing Has through it would recurse.
func (Attrs) Merge ¶
Merge returns a new bag combining a and other, preserving order. For each pair in other: a "class"/"style" value is CONCATENATED onto the first such pair already in the result (or appended if none). Any other key OVERWRITES the last existing occurrence in place and drops earlier duplicates, so the incoming bag wins under the last-wins scalar rule; absent keys append.
Merge is for userland eager composition, where you want duplicates resolved immediately rather than at render time. Generated call sites use ConcatAttrs instead (one allocation, no eager scan) because Spread resolves duplicates at render time anyway; see ConcatAttrs for why the two are observably equivalent there.
func (Attrs) Style ¶
Style returns the bag's style declaration. DUPLICATE-KEY RULE: AGGREGATES — the values of ALL "style" pairs are joined ("; "-separated).
func (Attrs) Take ¶
Take returns Get(key)'s last value and a copy of a without ALL occurrences of key.
func (Attrs) Without ¶
Without returns a copy of a without ANY pair whose key is in keys (a is not mutated); the order of the rest is preserved. An empty result (or empty input) yields nil.
func (Attrs) WithoutFold ¶
WithoutFold is Without with Unicode simple-fold matching: it drops any pair whose key case-folds to one of keys (which must already be lowercase), preserving the order of the rest. No generated code calls it — a forwarding element's URL-classified keys render in place via Spread rather than being extracted and dropped from the bag first — but it remains public API for hand-written bag manipulation that needs the same fold semantics.
type Node ¶
Node is gsx's own rendering interface. Its method set is identical to templ.Component, so a gsx.Node satisfies templ.Component structurally — no templ import is needed for ecosystem interop.
func Fragment ¶
Fragment groups children into one Node with no wrapper element — the type-safe, variadic way to fill a single gsx.Node prop with multiple nodes (and the lowering target for a future <>…</> syntax). Renders each child in order; nil children are skipped; Fragment() renders nothing.
func Raw ¶
Raw wraps trusted, already-safe HTML — the opt-out from auto-escaping. The string is written verbatim.
func Text ¶
Text is the escaped-text Node — codegen's static-string fast-path and a Go-side text constructor (one alloc, no any-box).
func Val ¶
Val wraps any renderable value as a Node (so a value can fill a gsx.Node prop). A Node renders itself; string/[]byte/[]string/fmt.Stringer render as escaped text ([]string joined with spaces); the numeric and bool kinds render their plain Go form (use the |> pipeline for formatted numbers, e.g. { f | money("$") }); nil renders nothing.
Values are classified by their UNDERLYING type, so a named scalar (type Slug string, type Money float64) renders exactly as { x } does inline. See anyRenderVal, the single classifier this shares with every other runtime consumer.
Why a runtime box rather than classify-and-specialize at codegen (the type IS known at emit time): see docs/superpowers/specs/2026-06-23-gsx-node-prop-promotion-design.md §8.
type RawCSS ¶
type RawCSS string
RawCSS is a string the template author vouches for as safe CSS. In a CSS context — inside a <style> block or a style= attribute — a RawCSS value is emitted verbatim, bypassing the gw.CSS value-filter (the CSS analogue of trusting raw HTML via Raw). Use it only for CSS you control, never for untrusted data.
type RawJS ¶
type RawJS string
RawJS is a string the template author vouches for as safe JavaScript. In a JS value context — inside a <script> block or an event-handler attribute — a RawJS value passed to gw.JSVal is emitted verbatim, bypassing JSON marshaling and escaping (the JS analogue of trusting raw HTML via Raw, or template.JS in html/template). Use it only for JavaScript you control, never for untrusted data.
type RawURL ¶
type RawURL string
RawURL marks a URL the template author vouches for — the opt-out from gsx's URL scheme allow-list. A RawURL value in a URL attribute (href, src, …) skips the scheme check, so a non-http(s)/mailto/tel scheme is NOT replaced with the blocked-URL sentinel. It is still entity-escaped for the attribute context, so it cannot break out of the quotes — "raw" means "skip gsx's safety judgement about the scheme", not "write byte-for-byte". Use only for URLs you control or have already validated. It is also the sanctioned way to render a data: URL the image-sink validator rejects (a non-image MIME, or an encoding outside the base64/strict-percent forms) when you trust the bytes.
type Toggle ¶
type Toggle bool
Toggle forces boolean-attribute (presence) semantics on any attribute name, bypassing the name tables: Toggle(true) writes a bare ` name`, Toggle(false) writes nothing. Its remaining use is the names where the platform DOES define a value vocabulary but the author wants presence anyway — a plain bool on a name the platform never defined already toggles on its own.
It is a value, not syntax, so the same expression works on an element, as a component prop, and in a hand-written bag: gsx.Toggle(b) travels to the leaf where the presence decision is actually made.
gsx also uses Toggle internally when a syntactically bare attribute must travel through an Attrs bag, carrying its authored presence to the leaf independent of what the name tables say.
type Writer ¶
type Writer struct {
// contains filtered or unexported fields
}
Writer streams HTML to an underlying io.Writer. Ordinary write helpers retain the first error and no-op while it is set. Node applies a child result only when the parent state is clear. After a generated direct child uses this Writer, generated code uses NodeResult to apply the child's return, which may replace or clear state created during that child. Read current state via Err.
func (*Writer) AttrAny ¶
AttrAny is TextAny for attribute-value position (AttrValue escaping). See gsx.Val for the named-types-not-matched contract this mirrors.
func (*Writer) AttrAnyToggle ¶
AttrAnyToggle writes one complete attribute whose name renders a bool bare (codegen resolved htmlattr.RendersBare at generate time) but whose value type is known only at runtime — a mixed type parameter such as T string | bool. A bool-kinded value writes presence (` name` or nothing); any other value writes ` name="escaped"`. It owns the whole span — the leading space, the name, and the optional ="…" — which is what lets it omit a name codegen would otherwise have baked into a static string.
func (*Writer) CSS ¶
CSS writes s into a <style> raw-text context, value-filtered so it cannot break out of a CSS value. The filter rejects '<', so the result is raw-text safe and needs no HTML escaping.
func (*Writer) Class ¶
Class composes parts, runs them through merge, and writes the escaped class attribute value. merge receives the raw, un-split on-class strings.
func (*Writer) ClassMerged ¶
func (gw *Writer) ClassMerged(merge func(classes []string) string, extra string, parts ...conditionalPart)
ClassMerged writes a class attribute composed of parts plus the extra string (e.g. a fallthrough Attrs.Class()), running everything through merge. It writes nothing when there is no class to emit — so a root element with no class and no fallthrough class stays attribute-free. merge receives the raw, un-split on-class strings.
func (*Writer) FloatInto ¶
FloatInto writes f using strconv's 'g' shortest form (see IntInto). The output charset (digits, '.', '-', '+', 'e', and Inf/NaN letters) is always HTML-safe.
func (*Writer) IntInto ¶
IntInto writes n in base 10 into the caller-provided scratch buffer and writes the digit bytes directly to the output — no intermediate string allocation, and no HTML escaping (decimal digits and a leading '-' are always safe in text and attribute contexts). Generated code declares one buffer per render and reuses it across all numeric interpolations, so a numeric-heavy component allocates the scratch at most once (when it escapes) rather than once per number.
func (*Writer) JSRegexp ¶
JSRegexp writes s into a JS regular-expression literal so it is matched literally, as the stdlib's jsRegexpEscaper does. An empty input yields "(?:)" so that /<here>/ is not parsed as a line comment.
func (*Writer) JSRegexpAttr ¶
JSRegexpAttr writes s into a JS regexp literal inside an HTML attribute. It applies JS-regexp escaping first, then HTML-attribute escaping.
func (*Writer) JSStr ¶
JSStr writes s into the interior of a JS string literal (between quotes), or an HTML event-handler attribute, as the stdlib's jsStrEscaper does for a plain string.
func (*Writer) JSStrAttr ¶
JSStrAttr writes s into a JS string literal inside an HTML attribute. It applies JS-string escaping first, then HTML-attribute escaping.
func (*Writer) JSTmpl ¶
JSTmpl writes s into the text portion of a JS template literal (between backticks), as the stdlib's jsTmplLitEscaper does.
func (*Writer) JSTmplAttr ¶
JSTmplAttr writes s into a JS template literal inside an HTML attribute. It applies JS-template-literal escaping first, then HTML-attribute escaping.
func (*Writer) JSVal ¶
JSVal writes v into a JS value context (e.g. `var x = <here>`), as the stdlib's jsValEscaper does. A gsx.RawJS value is emitted verbatim; everything else is JSON-marshaled with the </script>, */, <!-- and U+2028/U+2029 defenses. On a marshal error the comment-safe failsafe string is emitted.
func (*Writer) JSValAttr ¶
JSValAttr writes v into a JS value context inside an HTML attribute (e.g. x-data="<here>"). It applies JS-value escaping first, then HTML-attribute escaping, so the result is safe in both JS and HTML attribute contexts. A gsx.RawJS value is emitted as raw JS but still HTML-attribute-escaped.
func (*Writer) Node ¶
Node renders a child node to the same writer; a nil node is a no-op. A render error is retained.
func (*Writer) NodeResult ¶
NodeResult records the return from a directly rendered generated child. Generated code calls it after the child's helper has used this Writer.
func (*Writer) Nonce ¶
Nonce writes ` nonce="<value>"` (attribute-escaped) when ctx carries a non-empty nonce (WithNonce), and nothing otherwise. Generated code calls it at the end of every <script>/<style> open tag that has no author-written nonce attribute.
func (*Writer) PIName ¶
PIName writes s as a processing instruction's name="…" value. Unlike every other sink there is no escaping to fall back on, so an unrepresentable value is a render error rather than a silently altered name — a stripped name would mistarget the update with no signal.
func (*Writer) RefreshContent ¶
RefreshContent writes a meta refresh content value with any embedded redirect URL sanitized, then HTML-escapes the complete attribute value.
func (*Writer) RefreshContentVal ¶
RefreshContentVal is RefreshContent for a value whose kind is not known until render time — a mixed type parameter, or a `content` key arriving through an element spread on a meta the caller identified as a refresh. A gsx.RawURL is the author's whole-value vouch and is emitted verbatim (still attribute- escaped), matching what codegen does when it can see the static type; any other value is stringified then refresh-sanitized.
func (*Writer) Spread ¶
func (gw *Writer) Spread(ctx context.Context, tag string, a Attrs, sinks AttrSinks, excluded []string)
Spread is gsx's sole spread primitive: the single-pass writer for EVERY element spread `{ x... }`, in one ordered walk it renders the plain attributes AND routes every URL-classified key through its sanitizing sink. There is no separate unsanitizing spread — a bag's provenance (forwarding field, local variable, function result, derived via Without, nested in a conditional-attr group, …) never changes this. It replaces the older unrolled per-name GetFold extraction + prefix-matched URL pass + residual spread write that only covered the forwarding bag. Generated code emits exactly one call per element spread, after the class/style merge site.
It walks a in slice order, honoring lastValidAttrIndexes (scalar last-wins) and validAttrName (structurally unsafe names dropped). excluded carries the names a FORCED root attr owns at this element (class/style — merged separately; static forced names — always; a post-spread conditional's names — only when its branch was taken, which is why codegen passes the runtime drop slice); such a key is SKIPPED so the owning site is the sole value.
Each surviving key is routed by AttrSinks.sinkFor(tag, key), matching case-insensitively (HTML attribute names fold, so a smuggled HREF/SRC cannot slip an unsanitized value past the sink). The built-in floor is applied from the table in urlattrs.go and is NOT caller-supplied: it is the safety default, so it holds even for a hand-written caller passing the zero AttrSinks, and no project rule can downgrade it. sinks carries only that project's own url_attrs delta. A key with no sink gets the plain attribute write (a non-excluded class/style key aggregates via a.Class()/a.Style(); bool → BoolAttr; else key="value", attribute-escaped).
tag is the element the bag is being written onto — needed because a sink can be tag-scoped (`content` is a refresh directive on <meta> and an ordinary attribute everywhere else) and because `src` splits between the image and strict sinks by element. An empty tag applies only the element-independent floor.
The names in sinks must already be lowercase. A RawURL value is the author's vouch and is emitted verbatim (still attribute-escaped) by the URL sinks. URL keys render IN their bag position — not hoisted ahead of the residual as the old unrolled extraction did — so the bag's authored attribute order is preserved. ctx is reserved for forward-compatibility.
func (*Writer) Srcset ¶
Srcset writes s as a sanitized, escaped srcset attribute value: a comma-separated image-candidate list, each candidate URL sanitized as an image resource. Codegen emits it for srcset/imagesrcset attributes.
func (*Writer) SrcsetVal ¶
SrcsetVal is Srcset for a dynamically-typed bag value: a gsx.RawURL is the author's whole-value vouch and is emitted verbatim (still attribute-escaped); any other value is stringified then sanitized.
func (*Writer) Style ¶
func (gw *Writer) Style(parts ...conditionalPart)
Style composes the on parts as '; '-joined declarations (no merge) and writes the escaped style attribute value. A part's trailing ';' is trimmed (see StyleString), so it never yields a doubled separator.
func (*Writer) StyleMerged ¶
StyleMerged emits a merged ` style="…"` attribute combining rootStyle then bagStyle (caller last), deduping by property keeping the LAST occurrence, survivors in source order. A malformed fragment (no ':') is dropped. When the merged result is empty it emits nothing (matching the empty-bag no-op).
func (*Writer) TextAny ¶
TextAny writes v as escaped text, dispatching on its dynamic type. Codegen emits it for interpolations whose type is a type parameter with a MIXED non-tilde constraint whose terms are all runtime-dispatchable (e.g. T string | int) — classify proves every term has a matching case in anyRenderString at generate time, so the dispatch is total for generated code. See gsx.Val for the named-types-not-matched contract this mirrors.
func (*Writer) URLImage ¶
URLImage writes s as an image-resource-sanitized, escaped URL attribute value. It permits data:image/* (raster + svg) in addition to the standard URL() allow-list; codegen emits it only for image-rendering sinks (<img src>, <source src>, <video poster>, background), never for navigational or script sinks.
func (*Writer) URLImageVal ¶
URLImageVal is URLVal for image-resource sinks (data:image/* permitted).
func (*Writer) URLVal ¶
URLVal writes v as a navigational-URL attribute value: a gsx.RawURL is the author's vouch and is emitted verbatim (still attribute-escaped); any other value is stringified and scheme-sanitized like URL. Generated code uses it for URL-classified bag attributes, where the value is dynamic (any).
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package ast defines the gsx syntax tree produced by the parser.
|
Package ast defines the gsx syntax tree produced by the parser. |
|
cmd
|
|
|
gsx
command
Command gsx is the stock gsx CLI: it generates .x.go from .gsx files using the hardcoded standard codegen.
|
Command gsx is the stock gsx CLI: it generates .x.go from .gsx files using the hardcoded standard codegen. |
|
gsx-examples
command
Command gsx-examples regenerates the docs Examples page and the playground preset lists from the single-source examples/*.txtar fixtures.
|
Command gsx-examples regenerates the docs Examples page and the playground preset lists from the single-source examples/*.txtar fixtures. |
|
gsx-typebundle
command
Command gsx-typebundle produces a self-describing type archive for the browser playground.
|
Command gsx-typebundle produces a self-describing type archive for the browser playground. |
|
Package gen is the gsx generation engine: it discovers .gsx files under a set of paths, runs the codegen for each Go package directory, and writes the resulting .x.go files to disk next to their .gsx sources.
|
Package gen is the gsx generation engine: it discovers .gsx files under a set of paths, runs the codegen for each Go package directory, and writes the resulting .x.go files to disk next to their .gsx sources. |
|
internal
|
|
|
attrclass
Package attrclass classifies HTML attribute names into security/escaping contexts (JS, URL, CSS, plain).
|
Package attrclass classifies HTML attribute names into security/escaping contexts (JS, URL, CSS, plain). |
|
codegen
Package codegen lowers a parsed gsx AST to Go source (.x.go) targeting the gsx runtime.
|
Package codegen lowers a parsed gsx AST to Go source (.x.go) targeting the gsx runtime. |
|
codegen/mkstdlibindex
command
Command mkstdlibindex writes internal/codegen/stdlibindex_gen.go: a package-name -> import-path table for the Go standard library.
|
Command mkstdlibindex writes internal/codegen/stdlibindex_gen.go: a package-name -> import-path table for the Go standard library. |
|
codegen/stdpath
Package stdpath decides whether an import path is importable from ordinary user code, applying Go's own `internal`/`vendor` path rules rather than an approximation of them.
|
Package stdpath decides whether an import path is importable from ordinary user code, applying Go's own `internal`/`vendor` path rules rather than an approximation of them. |
|
cssfmt
Package cssfmt re-indents the CSS inside <style> bodies during gsx fmt.
|
Package cssfmt re-indents the CSS inside <style> bodies during gsx fmt. |
|
cssmin
Package cssmin is gsx's codegen-time CSS minifier: a robust, stable, safe pass over the static CSS of <style> blocks.
|
Package cssmin is gsx's codegen-time CSS minifier: a robust, stable, safe pass over the static CSS of <style> blocks. |
|
diag
Package diag is gsx's structured-diagnostic foundation: a fileset-agnostic Diagnostic model (resolved token.Position ranges, severity, code, help, source), a Bag collector for error recovery, and renderers (see render.go).
|
Package diag is gsx's structured-diagnostic foundation: a fileset-agnostic Diagnostic model (resolved token.Position ranges, severity, code, help, source), a Bag collector for error recovery, and renderers (see render.go). |
|
examplegen
Package examplegen turns the single-source examples/*.txtar fixtures into the docs Examples page and the playground preset lists.
|
Package examplegen turns the single-source examples/*.txtar fixtures into the docs Examples page and the playground preset lists. |
|
fullmin
Package fullmin is gsx's aggressive ("full") minifier: a thin wrapper over github.com/tdewolff/minify/v2 for the minify level "full".
|
Package fullmin is gsx's aggressive ("full") minifier: a thin wrapper over github.com/tdewolff/minify/v2 for the minify level "full". |
|
goexprshape
Package goexprshape classifies where a gsx value sits within the Go expression it was substituted into, at a GoWithElements decl's embedding point (e.g.
|
Package goexprshape classifies where a gsx value sits within the Go expression it was substituted into, at a GoWithElements decl's embedding point (e.g. |
|
golauncher
Package golauncher captures and validates the Go launcher used across a semantic operation.
|
Package golauncher captures and validates the Go launcher used across a semantic operation. |
|
gsxfmt
Package gsxfmt is the single source-formatting engine shared by the `gsx fmt` CLI and the language server's textDocument/formatting: parse → whitespace- normalize → print, producing the canonical, idempotent form of a .gsx file.
|
Package gsxfmt is the single source-formatting engine shared by the `gsx fmt` CLI and the language server's textDocument/formatting: parse → whitespace- normalize → print, producing the canonical, idempotent form of a .gsx file. |
|
htmlattr
Package htmlattr holds the HTML attribute-name tables that BOTH the runtime and the generator must agree on: which names render a bool as presence, which are presence-only, and which carry a URL on which element.
|
Package htmlattr holds the HTML attribute-name tables that BOTH the runtime and the generator must agree on: which names render a bool as presence, which are presence-only, and which carry a URL on which element. |
|
htmldata
Package htmldata is the HTML tag/attribute/value completion dataset, generated from the vendored @vscode/web-custom-data browsers.html-data.json (MIT, LICENSE.vendored).
|
Package htmldata is the HTML tag/attribute/value completion dataset, generated from the vendored @vscode/web-custom-data browsers.html-data.json (MIT, LICENSE.vendored). |
|
htmldata/gen
command
Command gen regenerates table.gen.go from browsers.html-data.json (@vscode/web-custom-data, MIT — see LICENSE.vendored) and htmx-data.json (transcribed from https://htmx.org/reference/, same custom-data schema).
|
Command gen regenerates table.gen.go from browsers.html-data.json (@vscode/web-custom-data, MIT — see LICENSE.vendored) and htmx-data.json (transcribed from https://htmx.org/reference/, same custom-data schema). |
|
jsfmt
Package jsfmt re-indents the JavaScript inside executable <script> bodies during gsx fmt.
|
Package jsfmt re-indents the JavaScript inside executable <script> bodies during gsx fmt. |
|
jsmin
Package jsmin is gsx's codegen-time safe JS minifier: a tdewolff-lexer-driven pass over the static JS of <script> blocks.
|
Package jsmin is gsx's codegen-time safe JS minifier: a tdewolff-lexer-driven pass over the static JS of <script> blocks. |
|
jsx
Package jsx is gsx's codegen-time JavaScript context engine for <script> interpolation (Slice C1).
|
Package jsx is gsx's codegen-time JavaScript context engine for <script> interpolation (Slice C1). |
|
lsp
Package lsp implements gsx's language server: a stdio JSON-RPC transport, a minimal hand-written subset of the LSP protocol, an in-memory document store, and a server loop that publishes gsx diagnostics.
|
Package lsp implements gsx's language server: a stdio JSON-RPC transport, a minimal hand-written subset of the LSP protocol, an in-memory document store, and a server loop that publishes gsx diagnostics. |
|
modpath
Package modpath maps canonical Go import paths to module-local directories.
|
Package modpath maps canonical Go import paths to module-local directories. |
|
pretty
Package pretty is a language-agnostic Wadler/Prettier-style pretty-printing document model.
|
Package pretty is a language-agnostic Wadler/Prettier-style pretty-printing document model. |
|
printer
Package printer renders a (normalized) gsx AST back to canonical gsx source.
|
Package printer renders a (normalized) gsx AST back to canonical gsx source. |
|
rawfmt
Package rawfmt is the language-agnostic embedding layer that formats the body of a raw-text element (today <style>) during gsx fmt.
|
Package rawfmt is the language-agnostic embedding layer that formats the body of a raw-text element (today <style>) during gsx fmt. |
|
reindent
Package reindent is the language-agnostic core of gsx's embedded-language formatters.
|
Package reindent is the language-agnostic core of gsx's embedded-language formatters. |
|
sourceintel
Package sourceintel maps generated Go byte ranges to authored GSX byte ranges.
|
Package sourceintel maps generated Go byte ranges to authored GSX byte ranges. |
|
sourceview
Package sourceview builds the one logical source manifest shared by normal code generation and persistent-cache metadata queries.
|
Package sourceview builds the one logical source manifest shared by normal code generation and persistent-cache metadata queries. |
|
tagcallable
Package tagcallable classifies whether a Go value — a func, or a function-typed var — has the shape a gsx tag can call: a signature with exactly one result assignable to gsx.Node.
|
Package tagcallable classifies whether a Go value — a func, or a function-typed var — has the shape a gsx tag can call: a signature with exactly one result assignable to gsx.Node. |
|
txtar
Package txtar implements a minimal read/write of the txtar archive format.
|
Package txtar implements a minimal read/write of the txtar archive format. |
|
typebundle
Package typebundle serializes a transitively-closed set of go/types packages together with the exact build context that selected them.
|
Package typebundle serializes a transitively-closed set of go/types packages together with the exact build context that selected them. |
|
wsnorm
Package wsnorm implements the gsx JSX-style whitespace normalization pass.
|
Package wsnorm implements the gsx JSX-style whitespace normalization pass. |
|
parser/boundary.go
|
parser/boundary.go |
|
playground
|
|
|
playbundle
Package playbundle embeds the playground type bundle — the transitive go/types closure of the gsx runtime, the std filter package, and the playground stdlib allowlist — and builds a rootless resolver from it with no packages.Load and no subprocess.
|
Package playbundle embeds the playground type bundle — the transitive go/types closure of the gsx runtime, the std filter package, and the playground stdlib allowlist — and builds a rootless resolver from it with no packages.Load and no subprocess. |
|
wasm
command
Command gsx-wasm is the client-side playground engine.
|
Command gsx-wasm is the client-side playground engine. |
|
Package std provides the gsx public filter standard library.
|
Package std provides the gsx public filter standard library. |