refactor(rome_js_formatter): Extract `JsAnyFunction` formatter into `FormatFunction`
MODIFY
crates/rome_js_formatter/src/js/any/function.rs
crates/rome_js_formatter/src/js/any/function.rs
-use crate::prelude::*;
-use crate::utils::is_simple_expression;
-use rome_formatter::{format_args, write};
-use rome_js_syntax::{
- JsAnyArrowFunctionParameters, JsAnyExpression, JsAnyFunction, JsAnyFunctionBody,
-};
+//! Generated file, do not edit by hand, see `xtask/codegen`
+use crate::prelude::*;
+use rome_js_syntax::JsAnyFunction;
#[derive(Debug, Clone, Default)]
pub struct FormatJsAnyFunction;
-
impl FormatRule<JsAnyFunction> for FormatJsAnyFunction {
type Context = JsFormatContext;
-
fn fmt(&self, node: &JsAnyFunction, f: &mut JsFormatter) -> FormatResult<()> {
- if let Some(async_token) = node.async_token() {
- write!(f, [async_token.format(), space()])?;
- }
-
- write!(
- f,
- [node.function_token().format(), node.star_token().format()]
- )?;
-
- if !matches!(node, JsAnyFunction::JsArrowFunctionExpression(_)) {
- match node.id()? {
- Some(id) => {
- write!(f, [space(), id.format()])?;
- }
- None => {
- write!(f, [space()])?;
- }
- }
+ match node {
+ JsAnyFunction::JsFunctionExpression(node) => node.format().fmt(f),
+ JsAnyFunction::JsFunctionDeclaration(node) => node.format().fmt(f),
+ JsAnyFunction::JsArrowFunctionExpression(node) => node.format().fmt(f),
+ JsAnyFunction::JsFunctionExportDefaultDeclaration(node) => node.format().fmt(f),
}
-
- write!(f, [node.type_parameters().format()])?;
-
- match node.parameters()? {
- JsAnyArrowFunctionParameters::JsAnyBinding(binding) => write!(
- f,
- [format_parenthesize(
- binding.syntax().first_token().as_ref(),
- &format_args![binding.format(), if_group_breaks(&text(",")),],
- binding.syntax().last_token().as_ref(),
- )
- .grouped_with_soft_block_indent()]
- )?,
- JsAnyArrowFunctionParameters::JsParameters(params) => write![f, [params.format()]]?,
- }
-
- write![f, [node.return_type_annotation().format(), space()]]?;
-
- // We create a new group for everything after the parameters. That way if the parameters
- // get broken, we don't line break the arrow and the body if they can fit on the same line.
- // For instance:
- //
- // (
- // a = [abcdefghijklmnopqrstuvwxyz123456789],
- // b = [abcdefghijklmnopqrstuvwxyz123456789],
- // ) =>
- // a + b
- //
- // The line break for `a + b` is not necessary
- //
- if let JsAnyFunction::JsArrowFunctionExpression(arrow) = node {
- write![f, [arrow.fat_arrow_token().format(), space()]]?;
- }
-
- let body = node.body()?;
- // With arrays, arrow functions and objects, they have a natural line breaking strategy:
- // Arrays and objects become blocks:
- //
- // [
- // 100000,
- // 200000,
- // 300000
- // ]
- //
- // Arrow functions get line broken after the `=>`:
- //
- // (foo) => (bar) =>
- // (foo + bar) * (foo + bar)
- //
- // Therefore if our body is an arrow function, array, or object, we
- // do not have a soft line break after the arrow because the body is
- // going to get broken anyways.
- //
- // TODO: Explore the concept of hierarchical line breaking
- // or vertical stacking for arrow functions
- let body_has_soft_line_break = match body {
- JsAnyFunctionBody::JsFunctionBody(_) => true,
- JsAnyFunctionBody::JsAnyExpression(expr) => match expr {
- JsAnyExpression::JsArrowFunctionExpression(_) => true,
- JsAnyExpression::JsParenthesizedExpression(_) => true,
- JsAnyExpression::JsxTagExpression(_) => true,
- expr => is_simple_expression(&expr)?,
- },
- };
-
- if body_has_soft_line_break {
- write![f, [node.body().format()]]?;
- } else {
- write!(
- f,
- [group(&soft_line_indent_or_space(&node.body().format()))]
- )?;
- }
-
- Ok(())
}
}

MODIFY
crates/rome_js_formatter/src/js/declarations/function_declaration.rs
crates/rome_js_formatter/src/js/declarations/function_declaration.rs
use crate::prelude::*;
use rome_formatter::write;
-use rome_js_syntax::{JsAnyFunction, JsFunctionDeclaration};
+use rome_js_syntax::{
+ JsAnyBinding, JsFunctionBody, JsFunctionDeclaration, JsFunctionExportDefaultDeclaration,
+ JsFunctionExpression, JsParameters, JsSyntaxToken, TsReturnTypeAnnotation, TsTypeParameters,
+};
+use rome_rowan::{declare_node_union, SyntaxResult};
#[derive(Debug, Clone, Default)]
pub struct FormatJsFunctionDeclaration;
impl FormatNodeRule<JsFunctionDeclaration> for FormatJsFunctionDeclaration {
fn fmt_fields(&self, node: &JsFunctionDeclaration, f: &mut JsFormatter) -> FormatResult<()> {
- write![f, [JsAnyFunction::from(node.clone()).format()]]
+ write![f, [FormatFunction::from(node.clone())]]
+ }
+}
+
+declare_node_union! {
+ pub(crate) FormatFunction = JsFunctionDeclaration | JsFunctionExpression | JsFunctionExportDefaultDeclaration
+}
+
+impl FormatFunction {
+ fn async_token(&self) -> Option<JsSyntaxToken> {
+ match self {
+ FormatFunction::JsFunctionDeclaration(declaration) => declaration.async_token(),
+ FormatFunction::JsFunctionExpression(expression) => expression.async_token(),
+ FormatFunction::JsFunctionExportDefaultDeclaration(declaration) => {
+ declaration.async_token()
+ }
+ }
+ }
+
+ fn function_token(&self) -> SyntaxResult<JsSyntaxToken> {
+ match self {
+ FormatFunction::JsFunctionDeclaration(declaration) => declaration.function_token(),
+ FormatFunction::JsFunctionExpression(expression) => expression.function_token(),
+ FormatFunction::JsFunctionExportDefaultDeclaration(declaration) => {
+ declaration.function_token()
+ }
+ }
+ }
+
+ fn star_token(&self) -> Option<JsSyntaxToken> {
+ match self {
+ FormatFunction::JsFunctionDeclaration(declaration) => declaration.star_token(),
+ FormatFunction::JsFunctionExpression(expression) => expression.star_token(),
+ FormatFunction::JsFunctionExportDefaultDeclaration(declaration) => {
+ declaration.star_token()
+ }
+ }
+ }
+
+ fn id(&self) -> SyntaxResult<Option<JsAnyBinding>> {
+ match self {
+ FormatFunction::JsFunctionDeclaration(declaration) => declaration.id().map(Some),
+ FormatFunction::JsFunctionExpression(expression) => Ok(expression.id()),
+ FormatFunction::JsFunctionExportDefaultDeclaration(declaration) => Ok(declaration.id()),
+ }
+ }
+
+ fn type_parameters(&self) -> Option<TsTypeParameters> {
+ match self {
+ FormatFunction::JsFunctionDeclaration(declaration) => declaration.type_parameters(),
+ FormatFunction::JsFunctionExpression(expression) => expression.type_parameters(),
+ FormatFunction::JsFunctionExportDefaultDeclaration(declaration) => {
+ declaration.type_parameters()
+ }
+ }
+ }
+
+ fn parameters(&self) -> SyntaxResult<JsParameters> {
+ match self {
+ FormatFunction::JsFunctionDeclaration(declaration) => declaration.parameters(),
+ FormatFunction::JsFunctionExpression(expression) => expression.parameters(),
+ FormatFunction::JsFunctionExportDefaultDeclaration(declaration) => {
+ declaration.parameters()
+ }
+ }
+ }
+
+ fn return_type_annotation(&self) -> Option<TsReturnTypeAnnotation> {
+ match self {
+ FormatFunction::JsFunctionDeclaration(declaration) => {
+ declaration.return_type_annotation()
+ }
+ FormatFunction::JsFunctionExpression(expression) => expression.return_type_annotation(),
+ FormatFunction::JsFunctionExportDefaultDeclaration(declaration) => {
+ declaration.return_type_annotation()
+ }
+ }
+ }
+
+ fn body(&self) -> SyntaxResult<JsFunctionBody> {
+ match self {
+ FormatFunction::JsFunctionDeclaration(declaration) => declaration.body(),
+ FormatFunction::JsFunctionExpression(expression) => expression.body(),
+ FormatFunction::JsFunctionExportDefaultDeclaration(declaration) => declaration.body(),
+ }
+ }
+}
+
+impl Format<JsFormatContext> for FormatFunction {
+ fn fmt(&self, f: &mut JsFormatter) -> FormatResult<()> {
+ if let Some(async_token) = self.async_token() {
+ write!(f, [async_token.format(), space()])?;
+ }
+
+ write!(
+ f,
+ [self.function_token().format(), self.star_token().format()]
+ )?;
+
+ match self.id()? {
+ Some(id) => {
+ write!(f, [space(), id.format()])?;
+ }
+ None => {
+ write!(f, [space()])?;
+ }
+ }
+
+ write!(f, [self.type_parameters().format()])?;
+
+ write!(
+ f,
+ [group(&format_with(|f| {
+ write![
+ f,
+ [
+ self.parameters().format(),
+ self.return_type_annotation().format(),
+ space()
+ ]
+ ]
+ }))]
+ )?;
+
+ write!(f, [self.body().format()])
}
}

MODIFY
crates/rome_js_formatter/src/js/declarations/function_export_default_declaration.rs
crates/rome_js_formatter/src/js/declarations/function_export_default_declaration.rs
use crate::prelude::*;
use rome_formatter::write;
-use rome_js_syntax::JsAnyFunction;
+use crate::js::declarations::function_declaration::FormatFunction;
use rome_js_syntax::JsFunctionExportDefaultDeclaration;
#[derive(Debug, Clone, Default)]
@@ -15,6 +15,6 @@ impl FormatNodeRule<JsFunctionExportDefaultDeclaration>
node: &JsFunctionExportDefaultDeclaration,
f: &mut JsFormatter,
) -> FormatResult<()> {
- write![f, [JsAnyFunction::from(node.clone()).format()]]
+ write![f, [FormatFunction::from(node.clone())]]
}
}

