Repository navigation
Fix attribute bugs found with htmx, and name classes by their styles - #2
Merged
Merged
Conversation
- An attribute given twice (by a bundle and after it, by a function and
its call) is written once, with the later value. The browser keeps the
first of two, so the bundle's used to win.
- `hx-` names are HTML attributes, like `aria-` and `data-` ones:
`hx-get /items` is an error that shows `hx-get=/items`, and a bare
`hx-` or `data-` word is a flag (`hx-preserve`, `data-open`).
- Right after a `key=value`, a name htmlang doesn't know is reported as
the rest of that value, which a comma ended (`split-value`), with the
value written with `\,`.
- A `]` that ends a list inside a `'...'` in a value (`alert(']')`) is
reported (`unbalanced-quote`).
- A leading argument that reads as text (`@link [hx-get=/x] Open panel`)
is taken as the URL with a warning (`text-as-url`).
- `htmlang serve` answers GET and HEAD, gives 405 to other methods, and
adds its reload script only to pages, not to fragments.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hca8AvqJAmkTymf66PBCGk
A class was named by its place in the file (`hl-a`, `hl-b`, ...), so a fragment's `hl-a` and a page's `hl-a` were two different styles, and a fragment swapped into a page (htmx, or any server-rendered partial) restyled the page's elements and lost its own layout. - A class is `hl-` + 7 base-36 digits of a stable hash of its style (FNV-1a with SplitMix64's finalizer), so one style has one name in every file. Within a file, a style whose name is taken takes more digits. - A function's scoped `@style` is `hl-fn-NAME-HASH`, the hash of the stylesheet, so two functions of one name in two files don't meet. - `htmlang build` reports two files whose different styles got one name (`class-collision`). - The integration tests read the output with its classes numbered in the order they appear (tests/common), so the snapshots are unchanged and change only when styles do. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hca8AvqJAmkTymf66PBCGk
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Before: htmx attributes compiled, but several mistakes passed silently or with only a vague warning.
@el [$live, hx-trigger=click]wrotehx-triggertwice, so the browser kept the bundle's.hx-trigger=load, every 2sturnedevery 2sinto CSS.hx-get /itemsbecame CSS.@link [hx-get=/panel] Open panelgothref="Open". A barehx-preservewas an error. A]inalert(']')ended the list. Classes were numbered per file (hl-a,hl-b, ...), so a fragment swapped into a page restyled the page's elements.htmlang serveanswered a POST with the GET body and added its reload script to fragments.After: the later attribute wins and is written once.
hx-names are HTML attributes likearia-anddata-ones, and a barehx-/data-word is a flag. A comma that cuts a value short is reported with the value written with\,(split-value). A]inside'...'is reported (unbalanced-quote). Link text taken as the URL gets a warning (text-as-url). A class is named by a hash of its style (hl-2k9xq0m), so one style has one name in every file, andhtmlang buildreports two files whose different styles got one name (class-collision). The dev server answers GET and HEAD, gives 405 to other methods, and leaves fragments alone.This adds no new syntax. It is the "fix either way" part of the htmx investigation, and it helps anyone who swaps htmlang output into a page by any means.
How:
vocab::is_html_attributeandvocab::is_html_flagreplace the scatteredaria-/data-checks. Codegen writes each HTML attribute name once, keeping the last. The attribute check now knows which attribute came before, so it can report a split value.AttrList::quoted_closemarks the bracket case.StyleCollectornames a class withstable_hash(FNV-1a plus SplitMix64's finalizer) of the style's text. It takes more digits when a name is already taken in the file, andgenerate_with_classeshands the names tobuild. The integration tests read the output with classes numbered in order of appearance (tests/common), so the 118 snapshots are unchanged. Checked in Chromium: a fragment swapped into a page restyled 3 page elements before and 0 after, and it now looks the same as it does on its own.🤖 Generated with Claude Code
https://claude.ai/code/session_01Hca8AvqJAmkTymf66PBCGk
Generated by Claude Code