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 handling of comments with decorators before export #15032

Merged

Conversation

nicolo-ribaudo
Copy link
Member

@nicolo-ribaudo nicolo-ribaudo commented Oct 10, 2022

Q                       A
Fixed Issues? Fixes #12276
Patch: Bug Fix?
Major: Breaking Change?
Minor: New Feature?
Tests Added + Pass? Yes
Documentation PR Link
Any Dependency Changes?
License MIT

@babel-bot
Copy link
Collaborator

babel-bot commented Oct 10, 2022

Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/53238/

liuxingbaoyu
liuxingbaoyu previously approved these changes Oct 13, 2022
// comments between `export` and `class` as leading comments of the
// class declaration node.
// This is needed because the class location range overlaps with
// `export`, and thus they would me marked as inner comments of
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// `export`, and thus they would me marked as inner comments of
// `export`, and thus they would be marked as inner comments of

// `export`, and thus they would me marked as inner comments of
// the class declaration.
// @dec export /* comment */ class Foo {}
// See [parseDecorators] for the hanling of comments before decorators
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// See [parseDecorators] for the hanling of comments before decorators
// See [parseDecorators] for the handling of comments before decorators

lastTokEndLoc: { index: lastTokEnd },
} = this.state;

if (this.input.slice(lastTokStart, lastTokEnd) === "export") {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we move the comments manipulation to

finalizeComment(commentWS: CommentWhitespace) {
?

So that comments manipulation are placed within a single file and we probably don't have to do an export lookback.

Copy link
Member Author

Choose a reason for hiding this comment

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

I moved the logic to comments.ts, but I'm not sure about how to do it in finalizeComment. Specifically, I don't think we can distinguish /* 1 */ and /* 2 */ when finalizing the comments of the class node:

@dec export default /* 1 */ class /* 2 */ extends X {}

(I just realized that this PR doesn't support the default case, I'll add it)

@nicolo-ribaudo
Copy link
Member Author

nicolo-ribaudo commented Oct 25, 2022

I completely rewrote how decorators are attached to classes:

  • first we finalize the ClassDeclaration/ExportNamedDeclaration nodes, attaching their comments
  • then we attach the decorators

By doing so we don't need any custom comment adjustment logic. While doing so I also removed the decoratorStack state, which was not needed anymore.

@nicolo-ribaudo nicolo-ribaudo marked this pull request as draft October 25, 2022 13:18
@nicolo-ribaudo
Copy link
Member Author

There are still some generator bugs

@nicolo-ribaudo
Copy link
Member Author

nicolo-ribaudo commented Oct 25, 2022

Before this PR:

@dec export class A {}
    ^^^^^^^^^^^^^^^^^^
           ExportDeclaration

^^^^^^^^^^^^^^^^^^^^^^
   ClassDeclaration

^^^^
Decorator

After this PR:

@dec export class A {}
^^^^^^^^^^^^^^^^^^^^^^
   ExportDeclaration

^^^^^^^^^^^^^^^^^^^^^^
   ClassDeclaration

^^^^
Decorator

(in both cased the nodes hierarchy if ExportDeclaration > ClassDeclaration > Decorator)

The "unusual" comment attachment only happens when there is @dec export class. In all the other cases comments follow the common nesting rules, so

  • in /* 1 */ @d /* 2 */ class A {}, 1 is a leading comment of the class and 2 a trailing comment of the decorator
  • in /* 1 */ @d export /* 2 */ class A {} 1 is a leading comment of the export declaration and 2 a leading comment of the class.

@nicolo-ribaudo nicolo-ribaudo marked this pull request as ready for review October 25, 2022 15:42
Copy link
Member

@liuxingbaoyu liuxingbaoyu left a comment

Choose a reason for hiding this comment

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

Great job!
Also the E2E test failure is related, I'm not sure if that is expected.

packages/babel-parser/src/parser/statement.ts Outdated Show resolved Hide resolved
packages/babel-parser/src/parser/statement.ts Outdated Show resolved Hide resolved
Co-authored-by: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com>
@nicolo-ribaudo
Copy link
Member Author

@fisker / @sosukesuzuki How does prettier decide when to print decorators before export and when to print them after?

@JLHwung
Copy link
Contributor

JLHwung commented Oct 25, 2022

I believe e2e test is breaking because prettier uses location of first decorator versus the attached class node to detect decorators before export:

https://github.com/prettier/prettier/blob/ca246afacee8e6d5db508dae01730c9523bbff1d/src/language-js/print/decorators.js#L76

@nicolo-ribaudo
Copy link
Member Author

nicolo-ribaudo commented Oct 25, 2022

Uhm ok. I can restore the original location of the export declaration, but I believe it's wrong and in Babel 8 we should make it include decorators again (because the a node should always start before is children and end after).

If prettier uses tokens when printing, they can check if the export token comes before or after the first decorator.

@liuxingbaoyu
Copy link
Member

prettier/prettier#12806 (comment)
They should not use tokens.

Copy link
Contributor

@JLHwung JLHwung left a comment

Choose a reason for hiding this comment

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

I agree that the new location setting makes sense to me. Since prettier has pinned @babel/parser so it should be fine even if we ship as-is. Can prettier support the new location setting here? If so we don't have to defer to Babel 8.

@nicolo-ribaudo
Copy link
Member Author

nicolo-ribaudo commented Oct 25, 2022

Another option that prettier has is to check if inputSource[exportDeclarationNode.start] === "@". Prettier maintainers, how does that sound?

@fisker
Copy link
Contributor

fisker commented Oct 25, 2022

New location make sense, don't need worry about us, we'll tweak logic.

@liuxingbaoyu liuxingbaoyu added PR: Ready to be Merged A pull request with already two approvals, but waiting for the next minor release and removed PR: Ready to be Merged A pull request with already two approvals, but waiting for the next minor release labels Oct 25, 2022
@nicolo-ribaudo nicolo-ribaudo merged commit 362f15b into babel:main Oct 25, 2022
@nicolo-ribaudo nicolo-ribaudo deleted the decoratorsBeforeExport-comments branch October 25, 2022 18:18
@fisker
Copy link
Contributor

fisker commented Oct 26, 2022

End up with locStart(node) === locStart(decorators[0]) solution, https://github.com/prettier/prettier/pull/13733/files

@github-actions github-actions bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Jan 26, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jan 26, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: comments outdated A closed issue/PR that is archived due to age. Recommended to make a new issue pkg: generator pkg: parser PR: Bug Fix 🐛 A type of pull request used for our changelog categories Spec: Decorators (Legacy) Spec: Decorators
Projects
None yet
5 participants