From b00da37189c6102668e8adc70366278956103fca Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Wed, 24 Dec 2025 01:05:05 +0000 Subject: [PATCH] feat(formatter): normalize line break for directive (#17303) Fixes panic caused by https://github.com/oxc-project/oxc/blob/88a38b249a4d5927c733c2ef029a9ebc3fc13c48/crates/oxc_formatter/src/formatter/builders.rs#L336-L348 in #17261 --- .../src/formatter/format_element/mod.rs | 1 - crates/oxc_formatter/src/utils/string.rs | 27 +++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/crates/oxc_formatter/src/formatter/format_element/mod.rs b/crates/oxc_formatter/src/formatter/format_element/mod.rs index 74d39e0667f6c..a6479d42e2c79 100644 --- a/crates/oxc_formatter/src/formatter/format_element/mod.rs +++ b/crates/oxc_formatter/src/formatter/format_element/mod.rs @@ -201,7 +201,6 @@ pub const LINE_TERMINATORS: [char; 3] = ['\r', LINE_SEPARATOR, PARAGRAPH_SEPARAT /// Replace the line terminators matching the provided list with "\n" /// since its the only line break type supported by the printer -#[expect(unused)] pub fn normalize_newlines(text: &str, terminators: [char; N]) -> Cow<'_, str> { let mut result = String::new(); let mut last_end = 0; diff --git a/crates/oxc_formatter/src/utils/string.rs b/crates/oxc_formatter/src/utils/string.rs index 7d6e466902c03..4f5bdae58250e 100644 --- a/crates/oxc_formatter/src/utils/string.rs +++ b/crates/oxc_formatter/src/utils/string.rs @@ -208,7 +208,7 @@ impl<'a> LiteralStringNormalizer<'a> { } fn normalize_directive(&self, string_information: StringInformation) -> Cow<'a, str> { - // In diretcives, unnecessary escapes should be preserved. + // In directives, unnecessary escapes should be preserved. // See https://github.com/prettier/prettier/issues/1555 // Thus we don't normalize the string. // @@ -217,10 +217,27 @@ impl<'a> LiteralStringNormalizer<'a> { // // Note that we could change the quotes if the preferred quote is escaped. // However, Prettier doesn't go that far. - if string_information.raw_content_has_quotes { - Cow::Borrowed(self.token.string) - } else { - self.swap_quotes(self.raw_content(), string_information) + let normalized = normalize_newlines(self.raw_content(), ['\r']); + match normalized { + Cow::Borrowed(string) => { + if string_information.raw_content_has_quotes { + Cow::Borrowed(self.token.string) + } else { + self.swap_quotes(string, string_information) + } + } + Cow::Owned(string) => { + let mut s = String::with_capacity(string.len() + 2); + let quote = if string_information.raw_content_has_quotes { + string_information.current_quote.as_char() + } else { + string_information.preferred_quote.as_char() + }; + s.push(quote); + s.push_str(&string); + s.push(quote); + Cow::Owned(s) + } } }