Skip to content

htmx preset covers htmx 4; url presets become runtime predicates - #201

Merged
jackielii merged 1 commit into
mainfrom
htmx4-attrs
Sep 14, 2026
Merged

jackielii merged 1 commit into
mainfrom
htmx4-attrs

Conversation

@jackielii

Copy link
Copy Markdown
Contributor

Closes #199.

What

htmx URL preset covers htmx 4. hx-query and hx-action join the five method attributes, and every name is sanitized in the four spellings htmx 4's attribute lookup reads: plain, :inherited, :append, :inherited:append. Verified against the htmx 4.0.0 source (#attributeValue / #determineMethodAndAction): an ancestor's hx-action:inherited wins over a child's hx-get, and hx-get:append with no inheriting ancestor is the fetch URL verbatim, so all four are sinks. hx-method names the verb and stays plain. One preset serves htmx 2 and 4; an htmx 2 page never uses the htmx 4 names. htmx's config.prefix / metaCharacter renames are not chased; the docs say to list renamed attributes under [url_attrs].

URL presets are predicates, identified by name. Expanding the preset into the user URL name list put 28 names into every spread site, allocated per render, and churned goldens on every preset edit. A preset is now a predicate compiled into internal/htmlattr (HTMXURL), applied by both static classification and the runtime spread leaf so they cannot drift. Only the name travels: as a string into the classifier fingerprint (attrclass.Rules.Presets) and as a compile-time flag into generated code (gsx.AttrSinks.Presets, gsx.PresetHTMX):

_gsxgw.Spread(ctx, "button", _gsxv0, _gsxrt.AttrSinks{Presets: _gsxrt.PresetHTMX}, []string{"class", "style"})

User [url_attrs] rules stay declarative data; there is still no user-facing predicate (4af45c4 removed one because a closure can neither reach the leaf nor hash into the cache key).

Completion data is the union of the htmx 2 and htmx 4 attribute tables: ten htmx 4 attributes added, the nine htmx 4 removed keep their entry with a "htmx 2 only" lead naming the replacement, and hx-disable documents both meanings.

Compatibility

Runtime API is additive; previously generated .x.go files with the five-name Nav list compile and render identically. Config and gen.WithURLPreset are unchanged. Generated output changes only at spread sites in projects with the preset on. The only behavioural change is the intended one: more htmx URL attributes are sanitized. Patch-level under the release policy.

Tests

  • htmlattr.HTMXURL exhaustive pin (all spellings, wrong-order suffixes rejected, case folding)
  • classifier: preset identity, Presets() accessor, Rules.Merge dedupe, Valid rejects unknown names, fingerprint sees presets
  • runtime: AttrSinks{Presets: PresetHTMX}.sinkFor routes every spelling to the nav sink, zero value routes nothing
  • codegen: every preset in attrclass.PresetNames() has a runtime flag
  • corpus urlattrs/htmx_preset_v4: sanitization pinned statically and through a bag spread (the bag path can only pass via the runtime flag); bag_hx_get pins the emitted flag
  • htmldata: table count, htmx 4 presence with four.htmx.org links, version notes on removed attributes

make ci exit 0 on the committed branch (the playbundle drift check diffs against HEAD, so the regenerated typebundle is in the commit).

Follow-ups (not in this PR)

  • The separate URLPresets plumbing through codegen results for the LSP is now derivable from Classifier.Presets().
  • Completing :inherited / :append suffix forms in the editor needs a suffix grammar in the completer, not a name list.

https://claude.ai/code/session_01Mnm5vogYqtxqUQyEvUeYbN

The "htmx" url preset now sanitizes every htmx request-URL attribute of
htmx 2 and htmx 4: hx-query and hx-action join the five method
attributes, each in the four spellings htmx 4's attribute lookup reads
(plain, :inherited, :append, :inherited:append). An ancestor's
hx-action:inherited wins over a child's hx-get, and hx-get:append with
no inheriting ancestor is the fetch URL verbatim, so all of them are
sinks. hx-method names the verb and stays plain. One preset serves both
majors: an htmx 2 page never uses the htmx 4 names.

A preset is no longer expanded into the user URL name list. That list
travels into every spread site as data, and at 28 names it bloated
generated code, allocated per render, and churned goldens on every
preset edit. A preset is now a predicate compiled into htmlattr
(HTMXURL) and applied by both static classification and the runtime
spread leaf, so the two cannot drift; only its NAME travels — as a
string into the classifier fingerprint (Rules.Presets) and as a
compile-time flag to the leaf (gsx.AttrSinks.Presets, gsx.PresetHTMX).
Generated spread sites carry `Presets: _gsxrt.PresetHTMX` instead of a
name list. User [url_attrs] rules stay declarative data; there is still
no user predicate, for the reasons 4af45c4 removed one.

Completion data is the union of the htmx 2 and htmx 4 attribute tables:
ten htmx 4 attributes added, the nine htmx 4 removed say so in their
hover text with the replacement, and hx-disable documents both meanings.

Claude-Session: https://claude.ai/code/session_01Mnm5vogYqtxqUQyEvUeYbN
@jackielii
jackielii merged commit 7b465aa into main Sep 14, 2026
5 checks passed
@jackielii jackielii mentioned this pull request Sep 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

htmx attribute data and url_presets = ["htmx"] predate htmx 4

1 participant