From e352ec591132c63abe9cb68bb1ab6813ca4199d6 Mon Sep 17 00:00:00 2001 From: Carson McManus Date: Sat, 1 Jun 2024 09:29:24 -0400 Subject: [PATCH] fix(formatter): escape double quotes when printing formatter IR --- .../src/format_element/document.rs | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/crates/biome_formatter/src/format_element/document.rs b/crates/biome_formatter/src/format_element/document.rs index 3363858f269f..e308558a4fa0 100644 --- a/crates/biome_formatter/src/format_element/document.rs +++ b/crates/biome_formatter/src/format_element/document.rs @@ -250,7 +250,35 @@ impl Format for &[FormatElement] { FormatElement::Space | FormatElement::HardSpace => { write!(f, [text(" ")])?; } - element if element.is_text() => f.write_element(element.clone())?, + element if element.is_text() => { + // escape quotes + let new_element = match element { + // except for static text because source_position is unknown + FormatElement::StaticText { .. } => element.clone(), + FormatElement::DynamicText { + text, + source_position, + } => { + let text = text.to_string().replace('"', "\\\""); + FormatElement::DynamicText { + text: text.into(), + source_position: *source_position, + } + } + FormatElement::LocatedTokenText { + slice, + source_position, + } => { + let text = slice.to_string().replace('"', "\\\""); + FormatElement::DynamicText { + text: text.into(), + source_position: *source_position, + } + } + _ => unreachable!(), + }; + f.write_element(new_element)?; + } _ => unreachable!(), } @@ -710,6 +738,10 @@ impl FormatElements for [FormatElement] { #[cfg(test)] mod tests { + use biome_js_syntax::JsSyntaxKind; + use biome_js_syntax::JsSyntaxToken; + use biome_rowan::TextSize; + use crate::prelude::*; use crate::SimpleFormatContext; use crate::{format, format_args, write}; @@ -837,4 +869,24 @@ mod tests { ]"# ); } + + #[test] + fn escapes_quotes() { + let token = JsSyntaxToken::new_detached(JsSyntaxKind::JS_STRING_LITERAL, "\"bar\"", [], []); + let token_text = FormatElement::LocatedTokenText { + source_position: TextSize::default(), + slice: token.token_text(), + }; + + let mut document = Document::from(vec![ + FormatElement::DynamicText { + text: "\"foo\"".into(), + source_position: TextSize::default(), + }, + token_text, + ]); + document.propagate_expand(); + + assert_eq!(&std::format!("{document}"), r#"["\"foo\"\"bar\""]"#); + } }