fix: allow await expressions inside `{#await ...}` argument (#16514)

* fix: allow await expressions inside `{#await ...}` argument

* add test

* apply suggestion from review

---------

Co-authored-by: 7nik <kifiranet@gmail.com>
pull/16513/head
ComputerGuy 1 month ago committed by GitHub
parent 03f2e44757
commit 48f2fa22c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: allow await expressions inside `{#await ...}` argument

@ -1,7 +1,7 @@
/** @import { BlockStatement, Pattern, Statement } from 'estree' */
/** @import { AST } from '#compiler' */
/** @import { ComponentClientTransformState, ComponentContext } from '../types' */
import { extract_identifiers } from '../../../../utils/ast.js';
import { extract_identifiers, is_expression_async } from '../../../../utils/ast.js';
import * as b from '#compiler/builders';
import { create_derived } from '../utils.js';
import { get_value } from './shared/declarations.js';
@ -15,7 +15,10 @@ export function AwaitBlock(node, context) {
context.state.template.push_comment();
// Visit {#await <expression>} first to ensure that scopes are in the correct order
const expression = b.thunk(build_expression(context, node.expression, node.metadata.expression));
const expression = b.thunk(
build_expression(context, node.expression, node.metadata.expression),
node.metadata.expression.has_await
);
let then_block;
let catch_block;

@ -0,0 +1,43 @@
import { tick } from 'svelte';
import { test } from '../../test';
export default test({
async test({ assert, target }) {
const [reset, one, two, reject] = target.querySelectorAll('button');
await tick();
assert.htmlEqual(
target.innerHTML,
'<button>reset</button><button>one</button><button>two</button><button>reject</button> waiting'
);
one.click();
await tick();
assert.htmlEqual(
target.innerHTML,
'<button>reset</button><button>one</button><button>two</button><button>reject</button> one_res'
);
reset.click();
await tick();
assert.htmlEqual(
target.innerHTML,
'<button>reset</button><button>one</button><button>two</button><button>reject</button> waiting'
);
two.click();
await tick();
assert.htmlEqual(
target.innerHTML,
'<button>reset</button><button>one</button><button>two</button><button>reject</button> two_res'
);
reset.click();
reject.click();
await tick();
assert.htmlEqual(
target.innerHTML,
'<button>reset</button><button>one</button><button>two</button><button>reject</button> reject_catch'
);
}
});

@ -0,0 +1,22 @@
<script>
let deferred = $state(Promise.withResolvers());
</script>
<button onclick={() => deferred = Promise.withResolvers()}>reset</button>
<button onclick={() => deferred.resolve("one")}>one</button>
<button onclick={() => deferred.resolve("two")}>two</button>
<button onclick={() => deferred.reject("reject")}>reject</button>
<svelte:boundary>
{#await await deferred.promise + "_res"}
waiting
{:then res}
{res}
{:catch err}
{err}_catch
{/await}
{#snippet pending()}
<p>pending</p>
{/snippet}
</svelte:boundary>
Loading…
Cancel
Save