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

Commit

Permalink
feat(rome_formatter): add support to format comments (#4718)
Browse files Browse the repository at this point in the history
* feat: 🎸 allow comments in json file

* chore: 🤖 fmt

* chore: 🤖 update schema

* chore: 🤖 lint

* chore: 🤖 update codegen

* chore: 🤖 pass all tests

* chore: 🤖 basic finish parse with comments

* chore: 🤖 format

* chore: 🤖 lint

* fix: 🐛 compile erorr

* chore: 🤖 add matcher

* chore: 🤖 add extra test

* chore: 🤖 update snap

* chore: 🤖 update snap

* chore: 🤖 basic finish

* fix Cargo.toml

* chore: rebase

* chore: rebase

* just ready

* feat(rome_formatter): add support to format comments

* chore: add proper comments

* update changelog

* refactor

* update playground

* regression

---------

Co-authored-by: IWANABETHATGUY <iwanabethatguy@qq.com>
  • Loading branch information
ematipico and IWANABETHATGUY authored Jul 21, 2023
1 parent 22bca8e commit a65c626
Show file tree
Hide file tree
Showing 32 changed files with 878 additions and 381 deletions.
28 changes: 26 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,18 @@ if no error diagnostics are emitted.
rome check --error-on-wanrings ./src
```

- Add a configuration to enable parsing comments inside JSON files:

```json
{
"json": {
"parser": {
"allowComments": true
}
}
}
```

### Editors

#### Other changes
Expand All @@ -99,9 +111,11 @@ if no error diagnostics are emitted.

### Formatter

- Added a new option called `--jsx-quote-style` to the formatter. This option allows you to choose between single and double quotes for JSX attributes. [#4486](https://github.com/rome/tools/issues/4486)
- Add a new option called `--jsx-quote-style` to the formatter. This option allows you to choose between single and double quotes for JSX attributes. [#4486](https://github.com/rome/tools/issues/4486)

- Added a new option called `--arrow-parentheses` to the formatter. This option allows you to set the parentheses style for arrow functions. [#4666](https://github.com/rome/tools/issues/4666)
- Add a new option called `--arrow-parentheses` to the formatter. This option allows you to set the parentheses style for arrow functions. [#4666](https://github.com/rome/tools/issues/4666)

- The JSON formatter is now able to format `.json` files that have comments.

### Linter

Expand Down Expand Up @@ -345,7 +359,17 @@ if no error diagnostics are emitted.
}
}
```
- Add for parsing comments inside JSON files:

```json
{
"json": {
"parser": {
"allowComments": true
}
}
}
```
### VSCode

### JavaScript APIs
Expand Down
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ rome_migrate = { path = "./crates/rome_migrate" }
rome_parser = { version = "0.0.1", path = "./crates/rome_parser" }
rome_rowan = { version = "0.0.1", path = "./crates/rome_rowan" }
rome_service = { path = "./crates/rome_service" }
rome_suppression = { version = "0.0.1", path = "./crates/rome_suppression" }
rome_text_edit = { version = "0.0.1", path = "./crates/rome_text_edit" }
rome_text_size = { version = "0.0.1", path = "./crates/rome_text_size" }
tests_macros = { path = "./crates/tests_macros" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,19 @@ expression: content

/*test*/ [1, 2, 3]

```

# Termination Message

```block
internalError/io ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
× No files were processed in the specified paths.
```

# Emitted Messages

```block
tsconfig.json format ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
× Format with errors is disabled.
i Formatter would have printed the following content:
1 │ -
2 1 │ /*test*/ [1, 2, 3]
3 │ - →
2 │ +
```
Expand All @@ -45,8 +39,4 @@ tsconfig.json format ━━━━━━━━━━━━━━━━━━━
Compared 1 file(s) in <TIME>
```

```block
Skipped 1 file(s)
```


44 changes: 44 additions & 0 deletions crates/rome_formatter/src/comments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1173,3 +1173,47 @@ where
write!(f, [item.piece.as_piece()])
}
}

/// Returns `true` if `comment` is a multi line block comment:
///
/// # Examples
///
/// ```rs,ignore
/// assert!(is_doc_comment(&parse_comment(r#"
/// /**
/// * Multiline doc comment
/// */
/// "#)));
///
/// assert!(is_doc_comment(&parse_comment(r#"
/// /*
/// * Single star
/// */
/// "#)));
///
///
/// // Non doc-comments
/// assert!(!is_doc_comment(&parse_comment(r#"/** has no line break */"#)));
///
/// assert!(!is_doc_comment(&parse_comment(r#"
/// /*
/// *
/// this line doesn't start with a star
/// */
/// "#)));
/// ```
pub fn is_doc_comment<L: Language>(comment: &SyntaxTriviaPieceComments<L>) -> bool {
if !comment.has_newline() {
return false;
}

let text = comment.text();

text.lines().enumerate().all(|(index, line)| {
if index == 0 {
line.starts_with("/*")
} else {
line.trim_start().starts_with('*')
}
})
}
1 change: 1 addition & 0 deletions crates/rome_formatter_test/src/check_reformat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ where
.language
.format_node(self.options.clone(), &re_parse.syntax())
.unwrap();

let printed = formatted.print().unwrap();

if self.text != printed.as_code() {
Expand Down
62 changes: 1 addition & 61 deletions crates/rome_js_formatter/src/comments.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::prelude::*;
use crate::utils::AnyJsConditional;
use rome_diagnostics_categories::category;
use rome_formatter::comments::is_doc_comment;
use rome_formatter::{
comments::{
CommentKind, CommentPlacement, CommentStyle, CommentTextPosition, Comments,
Expand Down Expand Up @@ -67,67 +68,6 @@ impl FormatRule<SourceComment<JsLanguage>> for FormatJsLeadingComment {
}
}

/// Returns `true` if `comment` is a multi line block comment:
///
/// # Examples
///
/// ```
/// # use rome_js_parser::{JsParserOptions, parse_module};
/// # use rome_js_syntax::JsLanguage;
/// # use rome_rowan::{Direction, SyntaxTriviaPieceComments};
/// use rome_js_formatter::comments::is_doc_comment;
///
/// # fn parse_comment(source: &str) -> SyntaxTriviaPieceComments<JsLanguage> {
/// # let root = parse_module(source, JsParserOptions::default()).tree();
/// # root
/// # .eof_token()
/// # .expect("Root to have an EOF token")
/// # .leading_trivia()
/// # .pieces()
/// # .filter_map(|piece| piece.as_comments())
/// # .next()
/// # .expect("Source to contain a comment.")
/// # }
///
/// assert!(is_doc_comment(&parse_comment(r#"
/// /**
/// * Multiline doc comment
/// */
/// "#)));
///
/// assert!(is_doc_comment(&parse_comment(r#"
/// /*
/// * Single star
/// */
/// "#)));
///
///
/// // Non doc-comments
/// assert!(!is_doc_comment(&parse_comment(r#"/** has no line break */"#)));
///
/// assert!(!is_doc_comment(&parse_comment(r#"
/// /*
/// *
/// this line doesn't start with a star
/// */
/// "#)));
/// ```
pub fn is_doc_comment(comment: &SyntaxTriviaPieceComments<JsLanguage>) -> bool {
if !comment.has_newline() {
return false;
}

let text = comment.text();

text.lines().enumerate().all(|(index, line)| {
if index == 0 {
line.starts_with("/*")
} else {
line.trim_start().starts_with('*')
}
})
}

#[derive(Eq, PartialEq, Copy, Clone, Debug, Default)]
pub struct JsCommentStyle;

Expand Down
2 changes: 1 addition & 1 deletion crates/rome_js_formatter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
//! It helps you to understand which nodes need to be implemented/modified
//! in order to implement formatting. Alternatively, you can locally run the playground by following
//! the [playground instructions](https://github.com/rome/tools/blob/main/website/playground/README.md).
//! 5. Use the [`quick_test()`](https://github.com/rome/tools/blob/main/crates/rome_js_formatter/src/lib.rs#L597-L616)
//! 5. Use the `quick_test.rs` file in `tests/` directory.
//! function to test you snippet straight from your IDE, without running the whole test suite. The test
//! is ignored on purpose, so you won't need to worry about the CI breaking.
//!
Expand Down
1 change: 0 additions & 1 deletion crates/rome_js_formatter/tests/quick_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ fn quick_test() {
syntax,
JsParserOptions::default().with_parse_class_parameter_decorators(),
);
dbg!(tree.syntax());
let options = JsFormatOptions::new(syntax)
.with_semicolons(Semicolons::Always)
.with_quote_style(QuoteStyle::Double)
Expand Down
3 changes: 2 additions & 1 deletion crates/rome_json_formatter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ version = "0.0.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rome_diagnostics = { workspace = true }
rome_formatter = { workspace = true }
rome_json_syntax = { workspace = true }
rome_rowan = { workspace = true }
rome_suppression = { workspace = true }

[dev-dependencies]
countme = { workspace = true, features = ["enable"] }
insta = { workspace = true, features = ["glob"] }
rome_diagnostics = { workspace = true }
rome_formatter_test = { workspace = true }
rome_fs = { workspace = true }
rome_json_factory = { workspace = true }
Expand Down
85 changes: 85 additions & 0 deletions crates/rome_json_formatter/src/comments.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use crate::prelude::*;
use rome_diagnostics::category;
use rome_formatter::comments::{
is_doc_comment, CommentKind, CommentStyle, Comments, SourceComment,
};
use rome_formatter::formatter::Formatter;
use rome_formatter::{write, FormatResult, FormatRule};
use rome_json_syntax::{JsonLanguage, TextLen};
use rome_rowan::SyntaxTriviaPieceComments;
use rome_suppression::parse_suppression_comment;

pub type JsonComments = Comments<JsonLanguage>;

#[derive(Default)]
pub struct FormatJsonLeadingComment;

impl FormatRule<SourceComment<JsonLanguage>> for FormatJsonLeadingComment {
type Context = JsonFormatContext;

fn fmt(
&self,
comment: &SourceComment<JsonLanguage>,
f: &mut Formatter<Self::Context>,
) -> FormatResult<()> {
if is_doc_comment(comment.piece()) {
let mut source_offset = comment.piece().text_range().start();

let mut lines = comment.piece().text().lines();

// SAFETY: Safe, `is_doc_comment` only returns `true` for multiline comments
let first_line = lines.next().unwrap();
write!(f, [dynamic_text(first_line.trim_end(), source_offset)])?;

source_offset += first_line.text_len();

// Indent the remaining lines by one space so that all `*` are aligned.
write!(
f,
[align(
1,
&format_once(|f| {
for line in lines {
write!(
f,
[hard_line_break(), dynamic_text(line.trim(), source_offset)]
)?;

source_offset += line.text_len();
}

Ok(())
})
)]
)
} else {
write!(f, [comment.piece().as_piece()])
}
}
}

#[derive(Eq, PartialEq, Copy, Clone, Debug, Default)]
pub struct JsonCommentStyle;

impl CommentStyle for JsonCommentStyle {
type Language = JsonLanguage;

fn is_suppression(text: &str) -> bool {
parse_suppression_comment(text)
.filter_map(Result::ok)
.flat_map(|suppression| suppression.categories)
.any(|(key, _)| key == category!("format"))
}

fn get_comment_kind(comment: &SyntaxTriviaPieceComments<Self::Language>) -> CommentKind {
if comment.text().starts_with("/*") {
if comment.has_newline() {
CommentKind::Block
} else {
CommentKind::InlineBlock
}
} else {
CommentKind::Line
}
}
}
Loading

0 comments on commit a65c626

Please sign in to comment.