Skip to content

Commit fdd009b

Browse files
committed
make validate_each_keys async-aware
1 parent 951d8e6 commit fdd009b

File tree

3 files changed

+75
-11
lines changed

3 files changed

+75
-11
lines changed

packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -312,14 +312,7 @@ export function EachBlock(node, context) {
312312
declarations.push(b.let(node.index, index));
313313
}
314314

315-
if (dev && node.metadata.keyed) {
316-
context.state.init.push(
317-
b.stmt(b.call('$.validate_each_keys', b.thunk(collection), key_function))
318-
);
319-
}
320-
321315
const { has_await } = node.metadata.expression;
322-
323316
const thunk = b.thunk(collection, has_await);
324317

325318
const render_args = [b.id('$$anchor'), item];
@@ -342,20 +335,34 @@ export function EachBlock(node, context) {
342335
}
343336

344337
if (has_await) {
338+
const statements = [b.stmt(b.call('$.each', ...args))];
339+
if (dev && node.metadata.keyed) {
340+
statements.unshift(
341+
b.stmt(
342+
b.call(
343+
'$.validate_each_keys',
344+
b.thunk(b.call('$.get', b.id('$$collection'))),
345+
key_function
346+
)
347+
)
348+
);
349+
}
345350
context.state.init.push(
346351
b.stmt(
347352
b.call(
348353
'$.async',
349354
context.state.node,
350355
b.array([thunk]),
351-
b.arrow(
352-
[context.state.node, b.id('$$collection')],
353-
b.block([b.stmt(b.call('$.each', ...args))])
354-
)
356+
b.arrow([context.state.node, b.id('$$collection')], b.block(statements))
355357
)
356358
)
357359
);
358360
} else {
361+
if (dev && node.metadata.keyed) {
362+
context.state.init.push(
363+
b.stmt(b.call('$.validate_each_keys', b.thunk(collection), key_function))
364+
);
365+
}
359366
context.state.init.push(b.stmt(b.call('$.each', ...args)));
360367
}
361368
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { tick } from 'svelte';
2+
import { deferred } from '../../../../src/internal/shared/utils.js';
3+
import { test } from '../../test';
4+
5+
/** @type {ReturnType<typeof deferred>} */
6+
let d;
7+
8+
export default test({
9+
compileOptions: {
10+
dev: true
11+
},
12+
html: `<p>pending</p>`,
13+
14+
get props() {
15+
d = deferred();
16+
17+
return {
18+
promise: d.promise
19+
};
20+
},
21+
22+
async test({ assert, target, component }) {
23+
d.resolve(['a', 'b', 'c']);
24+
await tick();
25+
assert.htmlEqual(target.innerHTML, '<p>a</p><p>b</p><p>c</p>');
26+
27+
d = deferred();
28+
component.promise = d.promise;
29+
await tick();
30+
assert.htmlEqual(target.innerHTML, '<p>a</p><p>b</p><p>c</p>');
31+
32+
d.resolve(['d', 'e', 'f', 'g']);
33+
await tick();
34+
assert.htmlEqual(target.innerHTML, '<p>d</p><p>e</p><p>f</p><p>g</p>');
35+
36+
d = deferred();
37+
component.promise = d.promise;
38+
d.resolve(['d', 'e', 'f', 'd']);
39+
await tick();
40+
assert.fail('should not allow duplicate keys');
41+
},
42+
43+
runtime_error: 'each_key_duplicate'
44+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script>
2+
let { promise } = $props();
3+
</script>
4+
5+
<svelte:boundary>
6+
{#each await promise as item (item)}
7+
<p>{item}</p>
8+
{/each}
9+
10+
{#snippet pending()}
11+
<p>pending</p>
12+
{/snippet}
13+
</svelte:boundary>

0 commit comments

Comments
 (0)