[tsx] raise error on single arrow type argument without comma#14135
[tsx] raise error on single arrow type argument without comma#14135nicolo-ribaudo merged 12 commits intobabel:mainfrom ozanhonamlioglu:error-on-single-type-without-comma
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.
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
|
|
||
| // report error if single type parameter used without trailing comma. | ||
| if ( | ||
| arrow.node?.type === "ArrowFunctionExpression" && |
There was a problem hiding this comment.
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.
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.
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.
| const node = parameter.name; | ||
| let identifierName = ""; | ||
| if (typeof node === "object") identifierName = node.name; | ||
| else identifierName = node; |
There was a problem hiding this comment.
| 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.
| 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.
| "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.
| // If Type has any constraints, means that it is not alone their. | |
| // If parameter has any constraints, it must contain multiple tokens |
| // 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.
@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.
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.
| "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.
Nit: I'd prefer to name this SingleTypeParameterWithoutTrailingComma
| // 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.
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.
|
|
||
| if (hasSingleTypeError.status) { | ||
| this.raise( | ||
| hasSingleTypeError.start, |
There was a problem hiding this comment.
Rather than at .start, we could report the error at parameter.end + 1 which is where we expect the trailing comma.
| this.raise( | ||
| invalidSingleType.end + 1, |
There was a problem hiding this comment.
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.
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.
| "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.
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.
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.
@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.
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.
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.
@nicolo-ribaudo do you think it is okay?
There was a problem hiding this comment.
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.
There is createPositionWithColumnOffset in ./util/location serving the same purpose.
There was a problem hiding this comment.
Oh I didn't know that. So you want me to use that method for the position and update the PR right?
@JLHwung
|
@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.
Is it possible to check it only in tsx file? @ozanhonamlioglu
(#14361 )
There was a problem hiding this comment.
@nicolo-ribaudo Sounds logical to me, shall I change it with tsx? What is your opinion?
There was a problem hiding this comment.
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.
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)