MODIFY
crates/rome_js_formatter/src/js/expressions/arrow_function_expression.rs
crates/rome_js_formatter/src/js/expressions/arrow_function_expression.rs
use crate::prelude::*;
-use rome_formatter::write;
+use rome_formatter::{format_args, write};
-use rome_js_syntax::{JsAnyFunction, JsArrowFunctionExpression};
+use crate::utils::is_simple_expression;
+use rome_js_syntax::{
+ JsAnyArrowFunctionParameters, JsAnyExpression, JsAnyFunctionBody, JsArrowFunctionExpression,
+ JsArrowFunctionExpressionFields,
+};
#[derive(Debug, Clone, Default)]
pub struct FormatJsArrowFunctionExpression;
@@ -12,6 +16,84 @@ impl FormatNodeRule<JsArrowFunctionExpression> for FormatJsArrowFunctionExpressi
node: &JsArrowFunctionExpression,
f: &mut JsFormatter,
) -> FormatResult<()> {
- write![f, [JsAnyFunction::from(node.clone()).format()]]
+ use self::JsAnyExpression::*;
+ use JsAnyFunctionBody::*;
+
+ let JsArrowFunctionExpressionFields {
+ async_token,
+ type_parameters,
+ parameters,
+ return_type_annotation,
+ fat_arrow_token,
+ body,
+ } = node.as_fields();
+
+ if let Some(async_token) = async_token {
+ write!(f, [async_token.format(), space()])?;
+ }
+
+ write!(f, [type_parameters.format()])?;
+
+ match parameters? {
+ JsAnyArrowFunctionParameters::JsAnyBinding(binding) => write!(
+ f,
+ [format_parenthesize(
+ binding.syntax().first_token().as_ref(),
+ &format_args![binding.format(), if_group_breaks(&text(",")),],
+ binding.syntax().last_token().as_ref(),
+ )
+ .grouped_with_soft_block_indent()]
+ )?,
+ JsAnyArrowFunctionParameters::JsParameters(params) => write![f, [params.format()]]?,
+ }
+
+ write![
+ f,
+ [
+ return_type_annotation.format(),
+ space(),
+ fat_arrow_token.format(),
+ space()
+ ]
+ ]?;
+
+ let body = body?;
+
+ // With arrays, arrow selfs and objects, they have a natural line breaking strategy:
+ // Arrays and objects become blocks:
+ //
+ // [
+ // 100000,
+ // 200000,
+ // 300000
+ // ]
+ //
+ // Arrow selfs get line broken after the `=>`:
+ //
+ // (foo) => (bar) =>
+ // (foo + bar) * (foo + bar)
+ //
+ // Therefore if our body is an arrow self, array, or object, we
+ // do not have a soft line break after the arrow because the body is
+ // going to get broken anyways.
+ // TODO: Explore the concept of hierarchical line breaking
+ // or vertical stacking for arrow selfs
+ let body_has_soft_line_break = match &body {
+ JsFunctionBody(_) => true,
+ JsAnyExpression(expr) => match expr {
+ JsArrowFunctionExpression(_)
+ | JsArrayExpression(_)
+ | JsObjectExpression(_)
+ | JsxTagExpression(_) => true,
+ JsParenthesizedExpression(_) => true,
+ expr => is_simple_expression(expr)?,
+ },
+ };
+
+ if body_has_soft_line_break {
+ write![f, [body.format()]]
+ } else {
+ write!(f, [group(&soft_line_indent_or_space(&body.format()))])
+ }
}
}

