feat: format JS from CST
MODIFY
crates/formatter/Cargo.toml
crates/formatter/Cargo.toml
@@ -7,6 +7,5 @@ edition = "2018"
[dependencies]
rslint_parser = { path = "../rslint_parser" }
-
[dev-dependencies]
tests_macros = { path = "../tests_macros" }

MODIFY
crates/formatter/src/ts/array.rs
crates/formatter/src/ts/array.rs
use crate::{
- format_elements, group_elements, indent, join_elements, space_token, token, FormatElement,
- ToFormatElement,
+ format_elements, group_elements, if_group_breaks, join_elements, soft_indent,
+ soft_line_break_or_space, token, FormatElement, ToFormatElement,
};
use rslint_parser::ast::{ArrayExpr, ExprOrSpread};
impl ToFormatElement for ArrayExpr {
fn to_format_element(&self) -> FormatElement {
- let elements = self.elements();
- let mut tokens = vec![];
+ let tokens = self
+ .elements()
+ // TODO: use context when introduced or .syntax()
+ .map(|element| match element {
+ ExprOrSpread::Expr(expr) => expr.to_format_element(),
+ ExprOrSpread::Spread(spread) => spread.to_format_element(),
+ });
- for element in elements {
- match element {
- ExprOrSpread::Expr(expr) => {
- tokens.push(expr.to_format_element());
- }
- ExprOrSpread::Spread(spread) => {
- tokens.push(spread.to_format_element());
- }
- }
- }
- let separator = format_elements!(token(","), space_token());
- format_elements!(
+ let separator = format_elements!(token(","), soft_line_break_or_space());
+ group_elements(format_elements![
token("["),
- indent(group_elements(join_elements(separator, tokens))),
- token(","),
- token("]"),
- )
+ soft_indent(join_elements(separator, tokens)),
+ if_group_breaks(token(",")),
+ token("]")
+ ])
}
}

