From ae942cdcd9bd686e7b0394c8e91e63a31ff8fb5d Mon Sep 17 00:00:00 2001 From: edison Date: Fri, 17 Sep 2021 04:23:46 +0800 Subject: [PATCH] fix(compiler-sfc): support nested await statements (#4458) fix #4448 --- .../__snapshots__/compileScript.spec.ts.snap | 227 ++++++++++++++++++ .../__tests__/compileScript.spec.ts | 63 ++--- packages/compiler-sfc/src/compileScript.ts | 24 +- 3 files changed, 261 insertions(+), 53 deletions(-) diff --git a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap index c613cf50217..855ddd4a610 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap @@ -96,6 +96,233 @@ export default /*#__PURE__*/ Object.assign(__default__, { })" `; +exports[`SFC compile `, { refSugar: true }) @@ -1069,70 +1065,41 @@ const emit = defineEmits(['a', 'b']) expect(content).toMatch(`let __temp, __restore`) } expect(content).toMatch(`${shouldAsync ? `async ` : ``}setup(`) - if (typeof expected === 'string') { - expect(content).toMatch(expected) - } else { - expect(expected(content)).toBe(true) - } + assertCode(content) } test('expression statement', () => { - assertAwaitDetection( - `await foo`, - `;(([__temp,__restore]=_withAsyncContext(()=>(foo))),__temp=await __temp,__restore())` - ) + assertAwaitDetection(`await foo`) }) test('variable', () => { - assertAwaitDetection( - `const a = 1 + (await foo)`, - `1 + ((([__temp,__restore]=_withAsyncContext(()=>(foo))),__temp=await __temp,__restore(),__temp))` - ) + assertAwaitDetection(`const a = 1 + (await foo)`) }) test('ref', () => { - assertAwaitDetection( - `let a = $ref(1 + (await foo))`, - `1 + ((([__temp,__restore]=_withAsyncContext(()=>(foo))),__temp=await __temp,__restore(),__temp))` - ) + assertAwaitDetection(`let a = $ref(1 + (await foo))`) + }) + + test('nested await', () => { + assertAwaitDetection(`await (await foo)`) + assertAwaitDetection(`await ((await foo))`) + assertAwaitDetection(`await (await (await foo))`) }) test('nested statements', () => { - assertAwaitDetection(`if (ok) { await foo } else { await bar }`, code => { - return ( - code.includes( - `;(([__temp,__restore]=_withAsyncContext(()=>(foo))),__temp=await __temp,__restore())` - ) && - code.includes( - `;(([__temp,__restore]=_withAsyncContext(()=>(bar))),__temp=await __temp,__restore())` - ) - ) - }) + assertAwaitDetection(`if (ok) { await foo } else { await bar }`) }) test('should ignore await inside functions', () => { // function declaration - assertAwaitDetection( - `async function foo() { await bar }`, - `await bar`, - false - ) + assertAwaitDetection(`async function foo() { await bar }`, false) // function expression - assertAwaitDetection( - `const foo = async () => { await bar }`, - `await bar`, - false - ) + assertAwaitDetection(`const foo = async () => { await bar }`, false) // object method - assertAwaitDetection( - `const obj = { async method() { await bar }}`, - `await bar`, - false - ) + assertAwaitDetection(`const obj = { async method() { await bar }}`, false) // class method assertAwaitDetection( `const cls = class Foo { async method() { await bar }}`, - `await bar`, false ) }) diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts index cd189be5c8f..848bb322251 100644 --- a/packages/compiler-sfc/src/compileScript.ts +++ b/packages/compiler-sfc/src/compileScript.ts @@ -509,19 +509,33 @@ export function compileScript( /** * await foo() * --> - * (([__temp, __restore] = withAsyncContext(() => foo())),__temp=await __temp,__restore(),__temp) + * (([__temp, __restore] = withAsyncContext(async () => foo())),__temp=await __temp,__restore(),__temp) */ function processAwait(node: AwaitExpression, isStatement: boolean) { + const argumentStart = + node.argument.extra && node.argument.extra.parenthesized + ? (node.argument.extra.parenStart as number) + : node.argument.start! + + const argumentStr = source.slice( + argumentStart + startOffset, + node.argument.end! + startOffset + ) + + const containsNestedAwait = /\bawait\b/.test(argumentStr) + s.overwrite( node.start! + startOffset, - node.argument.start! + startOffset, - `${isStatement ? `;` : ``}(([__temp,__restore]=${helper( + argumentStart + startOffset, + `${isStatement ? `;` : ``}(\n ([__temp,__restore] = ${helper( `withAsyncContext` - )}(()=>(` + )}(${containsNestedAwait ? `async ` : ``}() => {\n return ` ) s.appendLeft( node.end! + startOffset, - `))),__temp=await __temp,__restore()${isStatement ? `` : `,__temp`})` + `\n })),\n __temp = await __temp,\n __restore()${ + isStatement ? `` : `,\n __temp` + }\n)` ) }