MODIFY
crates/rome_js_formatter/src/js/expressions/function_expression.rs
crates/rome_js_formatter/src/js/expressions/function_expression.rs
use crate::prelude::*;
+use crate::js::declarations::function_declaration::FormatFunction;
use rome_formatter::write;
-use rome_js_syntax::{JsAnyFunction, JsFunctionExpression};
+use rome_js_syntax::JsFunctionExpression;
#[derive(Debug, Clone, Default)]
pub struct FormatJsFunctionExpression;
impl FormatNodeRule<JsFunctionExpression> for FormatJsFunctionExpression {
fn fmt_fields(&self, node: &JsFunctionExpression, f: &mut JsFormatter) -> FormatResult<()> {
- write![f, [JsAnyFunction::from(node.clone()).format()]]
+ write![f, [FormatFunction::from(node.clone())]]
}
}

MODIFY
xtask/codegen/src/formatter.rs
xtask/codegen/src/formatter.rs
@@ -293,7 +293,7 @@ pub fn generate_formatter() {
// Union nodes except for AnyFunction and AnyClass have a generated
// implementation, the codegen will always overwrite any existing file
- let allow_overwrite = matches!(kind, NodeKind::Union { .. }) && name != "JsAnyFunction";
+ let allow_overwrite = matches!(kind, NodeKind::Union { .. });
if !allow_overwrite && path.exists() {
continue;

refactor(rome_js_formatter): Extract `JsAnyFunction` formatter into `FormatFunction` (#2988)