diff --git a/apps/oxfmt/conformance/fixtures/edge-cases/html/nested-html-in-script.html b/apps/oxfmt/conformance/fixtures/edge-cases/html/nested-html-in-script.html new file mode 100644 index 0000000000..cda8581c92 --- /dev/null +++ b/apps/oxfmt/conformance/fixtures/edge-cases/html/nested-html-in-script.html @@ -0,0 +1,3 @@ + diff --git a/apps/oxfmt/conformance/snapshots/conformance.snap.md b/apps/oxfmt/conformance/snapshots/conformance.snap.md index 232ba9ed4a..8f3fcb8c2a 100644 --- a/apps/oxfmt/conformance/snapshots/conformance.snap.md +++ b/apps/oxfmt/conformance/snapshots/conformance.snap.md @@ -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} diff --git a/apps/oxfmt/src/core/embed/dispatcher.rs b/apps/oxfmt/src/core/embed/dispatcher.rs index e5860d1c06..9fecdfddfc 100644 --- a/apps/oxfmt/src/core/embed/dispatcher.rs +++ b/apps/oxfmt/src/core/embed/dispatcher.rs @@ -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::() - .map(|c| HtmlishEmbeddedIn { - indent_multiple_roots: c.indent_multiple_roots, - placeholder: Some(c.placeholder), - }) - .or_else(|| { - request - .parent_context_as::() - .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::() { + Some(HtmlishEmbeddedIn { + indent_multiple_roots: c.indent_multiple_roots, + placeholder: Some(c.placeholder), + }) + } else if request.parent_context_as::().is_some() { + None + } else { + Some(HtmlishEmbeddedIn::default()) + }; oxc_formatter_htmlish::format_to_ir( session, text, diff --git a/apps/oxfmt/src/core/embed/jsdoc_fence.rs b/apps/oxfmt/src/core/embed/jsdoc_fence.rs index 63baab92fe..ac7a30a240 100644 --- a/apps/oxfmt/src/core/embed/jsdoc_fence.rs +++ b/apps/oxfmt/src/core/embed/jsdoc_fence.rs @@ -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, )?