fix(formatter_core): leave blank frontmatter without dispatcher (#27359)

Always leave FM (in any form) as-is when `embeddedLanguageFormatting: off` (or Rust CLI).
This commit is contained in:
leaysgur committed 2026-10-06 02:57:14 +00:00
1 parent 37b3c48b2e
commit d730fdd17c
5 files changed
+17 -9

No files matched your search

+7
View File
@@ -68,6 +68,13 @@ describe("CSS front matter", () => {
});
expect(result.errors).toStrictEqual([]);
expect(result.code).toBe("---\ntitle: Home\n---\n\nb {\n}\n");
// Even an empty block is not normalized
const empty = await format("a.css", "---\n\n---\nb {}\n", {
embeddedLanguageFormatting: "off",
});
expect(empty.errors).toStrictEqual([]);
expect(empty.code).toBe("---\n\n---\n\nb {\n}\n");
});
it("keeps a physical BOM at byte 0, before the block", async () => {
@@ -18,13 +18,13 @@ use crate::{
/// Writes a front matter block.
///
/// The body dispatches through the session when its resolved language is in `embeddable_languages`,
/// the whole block stays verbatim otherwise.
/// The body dispatches through the session when a dispatcher is installed
/// and its resolved language is in `embeddable_languages`, the whole block stays verbatim otherwise.
/// Membership means "gets the frame treatment", not "gets formatted":
/// a member language without a serving formatter keeps its body verbatim (`PreserveOriginal`),
/// but its EMPTY block still normalizes through the frame.
/// Never fails; any refusal (`PreserveOriginal`, operational error, non-embeddable language) keeps the block's bytes as-is
/// while the host document still formats.
/// but its EMPTY block still normalizes through the frame when a dispatcher is installed.
/// Never fails; any refusal (`PreserveOriginal`, operational error, no dispatcher, non-embeddable language)
/// keeps the block's bytes as-is while the host document still formats.
///
/// The composed shape (Prettier `embed.js` + its css/markdown printers):
/// opening delimiter with the explicit language re-emitted (`---yaml`),
@@ -36,7 +36,7 @@ pub fn write_front_matter<'a, C: FormatContext>(
f: &mut Formatter<'_, 'a, C>,
) {
let language = fm.language();
if embeddable_languages.contains(&language) {
if f.session().has_dispatcher() && embeddable_languages.contains(&language) {
let body = fm.value.trim();
if body.is_empty() {
write_frame(fm, None, f);
+1 -1
View File
@@ -31,7 +31,7 @@ pub fn format<'a>(
options: CssFormatOptions,
) -> Result<Formatted<'a, CssFormatContext<'a>>, OxcDiagnostic> {
// NOTE: this wrapper labels the run `PhysicalFile` with NO services:
// front matter is detected but its body degrades to verbatim (`PreserveOriginal`),
// front matter is detected but kept verbatim (no dispatcher),
// and `@apply` Tailwind classes print unsorted.
// Hosts that want them use `format_with_session` with the services installed.
format_with_session(
@@ -26,8 +26,9 @@ const CSS: ConformanceConfig = ConformanceConfig {
ignore: &[
// postcss-conditionals (archived: https://github.com/andyjansson/postcss-conditionals).
"css/atrule/if-else.css",
// YAML frontmatter
// YAML frontmatter, needs the dispatcher this harness doesn't install
"css/yaml/dirty.css",
"css/yaml/empty_newlines.css",
// range formatting / IDE cursor, not whole-file formatting
"css/range/",
"css/cursor/",
@@ -2,7 +2,7 @@
source: crates/oxc_formatter_css/tests/conformance.rs
expression: report
---
css compatibility: 142/151 (94.04%), 13 files skipped
css compatibility: 141/150 (94.00%), 13 files skipped
# Failed