Skip to content

Commit f30ce4b

Browse files
committed
perf(formatter): optimize formatting literal string (#15380)
1 parent 8f25a0e commit f30ce4b

File tree

9 files changed

+175
-89
lines changed

9 files changed

+175
-89
lines changed

crates/oxc_formatter/src/formatter/builders.rs

Lines changed: 18 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{backtrace, borrow::Cow, cell::Cell, num::NonZeroU8};
1+
use std::{backtrace, cell::Cell, num::NonZeroU8};
22

33
use Tag::{
44
EndAlign, EndConditionalContent, EndDedent, EndEntry, EndFill, EndGroup, EndIndent,
@@ -302,6 +302,23 @@ pub fn text(text: &str) -> Text<'_> {
302302
Text { text, width: None }
303303
}
304304

305+
/// Creates a text from a dynamic string and a known width, for example,
306+
/// identifiers or numbers that do not contain line breaks.
307+
pub fn text_with_width(text: &str, width: TextWidth) -> Text<'_> {
308+
if width.is_multiline() {
309+
debug_assert!(
310+
text.as_bytes().iter().any(|&b| matches!(b, b'\n' | b'\t')),
311+
"Text with a known multiline width must contain at least one whitespace character. Found invalid content: '{text}'"
312+
);
313+
} else {
314+
debug_assert!(
315+
!text.as_bytes().iter().any(|&b| matches!(b, b'\n' | b'\t')),
316+
"Text with a known width must not contain whitespace characters when the width is single line. Found invalid content: '{text}'"
317+
);
318+
}
319+
Text { text, width: Some(width) }
320+
}
321+
305322
#[derive(Eq, PartialEq)]
306323
pub struct Text<'a> {
307324
text: &'a str,
@@ -325,49 +342,6 @@ impl std::fmt::Debug for Text<'_> {
325342
}
326343
}
327344

328-
/// String that is the same as in the input source text if `text` is [`Cow::Borrowed`] or
329-
/// some replaced content if `text` is [`Cow::Owned`].
330-
pub fn syntax_token_cow_slice(text: Cow<'_, str>, span: Span) -> SyntaxTokenCowSlice<'_> {
331-
debug_assert_no_newlines(&text);
332-
SyntaxTokenCowSlice { text, span }
333-
}
334-
335-
pub struct SyntaxTokenCowSlice<'a> {
336-
text: Cow<'a, str>,
337-
span: Span,
338-
}
339-
340-
impl<'a> Format<'a> for SyntaxTokenCowSlice<'a> {
341-
fn fmt(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
342-
match &self.text {
343-
Cow::Borrowed(content) => {
344-
// let range = TextRange::at(self.start, text.text_len());
345-
// debug_assert_eq!(
346-
// *text,
347-
// &self.token.token()[range - self.token.text_range().start()],
348-
// "The borrowed string doesn't match the specified token substring. Does the borrowed string belong to this token and range?"
349-
// );
350-
351-
// let relative_range = range - self.token.text_range().start();
352-
// let slice = self.token.token_text().slice(relative_range);
353-
354-
text(f.source_text().text_for(&self.span)).fmt(f)
355-
}
356-
Cow::Owned(text) => f.write_element(FormatElement::Text {
357-
// TODO: Should use arena String to replace Cow::Owned.
358-
text: f.context().allocator().alloc_str(text),
359-
width: TextWidth::from_text(text, f.options().indent_width),
360-
}),
361-
}
362-
}
363-
}
364-
365-
impl std::fmt::Debug for SyntaxTokenCowSlice<'_> {
366-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
367-
std::write!(f, "SyntaxTokenCowSlice({})", self.text)
368-
}
369-
}
370-
371345
#[track_caller]
372346
fn debug_assert_no_newlines(text: &str) {
373347
debug_assert!(

crates/oxc_formatter/src/formatter/format_element/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,11 @@ impl TextWidth {
420420
Self::Width(Width::new(width))
421421
}
422422

423+
pub fn from_len(len: usize) -> TextWidth {
424+
#[expect(clippy::cast_possible_truncation)]
425+
TextWidth::Width(Width::new(len as u32))
426+
}
427+
423428
pub const fn width(self) -> Option<Width> {
424429
match self {
425430
TextWidth::Width(width) => Some(width),

crates/oxc_formatter/src/formatter/token/number.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ pub struct CleanedNumberLiteralText<'a> {
4040

4141
impl<'a> Format<'a> for CleanedNumberLiteralText<'a> {
4242
fn fmt(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
43-
syntax_token_cow_slice(format_trimmed_number(self.text, self.options), self.span).fmt(f)
43+
let text = format_trimmed_number(self.text, self.options);
44+
let width = TextWidth::from_len(text.len());
45+
text_with_width(f.context().allocator().alloc_str(&text), width).fmt(f)
4446
}
4547
}
4648

crates/oxc_formatter/src/utils/assignment_like.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use crate::{
2727
},
2828
};
2929

30-
use super::string_utils::{FormatLiteralStringToken, StringLiteralParentKind};
30+
use super::string::{FormatLiteralStringToken, StringLiteralParentKind};
3131

3232
#[derive(Clone, Copy)]
3333
pub enum AssignmentLike<'a, 'b> {

crates/oxc_formatter/src/utils/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub mod jsx;
88
pub mod member_chain;
99
pub mod object;
1010
pub mod statement_body;
11-
pub mod string_utils;
11+
pub mod string;
1212
pub mod suppressed;
1313
pub mod typecast;
1414
pub mod typescript;

crates/oxc_formatter/src/utils/object.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
Buffer, Format, FormatResult,
77
ast_nodes::{AstNode, AstNodes},
88
formatter::Formatter,
9-
utils::string_utils::{FormatLiteralStringToken, StringLiteralParentKind},
9+
utils::string::{FormatLiteralStringToken, StringLiteralParentKind},
1010
write,
1111
};
1212

0 commit comments

Comments
 (0)