fix(oxfmt): format HTML in a <script> body as an embedded part (#28379)

```html
<script type="text/html">
  <div style="color:red;background:blue" onclick="foo( 1 )" class="  a   b  ">x</div>
</script>
```

will be formatted:

```html
<script type="text/html">
  <div style="color:red;background:blue" onclick="foo( 1 )" class="  a   b  ">
    x
  </div>
</script>
```

Note attributes are NOT.
This commit is contained in:
Yuji Sugiura authored and GitHub committed 2026-10-30 07:49:53 +00:00
1 parent b1def652d3
commit 2e7a629be8
4 files changed
+26 -18

No files matched your search

@@ -0,0 +1,3 @@
<script type="text/html">
<div style="color:red;background:blue" onclick="foo( 1 )" class=" a b ">x</div>
</script>
@@ -370,7 +370,7 @@
## html
### Option 1: 617/623 (99.04%)
### Option 1: 618/624 (99.04%)
```json
{"printWidth":80}
@@ -389,7 +389,7 @@
- [externals/vite/html/valid.html](diffs/html/externals__vite__html__valid.html.md)
- crates/oxc_formatter_htmlish/DIVERGENCES.md#unquoted-value-with-slash
### Option 2: 618/623 (99.20%)
### Option 2: 619/624 (99.20%)
```json
{"printWidth":100,"htmlWhitespaceSensitivity":"ignore","singleAttributePerLine":true}
@@ -406,7 +406,7 @@
- [externals/vite/html/valid.html](diffs/html/externals__vite__html__valid.html.md)
- crates/oxc_formatter_htmlish/DIVERGENCES.md#unquoted-value-with-slash
### Option 3: 617/623 (99.04%)
### Option 3: 618/624 (99.04%)
```json
{"printWidth":120,"htmlWhitespaceSensitivity":"strict","bracketSameLine":true}
+14 -14
View File
@@ -26,6 +26,7 @@ use oxc_formatter_markdown::{MarkdownFormatOptions, XxxInMarkdownCodeBlock};
use oxc_formatter_toml::TomlFormatOptions;
use oxc_formatter_yaml::YamlFormatOptions;
use super::jsdoc_fence::XxxInJsdocFence;
use crate::core::{
language::{Route, route_embedded},
options::{
@@ -341,20 +342,19 @@ pub fn build_dispatcher(
dispatch_config.toml_options(),
),
NativeLanguage::Html(variant) => {
// Embedded in a JS template literal or a Markdown code block;
// `None` is a part formatted on its own (a JSDoc code block).
// An HTML parent added later needs its marker here, or reads as standalone.
let embedded_in = request
.parent_context_as::<HtmlInJsTemplate>()
.map(|c| HtmlishEmbeddedIn {
indent_multiple_roots: c.indent_multiple_roots,
placeholder: Some(c.placeholder),
})
.or_else(|| {
request
.parent_context_as::<XxxInMarkdownCodeBlock>()
.map(|_| HtmlishEmbeddedIn::default())
});
// Every part is embedded in its parent (Prettier's `parentParser`),
// but a JSDoc code block, formatted on its own
let embedded_in =
if let Some(c) = request.parent_context_as::<HtmlInJsTemplate>() {
Some(HtmlishEmbeddedIn {
indent_multiple_roots: c.indent_multiple_roots,
placeholder: Some(c.placeholder),
})
} else if request.parent_context_as::<XxxInJsdocFence>().is_some() {
None
} else {
Some(HtmlishEmbeddedIn::default())
};
oxc_formatter_htmlish::format_to_ir(
session,
text,
+6 -1
View File
@@ -16,6 +16,11 @@ use oxc_formatter_core::{
use super::dispatcher::ResolvedDispatchConfig;
/// Parent→child context for a JSDoc fenced code block:
/// a part formatted on its own, as Prettier formats it (`prettier.format`, no `parentParser`),
/// where every other dispatched part is embedded in its parent.
pub struct XxxInJsdocFence;
/// The session's string embedder: [`format_native_fence`] over `fence_dispatcher`,
/// a fallback-less registry (a native fence never falls back to Prettier).
/// `sort_tailwind` is the root's pre-bound sorter, for the `@apply` classes a CSS fence collects.
@@ -76,7 +81,7 @@ fn format_native_fence(
language,
text: code,
input_kind: InputKind::Fragment,
parent_context: None,
parent_context: Some(&XxxInJsdocFence),
},
printer_options,
)?