Skip to content

Document heading ID CSS-validity deviation from djot spec (jgm/djot#391)#179

Merged
dereuromark merged 3 commits into
masterfrom
feature/heading-id-css-deviation-docs
May 13, 2026
Merged

Document heading ID CSS-validity deviation from djot spec (jgm/djot#391)#179
dereuromark merged 3 commits into
masterfrom
feature/heading-id-css-deviation-docs

Conversation

@dereuromark
Copy link
Copy Markdown
Contributor

Summary

  • Cross-references jgm/djot#391 (where the djot spec's auto-ID wording is being clarified) from the existing CSS-Safe Heading IDs enhancements page.
  • Adds a Spec Alignment subsection with a side-by-side table of djot.js / djoths (the direction the spec is moving) vs. djot-php, and a short paragraph explaining the deliberate CSS-validity deviation on ', ", ;, :.
  • Pins the relevant edge cases — mid-word punctuation, apostrophe handling, consecutive punctuation collapse, ASCII + non-ASCII letter preservation, leading-digit prefix, empty-result fallback — with a focused regression test testNormalizeIdSpecAlignmentEdgeCases() so the behavior is locked in if/when the spec lands.

Rationale

The current djot spec says auto-IDs are formed by "removing punctuation (other than _ and -)". In practice djot.js (the reference), djoths (pandoc's engine), and most community implementations — including djot-php — replace mid-word punctuation with -. The cross-implementation comparison on jgm/djot#391 shows the spec is moving toward "replace".

djot-php goes one step further: ', ", ;, : are also replaced with -. These characters are not valid in unescaped CSS identifiers, so preserving them per the proposed spec would force every JS consumer to round-trip through CSS.escape() before doing a querySelector('#...') lookup. In practice almost nobody does this, and it silently breaks anchors and HTMX scroll-restoration on headings like # That's all.

This PR makes that choice explicit and defensible rather than implicit divergence. No behavior change — only docs + tests.

What changes

Cross-reference jgm/djot#391, where the spec wording on auto-ID
generation is being clarified. djot-php aligns with the proposed
direction on remove-vs-replace and Unicode preservation, but
deliberately deviates on apostrophes, double quotes, semicolons,
and colons (replacing rather than preserving) because heading IDs
are consumed by querySelector() and need to be valid CSS identifiers.

Add a Spec Alignment section to the existing CSS-Safe Heading IDs
reference, and pin the relevant edge cases with a focused regression
test so the deliberate behavior is locked in if/when the spec lands.
@dereuromark dereuromark added the documentation Improvements or additions to documentation label May 13, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.51%. Comparing base (615c640) to head (43f9e69).

Additional details and impacted files
@@            Coverage Diff            @@
##             master     #179   +/-   ##
=========================================
  Coverage     93.51%   93.51%           
  Complexity     3242     3242           
=========================================
  Files            93       93           
  Lines          8207     8207           
=========================================
  Hits           7675     7675           
  Misses          532      532           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

PhpCollective enables both PSR12.Classes.AnonClassDeclaration.SpaceAfterKeyword
(wants 1 space between 'class' and '(') and Universal.WhiteSpace.AnonClassKeywordSpacing
(wants no space). The two rules contradict each other, so any anonymous class
declaration fails CS regardless of how it is written. Exclude the PSR12 rule so
the Universal sniff wins, unblocking CI on this PR.
PhpCollective code-sniffer now configures Universal.WhiteSpace.AnonClassKeywordSpacing
with spacing=1, matching the existing PSR12.Classes.AnonClassDeclaration.SpaceAfterKeyword
rule. The two rules agree on '1 space between class and (' so the prior exclude is no
longer needed; revert it and apply the actual one-character source fix.
@dereuromark dereuromark merged commit a690b48 into master May 13, 2026
6 checks passed
@dereuromark dereuromark deleted the feature/heading-id-css-deviation-docs branch May 13, 2026 22:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant