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

Commit

Permalink
feat(rome_js_formatter): Indent Doc comments (#3129)
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaReiser authored Aug 30, 2022
1 parent 575b4d9 commit b08b5e2
Show file tree
Hide file tree
Showing 23 changed files with 353 additions and 653 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ jobs:
- name: Build TypeScript code
run: |
pnpm --prefix npm/backend-jsonrpc i
pnpm --prefix npm/backend-jsonrpc run build
pnpm --prefix npm/backend-jsonrpc run build
pnpm --prefix npm/rome run build:wasm-node
pnpm --prefix npm/rome i
pnpm --prefix npm/rome run build
Expand Down Expand Up @@ -175,7 +175,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: codegen-schema
- name: Run the schema codegen
- name: Run the bindings codegen
uses: actions-rs/cargo@v1
with:
command: codegen-bindings
Expand All @@ -188,4 +188,4 @@ jobs:
if [[ `git status --porcelain` ]]; then
git status
exit 1
fi
fi
3 changes: 3 additions & 0 deletions crates/rome_formatter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ pub trait CstFormatContext: FormatContext {
type Language: Language;
type Style: CommentStyle<Self::Language>;

/// Rule for formatting leading comments.
type LeadingCommentRule: FormatRule<SourceComment<Self::Language>, Context = Self> + Default;

/// Customizes how comments are formatted
#[deprecated(note = "Prefer FormatLanguage::comment_style")]
fn comment_style(&self) -> Self::Style;
Expand Down
10 changes: 7 additions & 3 deletions crates/rome_formatter/src/token.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::comments::CommentStyle;
use crate::prelude::*;
use crate::{
format_args, write, Argument, Arguments, CommentKind, CstFormatContext, GroupId, LastTokenKind,
SourceComment,
format_args, write, Argument, Arguments, CommentKind, CstFormatContext, FormatRefWithRule,
GroupId, LastTokenKind, SourceComment,
};
use rome_rowan::{Language, SyntaxToken, SyntaxTriviaPiece};

Expand Down Expand Up @@ -682,6 +682,7 @@ where
.context()
.comment_style()
.get_comment_kind(comment.piece());

last_inline_comment = comment_kind.is_inline() && lines_after == 0;

let format_content = format_with(|f| {
Expand All @@ -691,7 +692,10 @@ where
write!(f, [space()])?;
};

write!(f, [comment.piece()])?;
let format_comment =
FormatRefWithRule::new(comment, C::LeadingCommentRule::default());

write!(f, [format_comment])?;

match comment_kind {
CommentKind::Line => match lines_after {
Expand Down
160 changes: 160 additions & 0 deletions crates/rome_js_formatter/src/comments.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
use crate::prelude::*;
use rome_formatter::write;
use rome_formatter::{CommentKind, CommentStyle, SourceComment};
use rome_js_syntax::suppression::{parse_suppression_comment, SuppressionCategory};
use rome_js_syntax::{JsLanguage, JsSyntaxKind};
use rome_rowan::{SyntaxTriviaPieceComments, TextLen};

#[derive(Default)]
pub struct FormatJsLeadingComment;

impl FormatRule<SourceComment<JsLanguage>> for FormatJsLeadingComment {
type Context = JsFormatContext;

fn fmt(
&self,
comment: &SourceComment<JsLanguage>,
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()])
}
}
}

/// Returns `true` if `comment` is a multi line block comment:
///
/// # Examples
///
/// ```
/// # use rome_js_parser::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, 0).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;

impl CommentStyle<JsLanguage> for JsCommentStyle {
fn is_suppression(&self, text: &str) -> bool {
parse_suppression_comment(text)
.flat_map(|suppression| suppression.categories)
.any(|(category, _)| category == SuppressionCategory::Format)
}

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

fn is_group_start_token(&self, kind: JsSyntaxKind) -> bool {
matches!(
kind,
JsSyntaxKind::L_PAREN
| JsSyntaxKind::L_BRACK
| JsSyntaxKind::L_CURLY
| JsSyntaxKind::DOLLAR_CURLY
)
}

fn is_group_end_token(&self, kind: JsSyntaxKind) -> bool {
matches!(
kind,
JsSyntaxKind::R_BRACK
| JsSyntaxKind::R_CURLY
| JsSyntaxKind::R_PAREN
| JsSyntaxKind::COMMA
| JsSyntaxKind::SEMICOLON
| JsSyntaxKind::DOT
| JsSyntaxKind::EOF
)
}
}
56 changes: 5 additions & 51 deletions crates/rome_js_formatter/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use crate::comments::{FormatJsLeadingComment, JsCommentStyle};
use rome_formatter::printer::PrinterOptions;
use rome_formatter::{
CommentKind, CommentStyle, Comments, CstFormatContext, FormatContext, FormatOptions,
IndentStyle, LineWidth, TransformSourceMap,
Comments, CstFormatContext, FormatContext, FormatOptions, IndentStyle, LineWidth,
TransformSourceMap,
};
use rome_js_syntax::suppression::{parse_suppression_comment, SuppressionCategory};
use rome_js_syntax::{JsLanguage, JsSyntaxKind, SourceType};
use rome_rowan::SyntaxTriviaPieceComments;
use rome_js_syntax::{JsLanguage, SourceType};
use std::fmt;
use std::fmt::Debug;
use std::rc::Rc;
Expand Down Expand Up @@ -66,6 +65,7 @@ impl FormatContext for JsFormatContext {
impl CstFormatContext for JsFormatContext {
type Language = JsLanguage;
type Style = JsCommentStyle;
type LeadingCommentRule = FormatJsLeadingComment;

fn comment_style(&self) -> Self::Style {
JsCommentStyle
Expand Down Expand Up @@ -172,52 +172,6 @@ impl fmt::Display for JsFormatOptions {
}
}

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

impl CommentStyle<JsLanguage> for JsCommentStyle {
fn is_suppression(&self, text: &str) -> bool {
parse_suppression_comment(text)
.flat_map(|suppression| suppression.categories)
.any(|(category, _)| category == SuppressionCategory::Format)
}

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

fn is_group_start_token(&self, kind: JsSyntaxKind) -> bool {
matches!(
kind,
JsSyntaxKind::L_PAREN
| JsSyntaxKind::L_BRACK
| JsSyntaxKind::L_CURLY
| JsSyntaxKind::DOLLAR_CURLY
)
}

fn is_group_end_token(&self, kind: JsSyntaxKind) -> bool {
matches!(
kind,
JsSyntaxKind::R_BRACK
| JsSyntaxKind::R_CURLY
| JsSyntaxKind::R_PAREN
| JsSyntaxKind::COMMA
| JsSyntaxKind::SEMICOLON
| JsSyntaxKind::DOT
| JsSyntaxKind::EOF
)
}
}

#[derive(Debug, Eq, PartialEq, Clone, Copy)]
#[cfg_attr(
feature = "serde",
Expand Down
4 changes: 3 additions & 1 deletion crates/rome_js_formatter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ mod check_reformat;
#[rustfmt::skip]
mod generated;
pub(crate) mod builders;
pub mod comments;
pub mod context;
mod parentheses;
pub(crate) mod separated;
Expand All @@ -271,7 +272,8 @@ use rome_rowan::TextRange;
use rome_rowan::{AstNode, SyntaxNode};

use crate::builders::{format_parenthesize, format_suppressed_node};
use crate::context::{JsCommentStyle, JsFormatContext, JsFormatOptions};
use crate::comments::JsCommentStyle;
use crate::context::{JsFormatContext, JsFormatOptions};
use crate::cst::FormatJsSyntaxNode;
use crate::syntax_rewriter::transform;
use std::iter::FusedIterator;
Expand Down

This file was deleted.

Loading

0 comments on commit b08b5e2

Please sign in to comment.