Skip to content

feat(html): HTML accessibility-tree backend - #43

Merged
bdelanghe merged 1 commit into
mainfrom
feat/html-accessibility-backend
Jun 29, 2026
Merged

feat(html): HTML accessibility-tree backend#43
bdelanghe merged 1 commit into
mainfrom
feat/html-accessibility-backend

Conversation

@bdelanghe

Copy link
Copy Markdown
Collaborator

Summary

  • Adds src/html.rs — a new language backend that projects HTML DOM into an accessibility tree (Vec<Def>) for semantic identity tracking
  • Wires HTML into the existing dispatch: clean/smudge filter, git-ast inspect, git-ast match, and git-ast setup (registers *.html/*.htm gitattributes)
  • Downgraded dep from tree-sitter-html = "0.23" to "0.20" to match the API style of tree-sitter-rust = "0.21" (both use a language() fn rather than the 0.23 LANGUAGE const)

How it works:

  • canonicalize() — normalises attribute ordering (alphabetical), double-quotes all values, lowercases tag names; output is valid HTML (not JSON) so working trees stay readable
  • inspect() — returns a Def for each semantically meaningful element (landmarks, headings, interactive, img). Non-semantic divs/spans are skipped
  • content_hash — FNV-1a over role\0name\0tag\0sorted-k=v (role + accessible name + structure)
  • shape_hash — same preimage with accessible name AND its source attrs (aria-label, title, alt) replaced by _, so two navs that differ only in label share a shape hash and fuzzy-match correctly
  • subtree_hashes — one hash per semantic unit, feeding directly into the existing identity::match_defs Dice-similarity matching

Key implementation note: tree-sitter-html 0.20 represents void elements (<img />) as element → self_closing_tag (not self_closing_element), so element_to_def handles both start_tag and self_closing_tag children defensively.

Test plan

  • 20 new unit tests in html::tests covering: canonicalization, attribute sorting, idempotency, DOCTYPE normalization, accessible name resolution (aria-label / alt / text / title priority), role mapping, implicit/explicit roles, inspect element discovery, content_hash stability, shape_hash rename detection, subtree_hashes presence
  • All 97 tests pass (cargo test --lib)
  • Full test suite including cucumber acceptance tests passes (cargo test)
  • cargo build compiles clean (zero warnings)

PR checklist

  1. Independent PR — HTML backend only; no changes to existing Rust/JSON paths
  2. Changed codepaths verified — 20 HTML-specific unit tests + 5 cucumber integration tests pass
  3. Root cause identified — N/A (new feature)
  4. No duplication — FNV-1a copied from printer.rs (private there); a follow-up can extract it if the pattern repeats again
  5. No unrelated changes — only Cargo.toml/lock (new dep), 6 wiring files, and the new src/html.rs

🤖 Generated with Claude Code

Teaches git-ast to treat HTML files semantically. The DOM is projected
as an accessibility tree (landmarks, headings, interactive elements) so
`git-ast inspect`, `match`, and `blame` track DOM identity across
commits the same way they track Rust function identity.

Key design decisions:
- `canonicalize()` normalises attribute ordering + quoting and
  lowercases tag names but keeps the output as valid HTML (not JSON),
  so working trees stay readable and round-trip losslessly.
- `inspect()` returns `Vec<Def>` for semantically meaningful elements
  only (landmarks, headings, img, button, input, …). Presentational
  divs/spans with no role are ignored.
- `content_hash`: FNV-1a over `role\0name\0tag\0sorted-attrs`.
- `shape_hash`: same preimage with the accessible name AND its
  contributing attrs (aria-label, title, alt) replaced by `_` so a
  relabelled nav shares its shape with the original.
- `subtree_hashes`: one hash per semantic unit, enabling the existing
  Dice-similarity fuzzy matching from `identity::match_defs`.
- Extension dispatch wired into filters (clean/smudge), `inspect`, and
  `match`; `setup` registers *.html / *.htm gitattributes entries.
- Depends on tree-sitter-html 0.20 (matching tree-sitter-rust 0.21's
  API style); in 0.20, void elements are `element → self_closing_tag`
  (not `self_closing_element`), handled defensively in `element_to_def`.

97/97 tests green (20 new HTML tests).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@bdelanghe
bdelanghe merged commit 1a4cf33 into main Jun 29, 2026
4 of 5 checks passed
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.

1 participant