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
[tsx] raise error on single arrow type argument without comma #14135
[tsx] raise error on single arrow type argument without comma #14135
Conversation
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/51363/ |
) { | ||
const typeName = arrow.node.typeParameters.params[0].name; | ||
const start = arrow.node.start; | ||
this.raise(start, TSErrors.SingleTypeWithoutTrailingComma, typeName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Babel 8 tests (you can run them with BABEL_8_BREAKING=true yarn jest parser
) are failing, I think it's becaus typeName
isn't a string anymore but a node: #12829
@@ -2930,6 +2932,17 @@ export default (superClass: Class<Parser>): Class<Parser> => | |||
return expr; | |||
}, state); | |||
|
|||
// report error if single type parameter used without trailing comma. | |||
if ( | |||
arrow.node?.type === "ArrowFunctionExpression" && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should only report the error if this.hasPlugin("jsx")
// report error if single type parameter used without trailing comma. | ||
if ( | ||
arrow.node?.type === "ArrowFunctionExpression" && | ||
arrow.node?.typeParameters?.params.length === 1 && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After the previous check we know that node is defined, so we don't need the first ?.
. Also, we don't need it after .typeParameters
in the next check.
I have updated the PR to adapt to babel 8 features. I have a question but it can maybe out of topic @nicolo-ribaudo What do you suggest me to be good on Babel library? I started to educate myself on compilers and interpreters with a book named "Crafting Interpreters". The book is so good, it teach me so much stuff about compilers. But do you have any suggestion specificly on Babel. Thanks |
We have some videos about how Babel works at https://babeljs.io/videos, and https://github.com/jamiebuilds/babel-handbook shows different methods that are used in Babel plugins. Unfortunately we don't have much more 😅
I will probably buy it too one day 👀 |
CI is now failing on this test: https://github.com/microsoft/TypeScript/blob/main/tests/cases/compiler/jsxChildrenGenericContextualTypes.tsx I think it's because of |
Oh you right |
Btw, you can run that external TS tests with |
@@ -2930,6 +2932,33 @@ export default (superClass: Class<Parser>): Class<Parser> => | |||
return expr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you move the check before this line? It should simplify arrow.node
checks and we have typeParameters
ready. We can leak isSingleTypeWithoutTrailingComma
out of tryParse
and throw afterwards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
of course
const node = parameter.name; | ||
let identifierName = ""; | ||
if (typeof node === "object") identifierName = node.name; | ||
else identifierName = node; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const node = parameter.name; | |
let identifierName = ""; | |
if (typeof node === "object") identifierName = node.name; | |
else identifierName = node; | |
const identifierName = process.env.BABEL_8_BREAKING ? parameter.name.name : parameter.name; |
So we can remove Babel 7 AST support when we release Babel 8.
@@ -148,6 +148,8 @@ const TSErrors = makeErrorTemplates( | |||
"A 'set' accessor cannot have rest parameter.", | |||
SetAccesorCannotHaveReturnType: | |||
"A 'set' accessor cannot have a return type annotation.", | |||
SingleTypeWithoutTrailingComma: | |||
"Single type definition %0 should have a trailing comma end of it. Example usage: <%0,>.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Single type definition %0 should have a trailing comma end of it. Example usage: <%0,>.", | |
"Single type parameter %0 should have a trailing comma. Example usage: <%0,>.", |
) { | ||
const parameter = arrow.node.typeParameters.params[0]; | ||
if (parameter.constraint) { | ||
// If Type has any constraints, means that it is not alone their. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// If Type has any constraints, means that it is not alone their. | |
// If parameter has any constraints, it must contain multiple tokens |
@@ -2908,6 +2910,7 @@ export default (superClass: Class<Parser>): Class<Parser> => | |||
// Either way, we're looking at a '<': tt.jsxTagStart or relational. | |||
|
|||
let typeParameters: ?N.TsTypeParameterDeclaration; | |||
let hasSingleTypeError = { status: false, start: 0, identifierName: "" }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JLHwung I needed to raise error outside const arrow = ....
method because it should return expr
end of it instead an error.
This just a quick type which is defined in here but if you suggest me to move the type to anywhere else, that is okay too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we do let invalidSingleType: ?N.TSTypeParameter
, and then just do invalidSingleType = parameter
when it's invalid? It's similar to what we already do with the typeParameters
variable, and we avoid allocationg a few objects unnecessary.
@@ -148,6 +148,8 @@ const TSErrors = makeErrorTemplates( | |||
"A 'set' accessor cannot have rest parameter.", | |||
SetAccesorCannotHaveReturnType: | |||
"A 'set' accessor cannot have a return type annotation.", | |||
SingleTypeWithoutTrailingComma: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I'd prefer to name this SingleTypeParameterWithoutTrailingComma
@@ -2908,6 +2910,7 @@ export default (superClass: Class<Parser>): Class<Parser> => | |||
// Either way, we're looking at a '<': tt.jsxTagStart or relational. | |||
|
|||
let typeParameters: ?N.TsTypeParameterDeclaration; | |||
let hasSingleTypeError = { status: false, start: 0, identifierName: "" }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we do let invalidSingleType: ?N.TSTypeParameter
, and then just do invalidSingleType = parameter
when it's invalid? It's similar to what we already do with the typeParameters
variable, and we avoid allocationg a few objects unnecessary.
return expr; | ||
}, state); | ||
|
||
if (hasSingleTypeError.status) { | ||
this.raise( | ||
hasSingleTypeError.start, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than at .start
, we could report the error at parameter.end + 1
which is where we expect the trailing comma.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
this.raise( | ||
invalidSingleType.end + 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In 478a970 we changed the signature of .raise
; could you rebase this PR? 🙏 (otherwise I can do it)
As the new location, you can probably use { at: this.state.startLoc }
(which is the beginning of the token after the type parameter).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @nicolo-ribaudo , of course I can do it. I Will do it today night. But if you have any urgency, you can do it for me as well.
@@ -1,6 +1,9 @@ | |||
{ | |||
"type": "File", | |||
"start":0,"end":79,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":18}}, | |||
"errors": [ | |||
"SyntaxError: Single type parameter T should have a trailing comma. Example usage: <T,>. (2:17)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uh, this made me realize that this.state.startLoc
doesn't work because we didn't just finish parsing the type parameters, but the whole arrow. I guess we can go back to { at: invalidSingleType.end }
🙁
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You right, I actually realized that something wrong with that. Taking it back so and will update the PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nicolo-ribaudo but now it says 2:2 actually it should be 2:3 right? { at: invalidSingleType.loc.end }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2:2 is way better than 2:17 🤷
If we still want to report 2:3 (which is slightly better than 2:2, since it's consistent with the "unexpected token, expected ," errors) we could store this.state.startLoc
after the typeParameters = this.tsParseTypeParameters();
call a few lines above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did something different, lets see if it passes from tests, and if a valid usage for you also?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nicolo-ribaudo do you think it is okay?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @JLHwung can you give a last review for the PR? thanks
{ | ||
at: { | ||
...invalidSingleType.loc.end, | ||
column: invalidSingleType.loc.end.column + 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is createPositionWithColumnOffset
in ./util/location
serving the same purpose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I didn't know that. So you want me to use that method for the position and update the PR right?
@JLHwung
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, please!
@nicolo-ribaudo @JLHwung Hey guys |
|
||
// report error if single type parameter used without trailing comma. | ||
if ( | ||
this.hasPlugin("jsx") && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to check it only in tsx file? @ozanhonamlioglu
(#14361 )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nicolo-ribaudo Sounds logical to me, shall I change it with tsx? What is your opinion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TSX is "jsx in TypeScript". This check is only executed when TypeScript is enabled, so it's already only checking for tsx.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TSX is "jsx in TypeScript". This check is only executed when TypeScript is enabled, so it's already only checking for tsx.
In our project, we used the same presets (@babel/preset-env
+ @babel/preset-react
+ @babel/preset-typescript
) to transform all the files, which caused the .ts
files to be processed by the jsx plugin, so the generics in the .ts
files also triggered the SingleTypeParameterWithoutTrailingComma
error.
This is a wrong usage, we will improve it. Thank you! @ozanhonamlioglu @nicolo-ribaudo
In this issue #13778, we solved trailing comma end of single type usage in typescript plugin. But we didn't raised any error yet to notice developer about their wrong usage. Now with this PR, we are informing developer via raising an error.
Here is demo code
@nicolo-ribaudo you mentioned the bug in the discussion.
#14113 (comment)