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

feat(rome_js_formatter): Conditional expression formatting #3024

Merged
merged 6 commits into from
Aug 9, 2022

Conversation

MichaReiser
Copy link
Contributor

@MichaReiser MichaReiser commented Aug 7, 2022

Summary

This PR implements conditional expression formatting similar to Prettier with the exception of the special handling of conditional expressions containing JSX (PR is already huge).

Test Plan

I manually reviewed the snapshot changes. Some changes may appear as regressions but are mainly due to other syntax formatting (binary expression, call arguments). I ignored comments in this PR (except to make sure comments are stable) as we plan to refactor comments.

File Based Average Prettier Similarity: 78.85% -> 79.72%
Line Based Average Prettier Similarity: 74.25% -> 76.49%

@MichaReiser MichaReiser added the A-Formatter Area: formatter label Aug 7, 2022
@MichaReiser MichaReiser added this to the 0.9.0 milestone Aug 7, 2022
@MichaReiser MichaReiser force-pushed the feat/conditional-expression branch from f7c6b7e to 7102fcf Compare August 7, 2022 15:48
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Aug 7, 2022

Deploying with  Cloudflare Pages  Cloudflare Pages

Latest commit: ab1d20c
Status: ✅  Deploy successful!
Preview URL: https://98554c7b.tools-8rn.pages.dev
Branch Preview URL: https://feat-conditional-expression.tools-8rn.pages.dev

View logs

@@ -49,7 +50,7 @@ impl<'fmt, Context> Argument<'fmt, Context> {
}

/// Formats the value stored by this argument using the given formatter.
#[inline]
#[inline(always)]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I ran into issues with stack overflows on the playground in debug builds. Adding inline(always) ensures that this "trivial" calls are also inlined in debug mode which results in nicer stack traces

@@ -333,7 +333,7 @@ impl<'a> Printer<'a> {
// If the indentation level has changed since these line suffixes were queued,
// insert a line break before to push the comments into the new indent block
// SAFETY: Indexing into line_suffixes is guarded by the above call to is_empty
let has_line_break = self.state.line_suffixes[0].args.indent < args.indent;
let has_line_break = self.state.line_suffixes[0].args.indent.level() < args.indent.level();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Comparing the align isn't necessary as it turns out, this hack is only for moving comments after a (, [, or { into the indent.

+ }
+ }
+),
+ (
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is an issue with parenthesized expressions

@@ -148,228 +130,165 @@ a
- </Content>
- </Message>
- );
+const StorybookLoader = ({ match }) => (
+ match.params.storyId === "button"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

JSX special case is intentionally excluded from this PR

}