MODIFY
crates/formatter/src/ts/arrow_function.rs
crates/formatter/src/ts/arrow_function.rs
-use rslint_parser::ast::{ArrowExpr, ArrowExprParams};
+use rslint_parser::ast::{ArrowExpr, ArrowExprParams, ExprOrBlock};
use crate::{
concat_elements, format_elements, space_token, token, ts::format_syntax_token, FormatElement,
@@ -30,21 +30,18 @@ impl ToFormatElement for ArrowExpr {
tokens.push(space_token());
if let Some(arrow) = self.fat_arrow_token() {
tokens.push(format_syntax_token(arrow));
- } else {
- tokens.push(token("=>"));
}
+
tokens.push(space_token());
let body = self.body();
if let Some(body) = body {
match body {
- rslint_parser::ast::ExprOrBlock::Expr(expression) => {
+ ExprOrBlock::Expr(expression) => {
tokens.push(expression.to_format_element());
}
- rslint_parser::ast::ExprOrBlock::Block(block) => {
- tokens.push(block.to_format_element())
- }
+ ExprOrBlock::Block(block) => tokens.push(block.to_format_element()),
}
}

MODIFY
crates/formatter/src/ts/expressions/sequence_expression.rs
crates/formatter/src/ts/expressions/sequence_expression.rs
@@ -4,10 +4,9 @@ use crate::{concat_elements, FormatElement, ToFormatElement};
impl ToFormatElement for SequenceExpr {
fn to_format_element(&self) -> FormatElement {
- let tokens: Vec<_> = self
- .exprs()
- .map(|expression| expression.to_format_element())
- .collect();
- concat_elements(tokens)
+ concat_elements(
+ self.exprs()
+ .map(|expression| expression.to_format_element()),
+ )
}
}

MODIFY
crates/formatter/src/ts/literal.rs
crates/formatter/src/ts/literal.rs
@@ -9,6 +9,7 @@ impl ToFormatElement for Literal {
.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,
})

MODIFY
crates/formatter/src/ts/mod.rs
crates/formatter/src/ts/mod.rs
@@ -10,8 +10,8 @@ mod literal;
mod name;
mod name_ref;
mod paramter_list;
+mod patterns;
mod script;
-mod single_pattern;
mod spread;
mod statements;
mod var_decl;
@@ -20,20 +20,6 @@ pub fn format_syntax_token(syntax_token: SyntaxToken) -> FormatElement {
format_elements!(token(syntax_token.text().as_str()))
}
-// NOTE: please leave this comment here, it will be removed once this logic will be ported to the proper place
-// TODO: remove once logic is implemented somewhere else
-// let group = GroupToken::new(format_tokens!(
-// "{",
-// FormatToken::indent(format_tokens!(
-// LineToken::soft_or_space(),
-// ListToken::join(LineToken::soft_or_space(), format_nodes(node))
-// )),
-// LineToken::soft_or_space(),
-// "}"
-// ));
-
-// FormatToken::from(group)
-
#[cfg(test)]
mod test {
use rslint_parser::{ast::Script, parse_text, AstNode};
@@ -59,30 +45,30 @@ mod test {
}
#[test]
- #[ignore = "to enable later"]
fn array() {
let src = r#"let users = [ 'john', 'chandler', true ]"#;
- let _tree = parse_text(src, 0);
- // let result = format_token(&tree.format(), FormatOptions::default());
- // assert_eq!(result.code(), r#"let users = ["john", "chandler", true,];"#);
+ let tree = parse_text(src, 0);
+ let child = Script::cast(tree.syntax()).unwrap();
+ let result = format_element(&child.to_format_element(), FormatOptions::default());
+ assert_eq!(result.code(), r#"let users = ["john", "chandler", true];"#);
}
#[test]
- #[ignore = "to enable later"]
fn poc() {
- let src = r#"function foo { let var1 = [true, false]
- let broken = [-, 45, 54]
+ let src = r#"function foo() { let var1 = [true, false]
+ let broken = [ 45, 54]
let var2 = (var1, var2) => {}
}"#;
- let _tree = parse_text(src, 0);
- // let result = format_token(&tree.format(), FormatOptions::default());
- // assert_eq!(
- // result.code(),
- // r#"function foo {
- // let var1 = [true, false,];
- // let broken = [-, 45, 54,];
- // let var2 = (var1, var2) => {};
- // }"#
- // );
+ let tree = parse_text(src, 0);
+ let child = Script::cast(tree.syntax()).unwrap();
+ let result = format_element(&child.to_format_element(), FormatOptions::default());
+ assert_eq!(
+ result.code(),
+ r#"function foo() {
+ let var1 = [true, false];
+ let broken = [45, 54];
+ let var2 = (var1, var2) => {};
+}"#
+ );
}
}

MODIFY
crates/formatter/src/ts/name_ref.rs
crates/formatter/src/ts/name_ref.rs
@@ -4,9 +4,9 @@ use crate::{ts::format_syntax_token, ToFormatElement};
impl ToFormatElement for NameRef {
fn to_format_element(&self) -> crate::FormatElement {
- if let Some(name_ref) = self.ident_token() {
- return format_syntax_token(name_ref);
- }
- panic!("What the hell")
+ format_syntax_token(
+ self.ident_token()
+ .expect("This should not fail. If it fails, there's an error."),
+ )
}
}

MODIFY
crates/formatter/src/ts/paramter_list.rs
crates/formatter/src/ts/paramter_list.rs
@@ -16,7 +16,7 @@ impl ToFormatElement for ParameterList {
.map(|param| match param {
Pattern::SinglePattern(single_pattern) => single_pattern.to_format_element(),
Pattern::RestPattern(_) => todo!(),
- Pattern::AssignPattern(_) => todo!(),
+ Pattern::AssignPattern(assign_pattern) => assign_pattern.to_format_element(),
Pattern::ObjectPattern(_) => todo!(),
Pattern::ArrayPattern(_) => todo!(),
Pattern::ExprPattern(_) => todo!(),

ADD
crates/formatter/src/ts/patterns/assign_pattern.rs
+use crate::{concat_elements, FormatElement, ToFormatElement};
+use rslint_parser::ast::AssignPattern;
+
+impl ToFormatElement for AssignPattern {
+ fn to_format_element(&self) -> FormatElement {
+ let mut tokens = vec![];
+ if let Some(key) = self.key() {
+ tokens.push(key.to_format_element());
+ }
+
+ tokens.push(self.value().expect("No value").to_format_element());
+
+ concat_elements(tokens)
+ }
+}

ADD
crates/formatter/src/ts/patterns/mod.rs
+mod assign_pattern;
+mod pattern;
+mod single_pattern;

ADD
crates/formatter/src/ts/patterns/pattern.rs
+use rslint_parser::ast::Pattern;
+
+use crate::{space_token, ToFormatElement};
+
+impl ToFormatElement for Pattern {
+ fn to_format_element(&self) -> crate::FormatElement {
+ space_token()
+ }
+}

ADD
crates/formatter/src/ts/patterns/single_pattern.rs
+use crate::{FormatElement, ToFormatElement};
+use rslint_parser::ast::SinglePattern;
+
+impl ToFormatElement for SinglePattern {
+ fn to_format_element(&self) -> FormatElement {
+ // TODO: implementation not finished
+ self.name()
+ .expect("Name should always exist")
+ .to_format_element()
+ }
+}

DELETE
crates/formatter/src/ts/single_pattern.rs
-use crate::{concat_elements, FormatElement, ToFormatElement};
-use rslint_parser::ast::SinglePattern;
-
-impl ToFormatElement for SinglePattern {
- fn to_format_element(&self) -> FormatElement {
- let mut tokens = vec![];
- if let Some(name) = self.name() {
- tokens.push(name.to_format_element());
- }
-
- concat_elements(tokens)
- }
-}

MODIFY
crates/formatter/src/ts/spread.rs
crates/formatter/src/ts/spread.rs
@@ -3,8 +3,8 @@ use rslint_parser::ast::SpreadElement;
impl ToFormatElement for SpreadElement {
fn to_format_element(&self) -> FormatElement {
- let dotdotdot_token = self.dotdotdot_token().unwrap();
- let child = self.element().unwrap();
+ let dotdotdot_token = self.dotdotdot_token().expect("Token should always exist");
+ let child = self.element().expect("Token should always exist");
format_elements!(
format_syntax_token(dotdotdot_token),

MODIFY
crates/formatter/src/ts/statements/block.rs
crates/formatter/src/ts/statements/block.rs
use rslint_parser::ast::BlockStmt;
-use crate::{format_elements, space_token, token, FormatElement, ToFormatElement};
+use crate::{
+ format_elements, group_elements, join_elements, soft_indent, soft_line_break_or_space, token,
+ FormatElement, ToFormatElement,
+};
impl ToFormatElement for BlockStmt {
fn to_format_element(&self) -> FormatElement {
- let body: Vec<_> = self.stmts().map(|stmt| stmt.to_format_element()).collect();
-
- format_elements![
+ group_elements(format_elements![
token("{"),
- space_token(),
- concat_elements(body),
- space_token(),
+ soft_indent(join_elements(
+ soft_line_break_or_space(),
+ self.stmts().map(|stmt| stmt.to_format_element())
+ )),
token("}")
- ]
+ ])
}
}

MODIFY
crates/formatter/src/ts/statements/statement.rs
crates/formatter/src/ts/statements/statement.rs
@@ -22,7 +22,7 @@ impl ToFormatElement for Stmt {
Stmt::ThrowStmt(_) => todo!(),
Stmt::TryStmt(_) => todo!(),
Stmt::DebuggerStmt(_) => todo!(),
- Stmt::Decl(_) => todo!(),
+ Stmt::Decl(decl) => decl.to_format_element(),
}
}
}

feat: format JS from CST (#1697)