diff --git a/crates/rome_formatter/src/lib.rs b/crates/rome_formatter/src/lib.rs index 8ac338e9517..98dfe6d379f 100644 --- a/crates/rome_formatter/src/lib.rs +++ b/crates/rome_formatter/src/lib.rs @@ -37,6 +37,7 @@ pub mod printed_tokens; pub mod printer; pub mod separated; mod source_map; +pub mod token; pub mod trivia; mod verbatim; diff --git a/crates/rome_formatter/src/token/mod.rs b/crates/rome_formatter/src/token/mod.rs new file mode 100644 index 00000000000..6cdb135d40a --- /dev/null +++ b/crates/rome_formatter/src/token/mod.rs @@ -0,0 +1,2 @@ +pub mod number; +pub(crate) mod string; diff --git a/crates/rome_js_formatter/src/utils/number_utils.rs b/crates/rome_formatter/src/token/number.rs similarity index 90% rename from crates/rome_js_formatter/src/utils/number_utils.rs rename to crates/rome_formatter/src/token/number.rs index 81e2dce9385..ce65a7d5203 100644 --- a/crates/rome_js_formatter/src/utils/number_utils.rs +++ b/crates/rome_formatter/src/token/number.rs @@ -1,27 +1,35 @@ -use crate::prelude::*; -use crate::utils::string_utils::ToAsciiLowercaseCow; -use crate::JsFormatContext; -use crate::JsFormatter; -use rome_formatter::trivia::format_replaced; -use rome_formatter::Format; -use rome_formatter::FormatResult; -use rome_js_syntax::JsSyntaxKind::JS_NUMBER_LITERAL; -use rome_js_syntax::JsSyntaxKind::TS_NUMBER_LITERAL_TYPE; -use rome_js_syntax::JsSyntaxToken; +use crate::token::string::ToAsciiLowercaseCow; +use rome_rowan::{Language, SyntaxToken}; use std::borrow::Cow; use std::num::NonZeroUsize; -pub(crate) struct CleanedNumberLiteralText<'token> { - token: &'token JsSyntaxToken, - text: Cow<'token, str>, +use crate::prelude::*; +use crate::{CstFormatContext, Format}; + +pub fn format_number_token(token: &SyntaxToken) -> CleanedNumberLiteralText +where + L: Language, +{ + CleanedNumberLiteralText { token } } -impl Format for CleanedNumberLiteralText<'_> { - fn fmt(&self, f: &mut JsFormatter) -> FormatResult<()> { +pub struct CleanedNumberLiteralText<'token, L> +where + L: Language, +{ + token: &'token SyntaxToken, +} + +impl Format for CleanedNumberLiteralText<'_, L> +where + L: Language + 'static, + C: CstFormatContext, +{ + fn fmt(&self, f: &mut Formatter) -> FormatResult<()> { format_replaced( self.token, &syntax_token_cow_slice( - self.text.clone(), + format_trimmed_number(self.token.text_trimmed()), self.token, self.token.text_trimmed_range().start(), ), @@ -30,25 +38,12 @@ impl Format for CleanedNumberLiteralText<'_> { } } -impl<'token> CleanedNumberLiteralText<'token> { - pub fn from_number_literal_token(token: &'token JsSyntaxToken) -> Self { - debug_assert!(matches!( - &token.kind(), - JS_NUMBER_LITERAL | TS_NUMBER_LITERAL_TYPE - )); - CleanedNumberLiteralText { - token, - text: format_trimmed_number(token.text_trimmed()), - } - } -} - enum FormatNumberLiteralState { IntegerPart, DecimalPart(FormatNumberLiteralDecimalPart), Exponent(FormatNumberLiteralExponent), } -use FormatNumberLiteralState::*; + struct FormatNumberLiteralDecimalPart { dot_index: usize, last_non_zero_index: Option, @@ -61,6 +56,8 @@ struct FormatNumberLiteralExponent { } // Regex-free version of https://github.com/prettier/prettier/blob/ca246afacee8e6d5db508dae01730c9523bbff1d/src/common/util.js#L341-L356 fn format_trimmed_number(text: &str) -> Cow { + use FormatNumberLiteralState::*; + let text = text.to_ascii_lowercase_cow(); let mut copied_or_ignored_chars = 0usize; let mut iter = text.chars().enumerate(); diff --git a/crates/rome_formatter/src/token/string.rs b/crates/rome_formatter/src/token/string.rs new file mode 100644 index 00000000000..82fff862bcb --- /dev/null +++ b/crates/rome_formatter/src/token/string.rs @@ -0,0 +1,36 @@ +use std::borrow::Cow; + +pub trait ToAsciiLowercaseCow { + /// Returns the same value as String::to_lowercase. The only difference + /// is that this functions returns ```Cow``` and does not allocate + /// if the string is already in lowercase. + fn to_ascii_lowercase_cow(&self) -> Cow; +} + +impl ToAsciiLowercaseCow for str { + fn to_ascii_lowercase_cow(&self) -> Cow { + debug_assert!(self.is_ascii()); + + let bytes = self.as_bytes(); + + for idx in 0..bytes.len() { + let chr = bytes[idx]; + if chr != chr.to_ascii_lowercase() { + let mut s = bytes.to_vec(); + for b in &mut s[idx..] { + b.make_ascii_lowercase(); + } + return Cow::Owned(unsafe { String::from_utf8_unchecked(s) }); + } + } + + Cow::Borrowed(self) + } +} + +impl ToAsciiLowercaseCow for String { + #[inline(always)] + fn to_ascii_lowercase_cow(&self) -> Cow { + self.as_str().to_ascii_lowercase_cow() + } +} diff --git a/crates/rome_js_formatter/src/js/expressions/number_literal_expression.rs b/crates/rome_js_formatter/src/js/expressions/number_literal_expression.rs index cf22aad81df..c8f8f99605a 100644 --- a/crates/rome_js_formatter/src/js/expressions/number_literal_expression.rs +++ b/crates/rome_js_formatter/src/js/expressions/number_literal_expression.rs @@ -1,5 +1,5 @@ use crate::prelude::*; -use crate::utils::number_utils::CleanedNumberLiteralText; +use rome_formatter::token::number::format_number_token; use crate::parentheses::{is_member_object, NeedsParentheses}; use rome_js_syntax::JsNumberLiteralExpression; @@ -15,7 +15,7 @@ impl FormatNodeRule for FormatJsNumberLiteralExpressi f: &mut JsFormatter, ) -> FormatResult<()> { let JsNumberLiteralExpressionFields { value_token } = node.as_fields(); - CleanedNumberLiteralText::from_number_literal_token(&value_token?).fmt(f) + format_number_token(&value_token?).fmt(f) } fn needs_parentheses(&self, item: &JsNumberLiteralExpression) -> bool { diff --git a/crates/rome_js_formatter/src/ts/types/number_literal_type.rs b/crates/rome_js_formatter/src/ts/types/number_literal_type.rs index 9543ef59c77..00adb519f00 100644 --- a/crates/rome_js_formatter/src/ts/types/number_literal_type.rs +++ b/crates/rome_js_formatter/src/ts/types/number_literal_type.rs @@ -1,7 +1,7 @@ use crate::prelude::*; +use rome_formatter::token::number::format_number_token; use crate::parentheses::NeedsParentheses; -use crate::utils::number_utils::CleanedNumberLiteralText; use rome_formatter::write; use rome_js_syntax::{JsSyntaxNode, TsNumberLiteralType, TsNumberLiteralTypeFields}; @@ -16,10 +16,7 @@ impl FormatNodeRule for FormatTsNumberLiteralType { } = node.as_fields(); write![ f, - [ - minus_token.format(), - CleanedNumberLiteralText::from_number_literal_token(&literal_token?) - ] + [minus_token.format(), format_number_token(&literal_token?)] ] } diff --git a/crates/rome_js_formatter/src/utils/mod.rs b/crates/rome_js_formatter/src/utils/mod.rs index 3134a1fafb2..be6a0b2a51d 100644 --- a/crates/rome_js_formatter/src/utils/mod.rs +++ b/crates/rome_js_formatter/src/utils/mod.rs @@ -2,7 +2,6 @@ pub(crate) mod array; mod assignment_like; mod binary_like_expression; mod conditional; -pub(crate) mod number_utils; pub mod string_utils; pub(crate) mod format_class; diff --git a/crates/rome_json_formatter/src/json/value/number_value.rs b/crates/rome_json_formatter/src/json/value/number_value.rs index 3d05e07d2a8..9f0a21c3a4d 100644 --- a/crates/rome_json_formatter/src/json/value/number_value.rs +++ b/crates/rome_json_formatter/src/json/value/number_value.rs @@ -1,4 +1,5 @@ use crate::prelude::*; +use rome_formatter::token::number::format_number_token; use rome_json_syntax::JsonNumberValue; #[derive(Debug, Clone, Default)] @@ -6,6 +7,6 @@ pub(crate) struct FormatJsonNumberValue; impl FormatNodeRule for FormatJsonNumberValue { fn fmt_fields(&self, node: &JsonNumberValue, f: &mut JsonFormatter) -> FormatResult<()> { - node.value_token()?.format().fmt(f) + format_number_token(&node.value_token()?).fmt(f) } } diff --git a/crates/rome_json_formatter/tests/specs/json/number.json b/crates/rome_json_formatter/tests/specs/json/number.json new file mode 100644 index 00000000000..7e185425bb3 --- /dev/null +++ b/crates/rome_json_formatter/tests/specs/json/number.json @@ -0,0 +1,27 @@ +[ + { + "integer": 1234567890, + "real": -9876.543210, + "e": 0.123456789e-12, + "E": 1.234567890E+34, + "": 23456789012E66, + "zero": 0, + "one": 1, + " s p a c e d ": [ + 1, 2, 3, + + 4, 5, 6, 7 + ] + }, + 0.5, + 98.6, + 99.44, + 1066, + 1e1, + 0.1e1, + 1e-1, + 1, + 2, + 2, + 2.00000 +] diff --git a/crates/rome_json_formatter/tests/specs/json/number.json.snap b/crates/rome_json_formatter/tests/specs/json/number.json.snap new file mode 100644 index 00000000000..2ed3eff7920 --- /dev/null +++ b/crates/rome_json_formatter/tests/specs/json/number.json.snap @@ -0,0 +1,81 @@ +--- +source: crates/rome_formatter_test/src/snapshot_builder.rs +info: json/number.json +--- + +# Input + +```json +[ + { + "integer": 1234567890, + "real": -9876.543210, + "e": 0.123456789e-12, + "E": 1.234567890E+34, + "": 23456789012E66, + "zero": 0, + "one": 1, + " s p a c e d ": [ + 1, 2, 3, + + 4, 5, 6, 7 + ] + }, + 0.5, + 98.6, + 99.44, + 1066, + 1e1, + 0.1e1, + 1e-1, + 1, + 2, + 2, + 2.00000 +] + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Line width: 80 +----- + +```json +[ + { + "integer": 1234567890, + "real": -9876.54321, + "e": 0.123456789e-12, + "E": 1.23456789e34, + "": 23456789012e66, + "zero": 0, + "one": 1, + " s p a c e d ": [ + 1, 2, 3, + + 4, 5, 6, 7 + ] + }, + 0.5, + 98.6, + 99.44, + 1066, + 1e1, + 0.1e1, + 1e-1, + 1, + 2, + 2, + 2.0 +] +``` + + diff --git a/crates/rome_json_formatter/tests/specs/prettier/json/json/pass1.json.snap b/crates/rome_json_formatter/tests/specs/prettier/json/json/pass1.json.snap index 9437c677007..5517857da99 100644 --- a/crates/rome_json_formatter/tests/specs/prettier/json/json/pass1.json.snap +++ b/crates/rome_json_formatter/tests/specs/prettier/json/json/pass1.json.snap @@ -73,20 +73,7 @@ info: json/json/pass1.json ```diff --- Prettier +++ Rome -@@ -9,17 +9,17 @@ - null, - { - "integer": 1234567890, -- "real": -9876.54321, -+ "real": -9876.543210, - "e": 0.123456789e-12, -- "E": 1.23456789e34, -- "": 23456789012e66, -+ "E": 1.234567890E+34, -+ "": 23456789012E66, - "zero": 0, - "one": 1, - "space": " ", +@@ -19,7 +19,7 @@ "quote": "\"", "backslash": "\\", "controls": "\b\f\n\r\t", @@ -95,7 +82,7 @@ info: json/json/pass1.json "alpha": "abcdefghijklmnopqrstuvwyz", "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", "digit": "0123456789", -@@ -43,17 +43,18 @@ +@@ -43,11 +43,12 @@ "compact": [1, 2, 3, 4, 5, 6, 7], "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", "quotes": "" \u0022 %22 0x22 034 "", @@ -109,15 +96,6 @@ info: json/json/pass1.json 1066, 1e1, 0.1e1, - 1e-1, -- 1, -- 2, -- 2, -+ 1e00, -+ 2e+00, -+ 2e-00, - "rosebud" - ] ``` # Output @@ -134,10 +112,10 @@ info: json/json/pass1.json null, { "integer": 1234567890, - "real": -9876.543210, + "real": -9876.54321, "e": 0.123456789e-12, - "E": 1.234567890E+34, - "": 23456789012E66, + "E": 1.23456789e34, + "": 23456789012e66, "zero": 0, "one": 1, "space": " ", @@ -178,9 +156,9 @@ info: json/json/pass1.json 1e1, 0.1e1, 1e-1, - 1e00, - 2e+00, - 2e-00, + 1, + 2, + 2, "rosebud" ] ``` diff --git a/crates/rome_json_formatter/tests/specs/prettier/json/range/unary-expression-2.json.snap b/crates/rome_json_formatter/tests/specs/prettier/json/range/unary-expression-2.json.snap index dea573db691..e6146d091f2 100644 --- a/crates/rome_json_formatter/tests/specs/prettier/json/range/unary-expression-2.json.snap +++ b/crates/rome_json_formatter/tests/specs/prettier/json/range/unary-expression-2.json.snap @@ -1,7 +1,6 @@ --- source: crates/rome_formatter_test/src/snapshot_builder.rs -info: - test_file: json/range/unary-expression-2.json +info: json/range/unary-expression-2.json --- # Input @@ -21,14 +20,14 @@ info: @@ -1 +1,2 @@ --2.0 +- -+2.00000 ++2.0 ``` # Output ```json - -2.00000 +2.0 ``` # Errors