function foo() {
- void ((
- coooooooooooooooooooooooooooooooooooooooooooooooooooond
- ? baaaaaaaaaaaaaaaaaaaaar
+ void (
+ (coooooooooooooooooooooooooooooooooooooooooooooooooooond
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I only implemented the parentheses handling for expressions but not types. It will be easier to address this with an overall solution that avoids "resolving" expressions everywhere.

@MichaReiser MichaReiser force-pushed the feat/conditional-expression branch from 7102fcf to c72beb3 Compare August 8, 2022 06:53
@MichaReiser
Copy link
Contributor Author

!bench_formatter

@MichaReiser MichaReiser marked this pull request as ready for review August 8, 2022 06:55
@MichaReiser MichaReiser requested a review from ematipico as a code owner August 8, 2022 06:55
@MichaReiser MichaReiser requested a review from a team August 8, 2022 06:55
@github-actions
Copy link

github-actions bot commented Aug 8, 2022

Formatter Benchmark Results

group                                    main                                   pr
-----                                    ----                                   --
formatter/checker.ts                     1.00    375.1±3.34ms     6.9 MB/sec    1.00    375.3±3.07ms     6.9 MB/sec
formatter/compiler.js                    1.00    229.0±1.20ms     4.6 MB/sec    1.01    230.7±1.00ms     4.5 MB/sec
formatter/d3.min.js                      1.00    181.0±1.67ms  1482.9 KB/sec    1.02    185.4±1.54ms  1448.0 KB/sec
formatter/dojo.js                        1.00     12.9±0.06ms     5.3 MB/sec    1.01     12.9±0.05ms     5.3 MB/sec
formatter/ios.d.ts                       1.00    259.6±1.42ms     7.2 MB/sec    1.01    261.3±0.95ms     7.1 MB/sec
formatter/jquery.min.js                  1.00     49.3±0.53ms  1715.7 KB/sec    1.03     51.0±0.55ms  1660.0 KB/sec
formatter/math.js                        1.00    378.9±2.10ms  1749.9 KB/sec    1.04    393.1±3.05ms  1686.8 KB/sec
formatter/parser.ts                      1.00      8.7±0.03ms     5.6 MB/sec    1.01      8.7±0.01ms     5.5 MB/sec
formatter/pixi.min.js                    1.00    204.8±2.03ms     2.1 MB/sec    1.02    209.1±2.51ms     2.1 MB/sec
formatter/react-dom.production.min.js    1.00     61.2±0.87ms  1925.2 KB/sec    1.01     62.0±0.48ms  1902.4 KB/sec
formatter/react.production.min.js        1.00      3.2±0.02ms  1991.0 KB/sec    1.01      3.2±0.01ms  1979.9 KB/sec
formatter/router.ts                      1.00      6.7±0.05ms     9.1 MB/sec    1.00      6.8±0.01ms     9.1 MB/sec
formatter/tex-chtml-full.js              1.00    486.5±2.11ms  1918.2 KB/sec    1.03    502.6±3.70ms  1856.5 KB/sec
formatter/three.min.js                   1.00    237.9±2.03ms     2.5 MB/sec    1.01    240.6±1.26ms     2.4 MB/sec
formatter/typescript.js                  1.00  1537.7±16.05ms     6.2 MB/sec    1.00  1544.5±10.96ms     6.2 MB/sec
formatter/vue.global.prod.js             1.00     80.2±1.17ms  1538.1 KB/sec    1.04     83.1±1.36ms  1484.5 KB/sec

@MichaReiser
Copy link
Contributor Author

Formatter Benchmark Results

group                                    main                                   pr
-----                                    ----                                   --
formatter/checker.ts                     1.00    375.1±3.34ms     6.9 MB/sec    1.00    375.3±3.07ms     6.9 MB/sec
formatter/compiler.js                    1.00    229.0±1.20ms     4.6 MB/sec    1.01    230.7±1.00ms     4.5 MB/sec
formatter/d3.min.js                      1.00    181.0±1.67ms  1482.9 KB/sec    1.02    185.4±1.54ms  1448.0 KB/sec
formatter/dojo.js                        1.00     12.9±0.06ms     5.3 MB/sec    1.01     12.9±0.05ms     5.3 MB/sec
formatter/ios.d.ts                       1.00    259.6±1.42ms     7.2 MB/sec    1.01    261.3±0.95ms     7.1 MB/sec
formatter/jquery.min.js                  1.00     49.3±0.53ms  1715.7 KB/sec    1.03     51.0±0.55ms  1660.0 KB/sec
formatter/math.js                        1.00    378.9±2.10ms  1749.9 KB/sec    1.04    393.1±3.05ms  1686.8 KB/sec
formatter/parser.ts                      1.00      8.7±0.03ms     5.6 MB/sec    1.01      8.7±0.01ms     5.5 MB/sec
formatter/pixi.min.js                    1.00    204.8±2.03ms     2.1 MB/sec    1.02    209.1±2.51ms     2.1 MB/sec
formatter/react-dom.production.min.js    1.00     61.2±0.87ms  1925.2 KB/sec    1.01     62.0±0.48ms  1902.4 KB/sec
formatter/react.production.min.js        1.00      3.2±0.02ms  1991.0 KB/sec    1.01      3.2±0.01ms  1979.9 KB/sec
formatter/router.ts                      1.00      6.7±0.05ms     9.1 MB/sec    1.00      6.8±0.01ms     9.1 MB/sec
formatter/tex-chtml-full.js              1.00    486.5±2.11ms  1918.2 KB/sec    1.03    502.6±3.70ms  1856.5 KB/sec
formatter/three.min.js                   1.00    237.9±2.03ms     2.5 MB/sec    1.01    240.6±1.26ms     2.4 MB/sec
formatter/typescript.js                  1.00  1537.7±16.05ms     6.2 MB/sec    1.00  1544.5±10.96ms     6.2 MB/sec
formatter/vue.global.prod.js             1.00     80.2±1.17ms  1538.1 KB/sec    1.04     83.1±1.36ms  1484.5 KB/sec

I'm surprised this isn't worse. I guess, there aren't so many conditional expressions in our benchmark files

@MichaReiser MichaReiser force-pushed the feat/conditional-expression branch from c72beb3 to f10e508 Compare August 8, 2022 09:51
Base automatically changed from feat/align-indent-with-space-indent to main August 8, 2022 09:56
@MichaReiser MichaReiser force-pushed the feat/conditional-expression branch from f10e508 to 863b589 Compare August 8, 2022 09:56
@MichaReiser MichaReiser temporarily deployed to aws August 8, 2022 09:56 Inactive
@@ -1,39 +0,0 @@
use crate::context::QuoteStyle;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I had to move this is a manually created file and re-generating the formatter deletes the file. It's now part of utils/jsx

@github-actions
Copy link

github-actions bot commented Aug 8, 2022

@github-actions
Copy link

github-actions bot commented Aug 8, 2022

Parser conformance results on ubuntu-latest

js/262

Test result main count This PR count Difference
Total 45878 45878 0
Passed 44938 44938 0
Failed 940 940 0
Panics 0 0 0
Coverage 97.95% 97.95% 0.00%

jsx/babel

Test result main count This PR count Difference
Total 39 39 0
Passed 36 36 0
Failed 3 3 0
Panics 0 0 0
Coverage 92.31% 92.31% 0.00%

symbols/microsoft

Test result main count This PR count Difference
Total 5946 5946 0
Passed 395 395 0
Failed 5551 5551 0
Panics 0 0 0
Coverage 6.64% 6.64% 0.00%

ts/babel

Test result main count This PR count Difference
Total 588 588 0
Passed 519 519 0
Failed 69 69 0
Panics 0 0 0
Coverage 88.27% 88.27% 0.00%

ts/microsoft

Test result main count This PR count Difference
Total 16257 16257 0
Passed 12397 12397 0
Failed 3860 3860 0
Panics 0 0 0
Coverage 76.26% 76.26% 0.00%

@MichaReiser MichaReiser force-pushed the feat/conditional-expression branch from 863b589 to 94de173 Compare August 8, 2022 10:48
@MichaReiser MichaReiser temporarily deployed to aws August 8, 2022 10:48 Inactive
@@ -689,46 +688,6 @@ impl Indention {
}
}

/// Compares two [Indent]s by first comparing the indent level and, if equal, comparing the `align`.
/// This implementation assumes that `width(align) < width(1-level)`.
impl PartialOrd for Indention {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why was this removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's no longer needed, comparing the indent level is sufficient.

f,
[group(&soft_line_indent_or_space(&format_with(|f| {
if should_add_parens {
write!(f, [if_group_fits_on_line(&text("("))])?;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: just noticed this now but.. shouldn't this be if_group_fits_in_line?

Copy link
Contributor Author

@MichaReiser MichaReiser Aug 8, 2022

Choose a reason for hiding this comment

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

My understanding is:

  • fits in... you can stuff it into something.
  • fits on You can put it onto something?

That's why I think on is more appropriate. But maybe that's just due to my German background.

let argument = match parent.kind() {
JsSyntaxKind::JS_INITIALIZER_CLAUSE => {
let initializer = JsInitializerClause::unwrap_cast(parent);
initializer.expression().ok().map(JsAnyExpression::from)
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not sure sure we should "mute" a SyntaxResult. Is there a specific reason for doing so?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's safe to do so here because the function will return the "safe" default of false if the returned value from here is Err.

The errors get handled as part of the parent node.

let arrow = JsArrowFunctionExpression::unwrap_cast(parent.clone());

match arrow.body() {
Err(_) => false,
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not sure we should mute an error. I think we should bounce it to the parent

Copy link
Contributor Author

@MichaReiser MichaReiser Aug 8, 2022

Choose a reason for hiding this comment

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

This code is testing if the arrow.body is the direct parent because it may only then be necessary to add parentheses.

That also means that returning false is safe if it's an Err because it's then guaranteed that the conditional is for certain not the body (because it would then not be missing)

@MichaReiser MichaReiser force-pushed the feat/conditional-expression branch from 94de173 to cf30755 Compare August 8, 2022 13:01
@MichaReiser MichaReiser temporarily deployed to aws August 8, 2022 13:01 Inactive
@MichaReiser MichaReiser requested a review from ematipico August 8, 2022 13:01
@MichaReiser MichaReiser temporarily deployed to aws August 8, 2022 14:05 Inactive
@MichaReiser MichaReiser force-pushed the feat/conditional-expression branch from 68f3d30 to a53f0d5 Compare August 9, 2022 06:33
@MichaReiser MichaReiser temporarily deployed to aws August 9, 2022 06:33 Inactive
Comment on lines +3 to +5
assertion_line: 271
info:
test_file: js/unary-expression/urnary_expression.js
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe these changes can be reverted

Refactor conditional formatting to better make use of the new formatter infrastructure
@MichaReiser MichaReiser force-pushed the feat/conditional-expression branch from a53f0d5 to ab1d20c Compare August 9, 2022 15:28
@MichaReiser MichaReiser temporarily deployed to aws August 9, 2022 15:29 Inactive
@MichaReiser MichaReiser merged commit d2d95d5 into main Aug 9, 2022
@MichaReiser MichaReiser deleted the feat/conditional-expression branch August 9, 2022 15:42
IWANABETHATGUY pushed a commit to IWANABETHATGUY/tools that referenced this pull request Aug 22, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A-Formatter Area: formatter
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

2 participants
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载