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

feat(rome_js_formatter): JsAnyAssignmentLike node union for JsPropertyObjectMember and JsAssignmentExpression #2698

Merged
merged 18 commits into from
Jun 17, 2022

Conversation

denbezrukov
Copy link
Contributor

@denbezrukov denbezrukov commented Jun 11, 2022

Summary

This PR fixes #2410
This is the initial draft for JsAnyAssignmentLike.
I'd like to propose JsAnyAssignmentLike node union to handle different cases.
Prettier uses printAssignment for:

Open questions

I'm not sure about the name JsAnyAssignmentLike because some cases aren't assignment.

Test Plan

Add new spec tests cases for JsAssignmentExpression.

…pertyObjectMember and JsAssignmentExpression
@denbezrukov denbezrukov marked this pull request as draft June 11, 2022 19:15
@denbezrukov denbezrukov changed the title feat(rome_js_formatter): add JsAnyAssignmentLike node union for JsPropertyObjectMember and JsAssignmentExpression feat(rome_js_formatter): JsAnyAssignmentLike node union for JsPropertyObjectMember and JsAssignmentExpression Jun 11, 2022
let width = write_member_name(&property.name()?, f)?;
let text_width_for_break =
(f.context().tab_width() + MIN_OVERLAP_FOR_BREAK) as usize;
Ok(width < text_width_for_break)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, I noticed that too yesterday

@denbezrukov
Copy link
Contributor Author

denbezrukov commented Jun 11, 2022

If we choose this approach we'll need to add more variants for layout:

@denbezrukov

This comment was marked as resolved.

}

