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

feat(typescript-estree): add ParenthesizedExpression when surrounded by JSDoc type comment #3135

Closed
wants to merge 10 commits into from

Conversation

armano2
Copy link
Member

@armano2 armano2 commented Mar 2, 2021

This PR adds option to generate ParenthesizedExpression if they are surrounded by jsDoc comments

ParenthesizedExpression :< Node {
  type: 'ParenthesizedExpression';
  expression: Expression;
}

#1682
cc. @thorn0

@typescript-eslint
Copy link
Contributor

Thanks for the PR, @armano2!

typescript-eslint is a 100% community driven project, and we are incredibly grateful that you are contributing to that community.

The core maintainers work on this in their personal time, so please understand that it may not be possible for them to review your work immediately.

Thanks again!


🙏 Please, if you or your company is finding typescript-eslint valuable, help us sustain the project by sponsoring it transparently on https://opencollective.com/typescript-eslint. As a thank you, your profile/company logo will be added to our main README which receives thousands of unique visitors per day.

@armano2
Copy link
Member Author

armano2 commented Mar 2, 2021

do we want to generate them in when comment is outside of node?

const x = /* test */ (2);
const x = /* test */(2);
const x = (2) /* test */;
const x = (2)/* test */;

@armano2 armano2 added the package: typescript-estree Issues related to @typescript-eslint/typescript-estree label Mar 2, 2021
@bradzacher
Copy link
Member

This PR adds option to generate ParenthesizedExpression if they are surrounded by comments

For the specific usecase of a JSDoc type assertion - I think we should specifically handle that case with an AST node as part of the normal parse cycle (with no option required).

For other cases - I thought the intention was to indicate all parentheses via the AST?
eg (((1))) would generate ParenthesizedExpression > ParenthesizedExpression > ParenthesizedExpression > Literal.
Am I misunderstanding the request from prettier?

@bradzacher bradzacher added the enhancement New feature or request label Mar 2, 2021
@armano2
Copy link
Member Author

armano2 commented Mar 2, 2021

For the specific usecase of a JSDoc type assertion - I think we should specifically handle that case with an AST node as part of the normal parse cycle (with no option required).

this is breaking change, and will require major release

For other cases - I thought the intention was to indicate all parentheses via the AST?

if that's a case we can just remove condition

          hasComments(this.ast, node)

@codecov
Copy link

codecov bot commented Mar 2, 2021

Codecov Report

Merging #3135 (a99cd94) into master (84fe328) will increase coverage by 0.00%.
The diff coverage is 100.00%.

@@           Coverage Diff           @@
##           master    #3135   +/-   ##
=======================================
  Coverage   92.88%   92.88%           
=======================================
  Files         315      315           
  Lines       10706    10708    +2     
  Branches     3025     3026    +1     
=======================================
+ Hits         9944     9946    +2     
  Misses        342      342           
  Partials      420      420           
Flag Coverage Δ
unittest 92.88% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
...pt-estree/src/ts-estree/estree-to-ts-node-types.ts 100.00% <ø> (ø)
packages/visitor-keys/src/visitor-keys.ts 100.00% <ø> (ø)
packages/typescript-estree/src/convert.ts 98.25% <100.00%> (+<0.01%) ⬆️

@thorn0
Copy link
Contributor

thorn0 commented Mar 2, 2021

Am I misunderstanding the request from prettier?

Yes, a little. When I was talking about nested parentheses, first and foremost I had nested JSDoc type assertions in mind. Prettier doesn't care about other parenthesized expressions.

Just like in TypeScript, you can sometimes see things like foo as any as MyType, people do the same thing with JSDoc.

@thorn0
Copy link
Contributor

thorn0 commented Mar 2, 2021

That said, as mentioned in estree/estree#194, seemingly redundant parentheses sometimes can have runtime consequences in JS, so probably it's another use case where it makes sense to represent them in the AST. Nestedness doesn't matter in that case though.

@armano2
Copy link
Member Author

armano2 commented Mar 2, 2021

For cowpath-paving information, Acorn provides a preserveParens option that fixes exactly this:
estree/estree#194 (comment)

this option name seem better than mine

we can go both ways, i can generate them for all or when comments are present, i have no opinion on this.

@thorn0
Copy link
Contributor

thorn0 commented Mar 2, 2021

do we want to generate them in when comment is outside of node?

That's the only case when I personally would like to have them generated. Besides, the comment should be leading and contain @type {...}.

The syntax of JSDoc type assertions is simple: @type {...} comment followed by a parenthesized expression. Anything else is not a type assertion. Reference: Closure Compiler, TypeScript.

@bradzacher
Copy link
Member

In that case I'd suggest that we just handle the specific case of a JSDoc type assertion and ignore all others as I mentioned here: #1682 (comment)


