Create parser plugin "topLevelAwait"#10449
Conversation
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/11589/ |
|
Awesome! Should we add something like a flag using babel/packages/babel-preset-env/src/index.js Lines 160 to 166 in fcb77de |
|
We can do it when we have |
d7ba3c6 to
371115b
Compare
|
The failing test262 tests are fixed by tc39/test262#2388 |
371115b to
5f07ea2
Compare
| isAwaitAllowed(): boolean { | ||
| if (this.scope.inFunction) return this.scope.inAsync; | ||
| if (this.options.allowAwaitOutsideFunction) return true; | ||
| if (this.hasPlugin("topLevelAwait")) return this.inModule; |
There was a problem hiding this comment.
If top-level await is only valid in modules, should seeing one set sawUnambiguousESM? In other words, how should this behave with a sourceType of unambiguous? Currently, parsing await 0 with unambiguous yields an AST with sourceType of script, even though if you'd specified script it would not have parsed:
> require('./').parse('await 0', { plugins: ['topLevelAwait'], sourceType: 'unambiguous' }).program.sourceType
'script'
> require('./').parse('await 0', { plugins: ['topLevelAwait'], sourceType: 'script' }).program.sourceType
Thrown:
{ [SyntaxError: Unexpected token, expected ";" (1:6)
] pos: 6, loc: Position { line: 1, column: 6 } }
There was a problem hiding this comment.
This is tricky because, for exmaple, this is both a valid script and a valid module:
await
0I can set it to a module when await the next invalid token is on the same line.
c9112da to
00b0989
Compare
00b0989 to
94cfa86
Compare
| "column": 7 | ||
| } | ||
| }, | ||
| "sourceType": "script", |
There was a problem hiding this comment.
This is a script that contains an await expression? I thought that wasn’t allowed.
There was a problem hiding this comment.
We allow it using the allowAwaitOutsideFunction option, but it's not in the spec.
It's used, for example, by @babel/template users who might then wrap it in an async function.
| } | ||
|
|
||
| if (!this.scope.inFunction && !this.options.allowAwaitOutsideFunction) { | ||
| if (this.hasPrecedingLineBreak()) { |
There was a problem hiding this comment.
I think the following examples are also ambiguous
await + 0
await - 0
await ( 0 )
await [ 0 ]
await / 0 /uI am not sure if they are complete but we can always lookahead charcode to fix them.
| this.match(tt.plusMin) || | ||
| this.match(tt.parenL) || | ||
| this.match(tt.bracketL) || | ||
| this.match(tt.backQuote) || |
There was a problem hiding this comment.
Awesome! I missed await ` 0 ` .
I come up with a new case: If one turns on v8intrinsic, the following could be ambiguous, too.
await %a()|
I was initially going to add an |
Co-Authored-By: Brian Ng <bng412@gmail.com>
Fixes #1, Fixes #2It is a Stage 3 proposal: https://github.com/tc39/proposal-top-level-await
This is different from the
allowAwaitOutsideFunctionbecause the top-level-await proposal only allows it in modules, whileallowAwaitOutsideFunctionalso allows it in scripts. Also, I think that we need the plugin rather than the option for consistency with all the other plugins.Ref: babel/proposals#44, #7637