Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix empty line check between array elements #14736

Merged
merged 7 commits into from May 5, 2023
Merged

Conversation

solarized-fox
Copy link
Contributor

@solarized-fox solarized-fox commented Apr 21, 2023

Description

fixes #13017

it seems that parens are not included in the start-end range a node has for referencing the source text. this can cause skipToLineEnd to compute incorrectly because it isn't expecting to encounter any trailing ")"s. adding ")" to the list of characters it skips fixes this

Checklist

  • I’ve added tests to confirm my change works.
  • (If changing the API or CLI) I’ve documented the changes I’ve made (in the docs/ directory).
  • (If the change is user-facing) I’ve added my changes to changelog_unreleased/*/XXXX.md file following changelog_unreleased/TEMPLATE.md.
  • I’ve read the contributing guidelines.

Try the playground for this PR

@fisker
Copy link
Member

fisker commented Apr 21, 2023

Honestly, I didn't expect you to change this part ...

It's also a public API.
If we accept this change, we'll need this changelog to show that skipToLineEnd and isNextLineEmpty skips ).

But before that, we need to think about what will be affected.

@fisker
Copy link
Member

fisker commented Apr 21, 2023

This case is not format correctly

Prettier pr-14736
Playground link

--parser babel

Input:

[
  (a=b
  
  ),
  b, //
];

Output:

[
  (a = b),

  b, //
];

@solarized-fox
Copy link
Contributor Author

Honestly, I didn't expect you to change this part ...

I tried a few other approaches, but they caused tests to fail. if you have any ideas I'm open to suggestions!

But before that, we need to think about what will be affected.

as for this, my understanding of skipToLineEnd is that it supposes that the only non-comment characters between the last node and EOL are in the character class of "\t ,; ", which would mean that since ")" can appear in there, this is not actually a behavior change so much as a bug fix. that's why I didn't make a changelog, but I can add one if you believe it's important

as for:

This case is not format correctly

Input:

[
  (a=b
  
  ),
  b, //
];

Output:

[
  (a = b),

  b, //
];

I'm not sure the information required to fix this is present in the AST? the existing code uses the next line being whitespace as a sort of hacky heuristic here, but as you've demonstrated that is inadequate. any robust solution would require a fair bit of code to determine what is and isn't part of a multiline expression. perhaps this is better off raised as a followup issue, as it doesn't seem idempotency is violated in this example and fixing this beyond all edge cases might be a nontrivial effort requiring discussion?

@solarized-fox
Copy link
Contributor Author

I decided to force-push a different version of this change. it solves the edge case mentioned by @fisker and doesn't change any public APIs. if anyone knows a shorter way to do this I'm all ears but otherwise I think this is an improvement over the last solution

@solarized-fox
Copy link
Contributor Author

I noticed there was a trivial merge conflict (printArrayItems was renamed to printArrayElements while I was working on it) so I fixed that up and force-pushed the change. it should be automatically mergeable now

} else {
const nextCandidate =
text[currentIdx] == ")" ? currentIdx + 1 : candidateIdx;
return skipParens(skipIfComment(currentIdx + 1), nextCandidate);
Copy link
Member

Choose a reason for hiding this comment

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

Can skip function do the job?

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 think it can't replace skipParens (and I think I'll rename skipParens to indexAfterFurthestParen for clarity) however after looking into it skipIfComment can be implemented with skip calls which cuts down a fair bit of code, so I'll make that change

@solarized-fox
Copy link
Contributor Author

solarized-fox commented Apr 23, 2023

while working editing the code, I realized instead of skipping the parens I can just skip directly to the comma. this is a lot less code overall

however, it did trigger one change in the tests where

[
  1
  ,
  
  2,
]

used to format as [1, 2] and now formats as [1,\n2]. this seems like it should be the correct behavior though, because otherwise a newline gets eaten. I have added a changelog and updated tests accordingly

@solarized-fox
Copy link
Contributor Author

solarized-fox commented Apr 24, 2023

thinking about the change, I guess the root question is, for this input:

_ = [
  (a = b
  //comment
  ),

  2,
  3 //
]

which of these outputs is most appropriate?

git checkout #13017

_ = [
  (a = b),

  //comment
  2,
  3, //
];

git checkout #13017-2

_ = [
  (a = b),
  //comment
  2,
  3, //
];

looking at it now, it probably would be the second example. the comment gets separated otherwise. I can push 13017-2 onto this branch if you think that'd be an improvement

@fisker
Copy link
Member

fisker commented Apr 24, 2023

Expected output should be

_ = [
  (a = b), //comment

  2,
  3, //
];

It's bug in comment attach. Should be done in a separate PR. The blank line check is correct here.

@solarized-fox
Copy link
Contributor Author

I see. well, setting aside the comment then, for this input:

_ = [
  (a = b
  ),

  2,
  3 //
]

which of these is preferred?

git checkout #13017

_ = [
  (a = b),

  2,
  3, //
];

git checkout 13017-2

_ = [
  (a = b),
  2,
  3, //
];

@fisker
Copy link
Member

fisker commented Apr 24, 2023

_ = [
  (a = b),

  2,
  3, //
];

Because there is a blank line between comma after first element and second element.

@solarized-fox
Copy link
Contributor Author

alright then, I'm fairly confident that this (the branch this PR is attached to) is the correct change. solving the root issue (i.e. #13017) without changing any snapshots would require writing code that then needs to be thrown out later. if you find anything else in the PR that needs changing, let me know, but otherwise I think it's ready

@solarized-fox
Copy link
Contributor Author

oops, saw the lint failure, fixed it and ran lint locally too so it should be solved for good

@fisker fisker changed the title Fix trailing parens tripping up skipToLineEnd Fix empty line check between array elements Apr 24, 2023
Copy link
Member

@fisker fisker left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

@solarized-fox
Copy link
Contributor Author

solarized-fox commented Apr 25, 2023

ah, sorry for the sudden force push, I accidentally pushed the button to merge changes from main into this branch, but I rolled that back. is there something else I need to do or will these changes be merged at some point in the future? I'm not a maintainer on this project, so I cannot merge it myself

Copy link
Member

@sosukesuzuki sosukesuzuki left a comment

Choose a reason for hiding this comment

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

LGTM! Please check one comment.

@@ -170,6 +171,18 @@ function isConciselyPrintedArray(node, options) {
);
}

function isLineAfterElementEmpty(path, { originalText: text }) {
Copy link
Member

Choose a reason for hiding this comment

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

Can we use destructuring assignment here?

Suggested change
function isLineAfterElementEmpty(path, { originalText: text }) {
function isLineAfterElementEmpty({ node }, { originalText: text }) {

@@ -9,17 +9,18 @@ import {
fill,
} from "../../document/builders.js";
import hasNewline from "../../utils/has-newline.js";
import isNextLineEmptyAfterIndex from "../../utils/is-next-line-empty.js";
import { skipInlineComment, skipTrailingComment } from "../../utils/public.js";
Copy link
Member

Choose a reason for hiding this comment

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

Missed this on previous review. Do not import from public.js, please import from the actual file directly.

@solarized-fox
Copy link
Contributor Author

I've implemented the suggested changes!

@solarized-fox
Copy link
Contributor Author

solarized-fox commented May 5, 2023

oops, forgot a semicolon I guess. it's fixed now

@fisker fisker merged commit 8108864 into prettier:main May 5, 2023
29 checks passed
@solarized-fox solarized-fox deleted the #13017 branch May 5, 2023 08:00
medikoo pushed a commit to medikoo/prettier-elastic that referenced this pull request Feb 15, 2024
Co-authored-by: ☀️ <sol@solfox.online>
Co-authored-by: fisker Cheung <lionkay@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

(idempotence violation) Empty line after parenthesized array item
3 participants