pub(crate) fn is_break_after_operator(right: &JsAnyExpression) -> SyntaxResult<bool> {
if has_leading_newline(right.syntax()) && right.syntax().has_leading_comments() {
Copy link
Contributor Author

@denbezrukov denbezrukov Jun 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that it works properly, because after format comments can be(???) in another place.
https://github.com/prettier/prettier/blob/2316e2fecd171335fc00f3ec97b7e46cc8964153/src/language-js/print/assignment.js#L126

@ematipico
Copy link
Contributor

I'm not sure about the name JsAnyAssignmentLike because some cases aren't assignment.

I think that's fine, as long as we document the data structure and explain what kind of situations it handles.

@denbezrukov denbezrukov marked this pull request as ready for review June 17, 2022 07:21
@denbezrukov
Copy link
Contributor Author

denbezrukov commented Jun 17, 2022

@ematipico Could you help me please? 🙏🏽
I saw #2721.
Should I close this PR?

@MichaReiser MichaReiser requested a review from ematipico June 17, 2022 09:15
@ematipico
Copy link
Contributor

ematipico commented Jun 17, 2022

@ematipico Could you help me please? 🙏🏽
I saw #2721.
Should I close this PR?

Oh, please don't. I would actually close mine. The problem is that I didn't see what issues this PR is closing.

Could you please update the description? This is really important to us, it avoids double work.

I will help of course!

@denbezrukov
Copy link
Contributor Author

denbezrukov commented Jun 17, 2022

Could you please update the description? This is really important to us, it avoids double work.

I'm sorry for that. I didn't check the issues before opening PR. My bad. 😓

I would actually close mine.

I'm going to copy has_new_line_before_comment and spec test cases (:

Copy link
Contributor

@ematipico ematipico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the great contribution!

About the next steps, here's what I had in mind. As you explained, prettier uses this way of formatting for many things, and eventually we will need to check the "left" and "right" part of an assignment like.

Which means that "left" and "right" should be grouped inside another unions, because the "left" part of an assignment like might differ based on what we are formatting. My idea was to create a LeftAssignmentLike:

declare_node_union! {
    pub(crate) LeftAssignmentLike = JsAnyAssignmentPattern | JsAnyObjectMemberName
}

If you're OK which this plan, I will work on #2416 and you can choose another one (maybe VariableDeclarator?). Feel free to comment in the issue and I will assign that to you

crates/rome_js_formatter/src/utils/assignment_like.rs Outdated Show resolved Hide resolved
crates/rome_js_formatter/src/utils/assignment_like.rs Outdated Show resolved Hide resolved
let width = write_member_name(&property.name()?, f)?;
let text_width_for_break =
(f.context().tab_width() + MIN_OVERLAP_FOR_BREAK) as usize;
Ok(width < text_width_for_break)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, I noticed that too yesterday

@ematipico
Copy link
Contributor

If we choose this approach we'll need to add more variants for layout:

* [prettier/prettier@`2316e2f`/src/language-js/print/assignment.js#L37-L74](https://github.com/prettier/prettier/blob/2316e2fecd171335fc00f3ec97b7e46cc8964153/src/language-js/print/assignment.js#L37-L74)

I can definitely see that. And we should add variants while we implement other assignments. I already started implementing Chain and ChainTail

@denbezrukov
Copy link
Contributor Author

If you're OK which this plan, I will work on #2416 and you can choose another one (maybe VariableDeclarator?). Feel free to comment in the issue and I will assign that to you

It sounds great. 👍👍👍

VariableDeclarator - #2423 ? I've already taken it. After this PR I'll work on it.

@denbezrukov
Copy link
Contributor Author

I can definitely see that. And we should add variants while we implement other assignments. I already started implementing Chain and ChainTail

I noticed that to implement this variant we need to know layout outside format_with in format_assignment_like function.
Because chain variants don't have outer group. Do you have any idea how to get this?

Copy link
Contributor

@ematipico ematipico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! Thank you very much! This contribution is great! We can rebase and merge it :)

# Conflicts:
#	crates/rome_js_formatter/src/utils/mod.rs
#	crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/edge_case.js.snap
#	crates/rome_js_formatter/tests/specs/prettier/js/method-chain/bracket_0.js.snap
#	crates/rome_js_formatter/tests/specs/prettier/js/new-expression/with-member-expression.js.snap
#	crates/rome_js_formatter/tests/specs/prettier/js/template-literals/expressions.js.snap
#	crates/rome_js_formatter/tests/specs/prettier/js/template/graphql.js.snap
#	crates/rome_js_formatter/tests/specs/prettier/typescript/as/assignment.ts.snap
@ematipico ematipico merged commit 6cc5a3c into rome:main Jun 17, 2022
@ematipico
Copy link
Contributor

I can definitely see that. And we should add variants while we implement other assignments. I already started implementing Chain and ChainTail

I noticed that to implement this variant we need to know layout outside format_with in format_assignment_like function. Because chain variants don't have outer group. Do you have any idea how to get this?

* [prettier/prettier@`877ae8e`/src/language-js/print/assignment.js#L63-L70](https://github.com/prettier/prettier/blob/877ae8ec16369dc0cf79ee36019bfdce40429eae/src/language-js/print/assignment.js#L63-L70)

That's because we assumed that each variant had a group, and we should not. I think the best implementation is:

fn write_assignment_like() -> FormatResult<()> {
	match layout {}
}

And each variant write!

@denbezrukov
Copy link
Contributor Author

I can definitely see that. And we should add variants while we implement other assignments. I already started implementing Chain and ChainTail

I noticed that to implement this variant we need to know layout outside format_with in format_assignment_like function. Because chain variants don't have outer group. Do you have any idea how to get this?

* [prettier/prettier@`877ae8e`/src/language-js/print/assignment.js#L63-L70](https://github.com/prettier/prettier/blob/877ae8ec16369dc0cf79ee36019bfdce40429eae/src/language-js/print/assignment.js#L63-L70)

That's because we assumed that each variant had a group, and we should not. I think the best implementation is:

fn write_assignment_like() -> FormatResult<()> {
	match layout {}
}

And each variant write!

Yes, but unfortunately we need to call write_left to know if left part is short or not :(

@ematipico
Copy link
Contributor

ematipico commented Jun 17, 2022

I solved like this:

        match self {
            JsAnyAssignmentLike::JsPropertyObjectMember(_) => {
                write!(f, [group_elements(&format_content)])
            }
            JsAnyAssignmentLike::JsAssignmentExpression(_) => {
                write!(f, [&format_content])
            }
        }

At the very end of the function

@denbezrukov
Copy link
Contributor Author

denbezrukov commented Jun 17, 2022

I solved like this:

        match self {
            JsAnyAssignmentLike::JsPropertyObjectMember(_) => {
                write!(f, [group_elements(&format_content)])
            }
            JsAnyAssignmentLike::JsAssignmentExpression(_) => {
                write!(f, [&format_content])
            }
        }

At the very end of the function

Hmm, but there are cases then assignment expression has group in prettier. It seems that only chain layout variants should be without group. Is it possible to write in temporary buffer before wrapping in a group?

@ematipico
Copy link
Contributor

Sorry, I guess I assumed too many things here 😅

I had to move all the code inside write_assignment_like inside the format function in order to make things work. This is actually way better:

  • the implementation needs to have access to the parent. In this example path is the parent node. This way, we can access to the parent without too many traverse.
  • most of the functions we have can be moved inside impl JsAnyAssignmentLike
  • the only small issue is is_break_after_operator because it's used somewhere else

@ematipico
Copy link
Contributor

@denbezrukov Please check #2728

@denbezrukov denbezrukov deleted the assigment-like branch June 17, 2022 18:16
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Assignment of array/object literals
2 participants