Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

Commit

Permalink
feat(rome_json_formatter): JSON Formatting number #2570
Browse files Browse the repository at this point in the history
  • Loading branch information
denbezrukov committed Dec 22, 2022
1 parent c20d6cf commit f6b959a
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 66 deletions.
Original file line number Diff line number Diff line change
@@ -1,23 +1,37 @@
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::utils::string::ToAsciiLowercaseCow;
use rome_rowan::{Language, SyntaxToken};
use std::borrow::Cow;
use std::num::NonZeroUsize;

pub(crate) struct CleanedNumberLiteralText<'token> {
token: &'token JsSyntaxToken,
use crate::prelude::*;
use crate::{CstFormatContext, Format};

pub struct CleanedNumberLiteralText<'token, L>
where
L: Language,
{
token: &'token SyntaxToken<L>,
text: Cow<'token, str>,
}

impl Format<JsFormatContext> for CleanedNumberLiteralText<'_> {
fn fmt(&self, f: &mut JsFormatter) -> FormatResult<()> {
impl<'token, L> CleanedNumberLiteralText<'token, L>
where
L: Language,
{
pub fn from_number_literal_token(token: &'token SyntaxToken<L>) -> Self {
CleanedNumberLiteralText {
token,
text: format_trimmed_number(token.text_trimmed()),
}
}
}

impl<L, C> Format<C> for CleanedNumberLiteralText<'_, L>
where
L: Language + 'static,
C: CstFormatContext<Language = L>,
{
fn fmt(&self, f: &mut Formatter<C>) -> FormatResult<()> {
format_replaced(
self.token,
&syntax_token_cow_slice(
Expand All @@ -30,25 +44,12 @@ impl Format<JsFormatContext> 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<NonZeroUsize>,
Expand All @@ -61,6 +62,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<str> {
use FormatNumberLiteralState::*;

let text = text.to_ascii_lowercase_cow();
let mut copied_or_ignored_chars = 0usize;
let mut iter = text.chars().enumerate();
Expand Down
2 changes: 2 additions & 0 deletions crates/rome_formatter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub mod comments;
pub mod diagnostics;
pub mod format_element;
mod format_extensions;
pub mod format_number;
pub mod formatter;
pub mod group_id;
pub mod macros;
Expand All @@ -38,6 +39,7 @@ pub mod printer;
pub mod separated;
mod source_map;
pub mod trivia;
mod utils;
mod verbatim;

use crate::formatter::Formatter;
Expand Down
1 change: 1 addition & 0 deletions crates/rome_formatter/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub(crate) mod string;
36 changes: 36 additions & 0 deletions crates/rome_formatter/src/utils/string.rs
Original file line number Diff line number Diff line change
@@ -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<str>;
}

impl ToAsciiLowercaseCow for str {
fn to_ascii_lowercase_cow(&self) -> Cow<str> {
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<str> {
self.as_str().to_ascii_lowercase_cow()
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::prelude::*;
use crate::utils::number_utils::CleanedNumberLiteralText;
use rome_formatter::format_number::CleanedNumberLiteralText;

use crate::parentheses::{is_member_object, NeedsParentheses};
use rome_js_syntax::JsNumberLiteralExpression;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::prelude::*;
use rome_formatter::format_number::CleanedNumberLiteralText;

use crate::parentheses::NeedsParentheses;
use crate::utils::number_utils::CleanedNumberLiteralText;
use rome_formatter::write;
use rome_js_syntax::{JsSyntaxNode, TsNumberLiteralType, TsNumberLiteralTypeFields};

Expand Down
1 change: 0 additions & 1 deletion crates/rome_js_formatter/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion crates/rome_json_formatter/src/json/value/number_value.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::prelude::*;
use rome_formatter::format_number::CleanedNumberLiteralText;
use rome_json_syntax::JsonNumberValue;

#[derive(Debug, Clone, Default)]
pub(crate) struct FormatJsonNumberValue;

impl FormatNodeRule<JsonNumberValue> for FormatJsonNumberValue {
fn fmt_fields(&self, node: &JsonNumberValue, f: &mut JsonFormatter) -> FormatResult<()> {
node.value_token()?.format().fmt(f)
CleanedNumberLiteralText::from_number_literal_token(&node.value_token()?).fmt(f)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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": "&#34; \u0022 %22 0x22 034 &#x22;",
Expand All @@ -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
Expand All @@ -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": " ",
Expand Down Expand Up @@ -178,9 +156,9 @@ info: json/json/pass1.json
1e1,
0.1e1,
1e-1,
1e00,
2e+00,
2e-00,
1,
2,
2,
"rosebud"
]
```
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -21,14 +20,14 @@ info:
@@ -1 +1,2 @@
--2.0
+-
+2.00000
+2.0
```

# Output

```json
-
2.00000
2.0
```

# Errors
Expand Down

0 comments on commit f6b959a

Please sign in to comment.