vue3-core/packages/compiler-sfc/src/script/topLevelAwait.ts

70 lines
1.7 KiB
TypeScript

import { AwaitExpression } from '@babel/types'
import { ScriptCompileContext } from './context'
/**
* Support context-persistence between top-level await expressions:
*
* ```js
* const instance = getCurrentInstance()
* await foo()
* expect(getCurrentInstance()).toBe(instance)
* ```
*
* In the future we can potentially get rid of this when Async Context
* becomes generally available: https://github.com/tc39/proposal-async-context
*
* ```js
* // input
* await foo()
* // output
* ;(
* ([__temp,__restore] = withAsyncContext(() => foo())),
* await __temp,
* __restore()
* )
*
* // input
* const a = await foo()
* // output
* const a = (
* ([__temp, __restore] = withAsyncContext(() => foo())),
* __temp = await __temp,
* __restore(),
* __temp
* )
* ```
*/
export function processAwait(
ctx: ScriptCompileContext,
node: AwaitExpression,
needSemi: boolean,
isStatement: boolean
) {
const argumentStart =
node.argument.extra && node.argument.extra.parenthesized
? (node.argument.extra.parenStart as number)
: node.argument.start!
const startOffset = ctx.startOffset!
const argumentStr = ctx.descriptor.source.slice(
argumentStart + startOffset,
node.argument.end! + startOffset
)
const containsNestedAwait = /\bawait\b/.test(argumentStr)
ctx.s.overwrite(
node.start! + startOffset,
argumentStart + startOffset,
`${needSemi ? `;` : ``}(\n ([__temp,__restore] = ${ctx.helper(
`withAsyncContext`
)}(${containsNestedAwait ? `async ` : ``}() => `
)
ctx.s.appendLeft(
node.end! + startOffset,
`)),\n ${isStatement ? `` : `__temp = `}await __temp,\n __restore()${
isStatement ? `` : `,\n __temp`
}\n)`
)
}