I don't think this is a breaking change - we don't usually treat adding a new AST node as a breaking change.
For example, when we introduced optional chaining it was a feature, when we introduced tuple types it was a feature.

In the absolute strictest sense: yes, a new node is a breaking change, and a new property value is too (eg nullish coalescing added ?? to LogicalExpression.operator). However if we used that logic then almost every single AST addition would be a breaking change.
For example - even #3112 added JSXNamespacedName, so that was technically breaking.

That is a bad line to follow and was what lead the old project to release 18 major versions in 4 months.

@armano2
Copy link
Member Author

armano2 commented Mar 2, 2021

ok updated base on feedback, and i changed tests a little for this

@armano2 armano2 changed the title feat: add ParenthesizedExpression node if requested feat: add ParenthesizedExpression when needed Mar 2, 2021
@thorn0
Copy link
Contributor

thorn0 commented Mar 2, 2021

TypeScript expects the type to be enclosed in curly brackets, however Closure Compiler accepts types in parens and even without any delimiters at all. That's why Prettier searches comments only for starting with * and containing the substring "@type". I'm not insisting on taking this into account in this PR, especially if it complicates the implementation. JFYI.

upd: Looks like this has changed. TS is fine with types without delimiters, but still doesn't accept types in parens (/** @type (x) */). It still generates a JSDocTypeTag node for it though, so we are completely fine!

@armano2 armano2 changed the title feat: add ParenthesizedExpression when needed feat: add ParenthesizedExpression when surrounded by jsDoc type comment Mar 6, 2021
@armano2 armano2 changed the title feat: add ParenthesizedExpression when surrounded by jsDoc type comment feat(typescript-estree): add ParenthesizedExpression when surrounded by jsDoc type comment Mar 6, 2021
@armano2 armano2 changed the title feat(typescript-estree): add ParenthesizedExpression when surrounded by jsDoc type comment feat(typescript-estree): add ParenthesizedExpression when surrounded by JSDoc type comment Mar 6, 2021
@armano2
Copy link
Member Author

armano2 commented Mar 6, 2021

requested changes has been applied

Copy link
Member

@bradzacher bradzacher left a comment

Choose a reason for hiding this comment

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

all the code and tests LGTM.
One comment.

Comment on lines +1181 to +1182
export interface ParenthesizedExpression extends BaseNode {
type: AST_NODE_TYPES.ParenthesizedExpression;
Copy link
Member

Choose a reason for hiding this comment

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

Because this case is specifically about JSDoc type assertions, and we have no immediate or future plans to support more parenthesized expressions - I think we should call this JSDocTypeAssertion.

Copy link
Contributor

@thorn0 thorn0 Mar 22, 2021

Choose a reason for hiding this comment

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

ParenthesizedExpression is an established thing in the ecosystem. Could we keep this type and add a boolean property jsDocTypeAnnotation: true instead? (The typeAnnotation property containing a type will do too, but it's out of scope for now I guess.)

Copy link
Member

Choose a reason for hiding this comment

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

Within ESTree its not an established practice. Most JS parsers don't emit it either. Babel does emit it all-or-nothing via a flag.

Adding a new node type is a much better API than using something generic because it's a special type of expression which has special meaning AND syntax to typescript and we should treat it akin to an as or angle bracket assertion. This isn't just a regular parenthesised expression where the parentheses control order of operations.

Copy link
Member 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.

Babel does emit it all-or-nothing via a flag.

I'd say that's what most JS parsers do. I was a bit worried about compatibility issues for various tools like recast. There is no evidence people use it with this parser though. If you think it's not a big deal, so be it.

Choose a reason for hiding this comment

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

@armano2 Note that that PR doesn't change whether or not we create ParentesizedExpression nodes, it only ensures that we don't throw when we do emit them.

@thorn0
Copy link
Contributor

thorn0 commented Mar 22, 2021

I forgot to mention that, just like usual TS type assertions, this syntax can be the RHS of an assignment (see TS playground). This might be something that should be taken into account in this PR.

@bradzacher bradzacher added the awaiting response Issues waiting for a reply from the OP or another party label Mar 28, 2021
@bradzacher bradzacher added the DO NOT MERGE PRs which should not be merged yet label Jul 31, 2021
@bradzacher bradzacher added the stale PRs or Issues that are at risk of being or have been closed due to inactivity for a prolonged period label Mar 4, 2022
@bradzacher bradzacher closed this Mar 4, 2022
@bradzacher bradzacher deleted the feat/parenthesized-expressions branch March 4, 2022 07:41
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 25, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
awaiting response Issues waiting for a reply from the OP or another party DO NOT MERGE PRs which should not be merged yet enhancement New feature or request package: typescript-estree Issues related to @typescript-eslint/typescript-estree stale PRs or Issues that are at risk of being or have been closed due to inactivity for a prolonged period
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants