-
-
Notifications
You must be signed in to change notification settings - Fork 140
Fix edge cases with type imports #240
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 edge cases with type imports #240
Conversation
hendrikvanantwerpen
left a comment
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.
Thank you for willing contributing to this grammar!
I played a bit with the TS playground to get a feel for the different cases. Some interesting variants I found. The ones that parsed in Tree-sitter:
import A from './User.js'; // import identifier 'A'import type A from './User.js'; // import type 'A'import type { A } from './User.js'; // import type 'A'import { type A } from './User.js'; // import type 'A'import A, { type type } from './User.js'; // import identifier 'A' and type 'type'import type type from './User.js'; // import type 'type'
And those that didn't:
import type from './User.js'; // import identifier 'type'import { type, A } from './User.js'; // import identifiers 'type' and 'A'import type, { type A } from './User.js'; // import identifier 'type' and type 'A'import { type A } from './User.js'; // import type 'A'import type, A from './User.js'; // syntax errorimport { A, type } from './User.js'; // import identifiers 'type' and 'A'
The comments indicate the behavior in TSC.
I am surprised the type is not allowed for the $.identifier in import_clause and import_specifier. Especially since it works in other places, such as let type = 42;.
I think the fix worked, but fixing it like this will require doing it on more places (at least import_specifier). It would be better if we understand why type is not accepted in those positions and see if we can fix that, so it works everywhere where $.identifier is used.
Yeah, I was puzzled by this too. I thought it might have to do with it being a reserved identifier
After some time trying to figure it out, there didn't seem to be anything obvious so I went this workaround. I've just pushed a fix for the additional edge case with import specifiers and added more test cases. If someone with more knowledge of tree-sitter and this grammar can point out what is preventing |
hendrikvanantwerpen
left a comment
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 for adding more tests! It seems that this is the best solution for now. One last nit: I think we should create a separate production for the new choice, instead of replicating it several times. Something like:
_import_identifier: $ => choice($.identifier, alias('type', $.identifier))
and then use $._import_identifier in those places. That way we keep this localized, and if we find a more principled solution later, it will be easier to fix.
|
Good idea, thanks! |
hendrikvanantwerpen
left a comment
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.
That's much cleaner. There's one place where the change wasn't applied, but otherwise this looks good.
| choice( | ||
| field('name', $._import_identifier), | ||
| seq( | ||
| field('name', choice($._module_export_name, alias('type', $.identifier))), |
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.
One more place where we can use $._import_identifier.
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 think replacing choice($._module_export_name, alias('type', $.identifier)) with $._import_identifier would change the semantics of the grammar because $._module_export_name is equivalent to choice($.string, $.identifier) not merely $.identifier. See tree-sitter/tree-sitter-javascript#234 for more context.
If you'd like, I could factor out alias('type', $.identifier) from choice($.identifier, alias('type', $.identifier)) into its own rule and use it here.
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're absolutely right, this is not the same case!
|
Thanks for the contribution, @rtsao! |
Fixes #234
The following should parse correctly (TS playground) (Flow playground):
Before:
After:
Checklist: