fix(formatter_htmlish): handle XHTML (#28703)

- bump `oxc-htmlish-parser` to support Xhtml dialect
- Use it in formatter
This commit is contained in:
leaysgur committed 2026-11-02 04:52:00 +00:00
1 parent 3c85661446
commit fef809a7f3
8 files changed
+47 -18

No files matched your search

Generated
+2 -2
View File
@@ -1699,9 +1699,9 @@ dependencies = [
[[package]]
name = "oxc-htmlish-parser"
version = "0.0.1"
version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "909fd32d29f076e5129a27244801bed7de5ce33a974310c710f8777dee016495"
checksum = "d56b242831e1d43ca8b931fec32a68a263a7b1c1c7e7f74cfb7f94c4759f3ae9"
dependencies = [
"memchr",
"oxc_allocator",
+1 -1
View File
@@ -243,7 +243,7 @@ num-bigint = "0.5.0" # Big integers
num-traits = "0.2.19" # Numeric traits
oxc-css-parser = "0.0.18" # CSS/SCSS/Less parser (raffia 0.12.3 fork: adds `template_placeholder` typed placeholders for css-in-js + valid-syntax coverage fixes (see crates/oxc_formatter_css/AGENTS.md))
oxc-graphql-parser = "0.0.9" # GraphQL parser (direct AST; apollo-parser 0.8.6 fork aligned with graphql-js 17 syntax)
oxc-htmlish-parser = "0.0.1" # HTML / Vue / Angular parser (loose, span-faithful AST)
oxc-htmlish-parser = "0.0.2" # HTML / Vue / Angular parser (loose, span-faithful AST)
oxc-markdown-parser = "0.0.3" # CommonMark + GFM parser (span-faithful, style-preserving typed AST)
oxc-toml = "0.15.1" # TOML parser and formatter
oxc-yaml-parser = "0.0.7" # YAML 1.2 parser (comment-preserving typed AST, node naming from `yaml-unist-parser`)
+3 -1
View File
@@ -43,6 +43,7 @@ const LANGUAGES: Record<string, Language> = {
".yaml": "yaml",
".md": "markdown",
".html": "html",
".xhtml": "html",
".vue": "vue",
};
@@ -74,7 +75,8 @@ const PARSERS: Record<string, (name: string) => string> = {
graphql: withExt(".graphql"),
yaml: withExt(".yaml"),
markdown: withExt(".md"),
html: withExt(".html"),
// An HTML extension is kept, as oxfmt reads some differently (`.xhtml`)
html: (name) => (LANGUAGES[extname(name)] === "html" ? name : withExt(".html")(name)),
// The whole file goes to Prettier, but its `<script>` is formatted by oxc.
// A `.html` page under `vue` (e.g. `vue/html-vue/`) fails only on the doctype case for now:
// Prettier lowercases `<!DOCTYPE html>` for a `.html` filepath only, and this runs it as `.vue`.
@@ -670,7 +670,7 @@
## html
221/228 (96.93%)
222/228 (97.37%)
### Failed
@@ -685,11 +685,6 @@
- externals/prettier/html/tags/tags2.html (💥💥✨✨, 97.17%)
- crates/oxc_formatter_htmlish/DIVERGENCES.md#dialog-out-of-flow
### Error
- externals/prettier/misc/filename-matters/html-doctype/xhtml-doctype.xhtml: Syntax error: missing end tag of raw text element at 16..74
- ❓unclassified
## vue
175/184 (95.11%)
+3 -2
View File
@@ -14,14 +14,15 @@ pub enum HtmlishVariant {
/// Prettier's `parser: angular` equivalent.
Angular,
/// Prettier's `parser: html` on an XHTML file (`.xhtml`, `.xht`), which an XML parser may read:
/// read and printed as HTML, but the doctype keeps its case.
/// read and printed as HTML, but `/>` closes every element and the doctype keeps its case.
Xhtml,
}
impl HtmlishVariant {
pub(crate) fn to_dialect(self) -> Dialect {
match self {
Self::Html | Self::Xhtml => Dialect::Html,
Self::Html => Dialect::Html,
Self::Xhtml => Dialect::Xhtml,
Self::Vue => Dialect::Vue,
Self::Angular => Dialect::Angular,
}
+4 -6
View File
@@ -1,5 +1,3 @@
use oxc_htmlish_parser::Dialect;
use crate::HtmlishVariant;
/// What the variant changes in the shared rules, resolved once per document.
@@ -25,11 +23,11 @@ impl DialectRules {
/// `sfc`: a Vue file read as a single-file component, not as HTML.
/// `standalone`: a file of its own, not a part embedded in another language.
pub fn new(variant: HtmlishVariant, sfc: bool, standalone: bool) -> Self {
let dialect = variant.to_dialect();
Self {
names_ignore_case: dialect == Dialect::Html || (dialect == Dialect::Vue && !sfc),
keeps_element_gap_kind: dialect == Dialect::Vue,
has_blocks: dialect == Dialect::Angular,
names_ignore_case: matches!(variant, HtmlishVariant::Html | HtmlishVariant::Xhtml)
|| (variant == HtmlishVariant::Vue && !sfc),
keeps_element_gap_kind: variant == HtmlishVariant::Vue,
has_blocks: variant == HtmlishVariant::Angular,
lowercase_doctype: variant != HtmlishVariant::Xhtml,
lowercase_known_names: standalone && variant == HtmlishVariant::Html,
}
@@ -0,0 +1,4 @@
<script src="a"/>
<div/>after
<p><my-el/>in p</p>
<textarea/>
@@ -0,0 +1,29 @@
---
source: crates/oxc_formatter_htmlish/tests/fixtures/mod.rs
---
==================== Input ====================
<script src="a"/>
<div/>after
<p><my-el/>in p</p>
<textarea/>
==================== Output ====================
------------------
{ printWidth: 80 }
------------------
<script src="a" />
<div />
after
<p><my-el />in p</p>
<textarea />
-------------------
{ printWidth: 100 }
-------------------
<script src="a" />
<div />
after
<p><my-el />in p</p>
<textarea />
===================== End =====================