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

Narrow the token to async when checking default exports #648

Merged
merged 1 commit into from
Oct 7, 2021
Merged

Narrow the token to async when checking default exports #648

merged 1 commit into from
Oct 7, 2021

Conversation

benjdlambert
Copy link
Contributor

Needed to use tt._async here to make sure that we check if it's an async function in default exports.

Fixes #543

@freben
Copy link

freben commented Sep 28, 2021

@alangpierce Gentle ping! This is a really nice unblocker for us to get our ESM support in place. Thank you.

@jhaals
Copy link

jhaals commented Oct 6, 2021

It would be great to get this one looked at! Thanks

Copy link
Owner

@alangpierce alangpierce left a comment

Choose a reason for hiding this comment

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

Thanks! Unfortunately, this fix ends up introducing a bug in the regular export default async function case, but I think I have ideas on how to fix.

If you look at the the tokens for regular export default async function foo() {}, that async is actually a "contextual keyword" token: one of type tt.name with the raw text "async" and contextual keyword 4 (ContextualKeyword._async): https://sucrase.io/#compareWithBabel=false&showTokens=true&code=%0Aexport%20default%20async%20function%20foo()%20%7B%7D

The whole "contextual keyword" concept is a nuance in JS where some words can be a variable name sometimes and a keyword other times, and the Acorn and Babel parsers (from which Sucrase is forked) have the distinction as well. Unfortunately, async is a bit inconsistent right now in that it's a contextual keyword in most contexts but sometimes a regular keyword, which is probably something that could be cleaned up in the long run. In the meantime, probably best to think of it as a contextual keyword for the purposes of this PR.

In terms of impact, the PR right now breaks recognition of the export default async function case, which makes it so this code:

export default async function blah() {}
blah();

transpiles to this:

exports. default = async function blah() {}
blah();

when it should transpile to this:

 async function blah() {} exports.default = blah;
blah();

The syntax export default async function blah() {} is supposed to declare the name blah for use elsewhere in the file, so the PR as-is makes the code crash due to blah no longer being a valid name.

I think the best fix here is to make the check more specific using a variant of this.tokens.matchesContextual. For example, you could do something like:

... || (
  this.tokens.matches5(...) &&
  this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 2, ContextualKeyword._async)
)

(There's probably room for improvement in this tokens API, but seems fine to call that out of scope here.)

To get this working, it would be great to see a few updates here:

  • Add a test for the export default async function blah() {} case. Sorry, that was missing coverage before.
  • Change the code here to use some variant of matchesContextual in addition to the check that it's already doing.
  • I think it would be nice to update the // export async function line in this file similarly and also the // export default async function line in ESMImportTransformer.ts, but I won't consider that blocking since those are separate issues.

I also see that there's a pre-existing CI failure with the babel example project in the test suite, so I'll try to get that fixed.

@benjdlambert
Copy link
Contributor Author

OK 🤞 Added some more tests to cover some of the other bits too like the react-hot-loader transforms too.

@github-actions
Copy link

github-actions bot commented Oct 7, 2021

Benchmark results

Before this PR: 242.2 thousand lines per second
After this PR: 240.8 thousand lines per second

Measured change: 0.6% slower (1.19% slower to 1.34% faster)
Summary: Likely no significant difference

@codecov
Copy link

codecov bot commented Oct 7, 2021

Codecov Report

Merging #648 (7d22dac) into main (c15268c) will increase coverage by 0.07%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #648      +/-   ##
==========================================
+ Coverage   82.58%   82.65%   +0.07%     
==========================================
  Files          56       56              
  Lines        5690     5928     +238     
  Branches     1344     1344              
==========================================
+ Hits         4699     4900     +201     
- Misses        708      745      +37     
  Partials      283      283              
Impacted Files Coverage Δ
src/transformers/CJSImportTransformer.ts 88.32% <ø> (ø)
src/transformers/ESMImportTransformer.ts 87.28% <ø> (ø)
src/util/formatTokens.ts 70.58% <0.00%> (-10.06%) ⬇️
src/parser/util/identifier.ts 90.90% <0.00%> (-4.10%) ⬇️
src/util/shouldElideDefaultExport.ts 77.77% <0.00%> (-3.48%) ⬇️
src/util/getClassInfo.ts 87.85% <0.00%> (-1.85%) ⬇️
src/parser/plugins/jsx/index.ts 91.33% <0.00%> (-1.48%) ⬇️
src/identifyShadowedGlobals.ts 88.09% <0.00%> (-1.10%) ⬇️
src/parser/plugins/flow.ts 63.99% <0.00%> (-1.09%) ⬇️
src/parser/traverser/expression.ts 88.36% <0.00%> (-0.13%) ⬇️
... and 21 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c15268c...7d22dac. Read the comment docs.

Copy link
Owner

@alangpierce alangpierce left a comment

Choose a reason for hiding this comment

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

Thanks, looks great! I'll merge and release now.

@alangpierce alangpierce merged commit 978e138 into alangpierce:main Oct 7, 2021
@alangpierce
Copy link
Owner

Looks like npm authentication is down right now, but I'll publish when it's back up.

@alangpierce
Copy link
Owner

Released as 3.20.2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Expected async keyword in function export
4 participants