refactor(formatter): Add `format_token` method to `Formatter`
We probably want to implement some specific formatting for some token types (e.g. strings). Moving the formatting of `token`s to the context and dispatching it through `SyntaxToken` will help to add more special casing in the future (similar to `format_node`).
MODIFY
crates/formatter/src/cst.rs
crates/formatter/src/cst.rs
@@ -3,32 +3,7 @@ use rslint_parser::ast::{
ArrayExpr, ArrowExpr, AssignPattern, BlockStmt, Declarator, ExprStmt, FnDecl, Literal, Name,
NameRef, ParameterList, ReturnStmt, Script, SequenceExpr, SinglePattern, VarDecl,
};
-use rslint_parser::{AstNode, SyntaxKind, SyntaxNode, SyntaxToken};
-
-/// Creates a format token representing the exact same text as the syntax token
-///
-/// # Examples
-///
-/// ```
-///
-/// use rome_formatter::{FormatOptions, syntax_token, format_element};
-/// use rslint_parser::{SyntaxNode, T};
-/// use rslint_rowan::{GreenNode, GreenToken, SmolStr, SyntaxKind, NodeOrToken};
-///
-/// let node = SyntaxNode::new_root(
-/// GreenNode::new(SyntaxKind(1), vec![
-/// NodeOrToken::Token(GreenToken::new(SyntaxKind(T![=>].into()), SmolStr::new("=>")))
-/// ])
-/// );
-///
-/// let token = node.first_token().unwrap();
-/// let element = syntax_token(&token);
-///
-/// assert_eq!("=>", format_element(&element, FormatOptions::default()).code())
-/// ```
-pub fn syntax_token(syntax_token: &SyntaxToken) -> FormatElement {
- token(syntax_token.text().as_str())
-}
+use rslint_parser::{AstNode, AstToken, SyntaxKind, SyntaxNode, SyntaxToken};
impl ToFormatElement for SyntaxNode {
fn to_format_element(&self, formatter: &Formatter) -> FormatElement {
@@ -91,3 +66,14 @@ impl ToFormatElement for SyntaxNode {
}
}
}
+
+impl ToFormatElement for SyntaxToken {
+ fn to_format_element(&self, formatter: &Formatter) -> FormatElement {
+ match self.kind() {
+ SyntaxKind::STRING => rslint_parser::ast::String::cast(self.clone())
+ .unwrap()
+ .to_format_element(formatter),
+ _ => token(self.text().as_str()),
+ }
+ }
+}

MODIFY
crates/formatter/src/formatter.rs
crates/formatter/src/formatter.rs
use crate::printer::Printer;
use crate::{concat_elements, FormatElement, FormatOptions, FormatResult, ToFormatElement};
-use rslint_parser::{AstNode, SyntaxNode};
+use rslint_parser::{AstNode, SyntaxNode, SyntaxToken};
/// Handles the formatting of a CST and stores the options how the CST should be formatted (user preferences).
/// The formatter is passed to the [ToFormatElement] implementation of every node in the CST so that they
@@ -56,4 +56,31 @@ impl Formatter {
// TODO: Sets the marker for the end source map location, add trailing comments, ...
concat_elements(vec![])
}
+
+ /// Formats the passed in token
+ ///
+ /// # Examples
+ ///
+ /// ```
+ ///
+ /// use rome_formatter::{Formatter, token};
+ /// use rslint_parser::{SyntaxNode, T, SyntaxToken};
+ /// use rslint_rowan::{GreenNode, GreenToken, SmolStr, NodeOrToken, SyntaxKind};
+ ///
+ /// let node = SyntaxNode::new_root(
+ /// GreenNode::new(SyntaxKind(1), vec![
+ /// NodeOrToken::Token(GreenToken::new(SyntaxKind(T![=>].into()), SmolStr::new("=>")))
+ /// ])
+ /// );
+ ///
+ /// let syntax_token = node.first_token().unwrap();
+ ///
+ /// let formatter = Formatter::default();
+ /// let result = formatter.format_token(&syntax_token);
+ ///
+ /// assert_eq!(token("=>"), result)
+ /// ```
+ pub fn format_token(&self, syntax_token: &SyntaxToken) -> FormatElement {
+ syntax_token.to_format_element(self)
+ }
}

MODIFY
crates/formatter/src/lib.rs
crates/formatter/src/lib.rs
@@ -55,7 +55,6 @@ use crate::format_json::tokenize_json;
pub use formatter::Formatter;
use core::file_handlers::Language;
-pub use cst::syntax_token;
pub use format_element::{
concat_elements, group_elements, hard_line_break, if_group_breaks,
if_group_fits_on_single_line, indent, join_elements, soft_indent, soft_line_break,

MODIFY
crates/formatter/src/ts/declarators/declarator.rs
crates/formatter/src/ts/declarators/declarator.rs
-use crate::{
- concat_elements, space_token, syntax_token, token, FormatElement, Formatter, ToFormatElement,
-};
+use crate::{concat_elements, space_token, token, FormatElement, Formatter, ToFormatElement};
use rslint_parser::ast::Declarator;
impl ToFormatElement for Declarator {
@@ -12,7 +10,7 @@ impl ToFormatElement for Declarator {
}
if let Some(equal) = self.eq_token() {
tokens.push(space_token());
- tokens.push(syntax_token(&equal));
+ tokens.push(formatter.format_token(&equal));
tokens.push(space_token());
}

MODIFY
crates/formatter/src/ts/declarators/fn_decl.rs
crates/formatter/src/ts/declarators/fn_decl.rs
-use crate::{
- concat_elements, space_token, syntax_token, FormatElement, Formatter, ToFormatElement,
-};
+use crate::{concat_elements, space_token, FormatElement, Formatter, ToFormatElement};
use rslint_parser::ast::FnDecl;
impl ToFormatElement for FnDecl {
@@ -8,16 +6,16 @@ impl ToFormatElement for FnDecl {
let mut tokens = vec![];
if let Some(token) = self.async_token() {
- tokens.push(syntax_token(&token));
+ tokens.push(formatter.format_token(&token));
tokens.push(space_token());
}
if let Some(token) = self.function_token() {
- tokens.push(syntax_token(&token));
+ tokens.push(formatter.format_token(&token));
}
if let Some(token) = self.star_token() {
- tokens.push(syntax_token(&token));
+ tokens.push(formatter.format_token(&token));
}
tokens.push(space_token());

MODIFY
crates/formatter/src/ts/declarators/var_decl.rs
crates/formatter/src/ts/declarators/var_decl.rs
-use crate::{
- concat_elements, space_token, syntax_token, token, FormatElement, Formatter, ToFormatElement,
-};
+use crate::{concat_elements, space_token, token, FormatElement, Formatter, ToFormatElement};
use rslint_parser::ast::VarDecl;
impl ToFormatElement for VarDecl {
@@ -8,11 +6,11 @@ impl ToFormatElement for VarDecl {
let mut tokens = vec![];
if let Some(token) = self.const_token() {
- tokens.push(syntax_token(&token));
+ tokens.push(formatter.format_token(&token));
} else if let Some(token) = self.let_token() {
- tokens.push(syntax_token(&token));
+ tokens.push(formatter.format_token(&token));
} else if let Some(token) = self.var_token() {
- tokens.push(syntax_token(&token));
+ tokens.push(formatter.format_token(&token));
} else {
// TODO: Diagnostic?
tokens.push(token("var"));

MODIFY
crates/formatter/src/ts/expressions/arrow_expr.rs
crates/formatter/src/ts/expressions/arrow_expr.rs
use rslint_parser::ast::{ArrowExpr, ArrowExprParams};
use crate::{
- concat_elements, format_elements, space_token, syntax_token, token, FormatElement, Formatter,
- ToFormatElement,
+ concat_elements, format_elements, space_token, token, FormatElement, Formatter, ToFormatElement,
};
impl ToFormatElement for ArrowExpr {
@@ -10,7 +9,10 @@ impl ToFormatElement for ArrowExpr {
let mut tokens: Vec<FormatElement> = vec![];
if let Some(async_token) = self.async_token() {
- tokens.push(format_elements!(syntax_token(&async_token), space_token()));
+ tokens.push(format_elements!(
+ formatter.format_token(&async_token),
+ space_token()
+ ));
}
if let Some(arrow_expression_params) = self.params() {
@@ -28,7 +30,7 @@ impl ToFormatElement for ArrowExpr {
tokens.push(space_token());
if let Some(arrow) = self.fat_arrow_token() {
- tokens.push(syntax_token(&arrow));
+ tokens.push(formatter.format_token(&arrow));
}
tokens.push(space_token());

MODIFY
crates/formatter/src/ts/expressions/literal.rs
crates/formatter/src/ts/expressions/literal.rs
use rslint_parser::ast::Literal;
-use crate::{token, FormatElement, Formatter, ToFormatElement};
+use crate::{FormatElement, Formatter, ToFormatElement};
impl ToFormatElement for Literal {
- fn to_format_element(&self, _formatter: &Formatter) -> FormatElement {
- let new_string: String = self
- .to_string()
- .as_str()
- .chars()
- .map(|ch| match ch {
- // TODO: this is the final solution and will need to find a clever way to do replacing
- '\'' => '"',
- _ => ch,
- })
- .collect();
- token(new_string.as_str())
+ fn to_format_element(&self, formatter: &Formatter) -> FormatElement {
+ formatter.format_token(&self.token())
}
}

MODIFY
crates/formatter/src/ts/expressions/name_ref.rs
crates/formatter/src/ts/expressions/name_ref.rs
use rslint_parser::ast::NameRef;
-use crate::{syntax_token, Formatter, ToFormatElement};
+use crate::{Formatter, ToFormatElement};
impl ToFormatElement for NameRef {
- fn to_format_element(&self, _formatter: &Formatter) -> crate::FormatElement {
- syntax_token(
+ fn to_format_element(&self, formatter: &Formatter) -> crate::FormatElement {
+ formatter.format_token(
&self
.ident_token()
.expect("This should not fail. If it fails, there's an error."),

MODIFY
crates/formatter/src/ts/mod.rs
crates/formatter/src/ts/mod.rs
@@ -8,6 +8,7 @@ mod patterns;
mod script;
mod spread;
mod statements;
+mod tokens;
#[cfg(test)]
mod test {

MODIFY
crates/formatter/src/ts/name.rs
crates/formatter/src/ts/name.rs
-use crate::{syntax_token, FormatElement, Formatter, ToFormatElement};
+use crate::{FormatElement, Formatter, ToFormatElement};
use rslint_parser::ast::Name;
impl ToFormatElement for Name {
- fn to_format_element(&self, _formatter: &Formatter) -> FormatElement {
- syntax_token(&self.ident_token().unwrap())
+ fn to_format_element(&self, formatter: &Formatter) -> FormatElement {
+ formatter.format_token(&self.ident_token().unwrap())
}
}

MODIFY
crates/formatter/src/ts/parameter_list.rs
crates/formatter/src/ts/parameter_list.rs
use crate::{
- concat_elements, format_elements, join_elements, space_token, syntax_token, token,
- FormatElement, Formatter, ToFormatElement,
+ concat_elements, format_elements, join_elements, space_token, token, FormatElement, Formatter,
+ ToFormatElement,
};
use rslint_parser::ast::ParameterList;
@@ -8,7 +8,7 @@ impl ToFormatElement for ParameterList {
fn to_format_element(&self, formatter: &Formatter) -> FormatElement {
let mut elements = vec![];
if let Some(paren) = self.l_paren_token() {
- elements.push(syntax_token(&paren))
+ elements.push(formatter.format_token(&paren))
}
let param_tokens = self.parameters().map(|param| formatter.format_node(param));
@@ -19,7 +19,7 @@ impl ToFormatElement for ParameterList {
)));
if let Some(paren) = self.r_paren_token() {
- elements.push(syntax_token(&paren));
+ elements.push(formatter.format_token(&paren));
}
concat_elements(elements)

MODIFY
crates/formatter/src/ts/script.rs
crates/formatter/src/ts/script.rs
-use crate::{
- concat_elements, hard_line_break, syntax_token, FormatElement, Formatter, ToFormatElement,
-};
+use crate::{concat_elements, hard_line_break, FormatElement, Formatter, ToFormatElement};
use rslint_parser::ast::Script;
impl ToFormatElement for Script {
@@ -8,7 +6,7 @@ impl ToFormatElement for Script {
let mut tokens = vec![];
if let Some(shebang) = self.shebang_token() {
- tokens.push(syntax_token(&shebang));
+ tokens.push(formatter.format_token(&shebang));
tokens.push(hard_line_break());
}

ADD
crates/formatter/src/ts/tokens/mod.rs
+mod string_token;

ADD
crates/formatter/src/ts/tokens/string_token.rs
+use crate::{token, FormatElement, Formatter, ToFormatElement};
+use rslint_parser::ast::String as JsString;
+
+impl ToFormatElement for JsString {
+ fn to_format_element(&self, _formatter: &Formatter) -> FormatElement {
+ let mut content = self.to_string();
+
+ // uses single quotes
+ if content.starts_with('\'') {
+ content.replace_range(0..1, "\"");
+ content.replace_range(content.len() - 1..content.len(), "\"");
+ }
+
+ token(content.as_str())
+ }
+}

refactor(formatter): Add `format_token` method to `Formatter` (#1699)

We probably want to implement some specific formatting for some token types (e.g. strings). Moving the formatting of `token`s to the context and dispatching it through `SyntaxToken` will help to add more special casing in the future (similar to `format_node`).