Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 8 additions & 16 deletions crates/oxc_formatter/src/formatter/builders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use Tag::{
StartLabelled, StartLineSuffix,
};
use oxc_span::{GetSpan, Span};
use oxc_syntax::identifier::{is_line_terminator, is_white_space_single_line};
use oxc_syntax::identifier::{is_identifier_name, is_line_terminator, is_white_space_single_line};

use super::{
Argument, Arguments, Buffer, Comments, GroupId, TextSize, VecBuffer,
Expand Down Expand Up @@ -302,21 +302,13 @@ pub fn text(text: &str) -> Text<'_> {
Text { text, width: None }
}

/// Creates a text from a dynamic string and a known width, for example,
/// identifiers or numbers that do not contain line breaks.
pub fn text_with_width(text: &str, width: TextWidth) -> Text<'_> {
if width.is_multiline() {
debug_assert!(
text.as_bytes().iter().any(|&b| matches!(b, b'\n' | b'\t')),
"Text with a known multiline width must contain at least one whitespace character. Found invalid content: '{text}'"
);
} else {
debug_assert!(
!text.as_bytes().iter().any(|&b| matches!(b, b'\n' | b'\t')),
"Text with a known width must not contain whitespace characters when the width is single line. Found invalid content: '{text}'"
);
}
Text { text, width: Some(width) }
/// Creates a text from a dynamic string that contains no whitespace characters
pub fn text_without_whitespace(text: &str) -> Text<'_> {
debug_assert!(
text.as_bytes().iter().all(|&b| !b.is_ascii_whitespace()),
"The content '{text}' contains whitespace characters but text must not contain any whitespace characters."
);
Text { text, width: Some(TextWidth::from_non_whitespace_str(text)) }
}

#[derive(Eq, PartialEq)]
Expand Down
7 changes: 6 additions & 1 deletion crates/oxc_formatter/src/formatter/format_element/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::hash::{Hash, Hasher};
use std::num::NonZeroU32;
use std::{borrow::Cow, ops::Deref, rc::Rc};

use unicode_width::UnicodeWidthChar;
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};

use crate::{IndentWidth, TabWidth};

Expand Down Expand Up @@ -420,6 +420,11 @@ impl TextWidth {
Self::Width(Width::new(width))
}

pub fn from_non_whitespace_str(name: &str) -> TextWidth {
#[expect(clippy::cast_possible_truncation)]
Self::Width(Width::new(name.width() as u32))
}

pub fn from_len(len: usize) -> TextWidth {
#[expect(clippy::cast_possible_truncation)]
TextWidth::Width(Width::new(len as u32))
Expand Down
3 changes: 1 addition & 2 deletions crates/oxc_formatter/src/formatter/token/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ pub struct CleanedNumberLiteralText<'a> {
impl<'a> Format<'a> for CleanedNumberLiteralText<'a> {
fn fmt(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
let text = format_trimmed_number(self.text, self.options);
let width = TextWidth::from_len(text.len());
text_with_width(f.context().allocator().alloc_str(&text), width).fmt(f)
text_without_whitespace(f.context().allocator().alloc_str(&text)).fmt(f)
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_formatter/src/utils/jsx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ impl<'a> JsxWord<'a> {

impl<'a> Format<'a> for JsxWord<'a> {
fn fmt(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
write!(f, [text(self.text)])
write!(f, [text_without_whitespace(self.text)])
}
}

Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_formatter/src/write/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl<'a> FormatWrite<'a> for AstNode<'a, PropertyDefinition<'a>> {

impl<'a> FormatWrite<'a> for AstNode<'a, PrivateIdentifier<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
write!(f, ["#", text(self.name().as_str())])
write!(f, ["#", text_without_whitespace(self.name().as_str())])
}
}

Expand Down Expand Up @@ -214,7 +214,7 @@ impl<'a> Format<'a> for AstNode<'a, Vec<'a, TSIndexSignatureName<'a>>> {

impl<'a> FormatWrite<'a> for AstNode<'a, TSIndexSignatureName<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
write!(f, [text(self.name().as_str()), self.type_annotation()])
write!(f, [text_without_whitespace(self.name().as_str()), self.type_annotation()])
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_formatter/src/write/jsx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ impl<'a> FormatWrite<'a> for AstNode<'a, JSXSpreadAttribute<'a>> {

impl<'a> FormatWrite<'a> for AstNode<'a, JSXIdentifier<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
write!(f, text(self.name().as_str()))
write!(f, text_without_whitespace(self.name().as_str()))
}
}

Expand Down
10 changes: 5 additions & 5 deletions crates/oxc_formatter/src/write/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,25 +103,25 @@ pub trait FormatWrite<'ast, T = ()> {

impl<'a> FormatWrite<'a> for AstNode<'a, IdentifierName<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
write!(f, text(self.name().as_str()))
write!(f, text_without_whitespace(self.name().as_str()))
}
}

impl<'a> FormatWrite<'a> for AstNode<'a, IdentifierReference<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
write!(f, text(self.name().as_str()))
write!(f, text_without_whitespace(self.name().as_str()))
}
}

impl<'a> FormatWrite<'a> for AstNode<'a, BindingIdentifier<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
write!(f, text(self.name().as_str()))
write!(f, text_without_whitespace(self.name().as_str()))
}
}

impl<'a> FormatWrite<'a> for AstNode<'a, LabelIdentifier<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
write!(f, text(self.name().as_str()))
write!(f, text_without_whitespace(self.name().as_str()))
}
}

Expand Down Expand Up @@ -1095,7 +1095,7 @@ impl<'a> FormatWrite<'a> for AstNode<'a, RegExpLiteral<'a>> {
flags.sort_unstable();
let flags = flags.iter().collect::<String>();
let s = StringBuilder::from_strs_array_in([pattern, "/", &flags], f.context().allocator());
write!(f, text(s.into_str(),))
write!(f, text(s.into_str()))
}
}

Expand Down
Loading