fix: error if `each` block has `key` but no `as` clause (#16966)

pull/15673/merge
Rich Harris 1 month ago committed by GitHub
parent 7d977fad88
commit 9b5fb3f430
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: error if `each` block has `key` but no `as` clause

@ -453,6 +453,12 @@ This turned out to be buggy and unpredictable, particularly when working with de
{/each} {/each}
``` ```
### each_key_without_as
```
An `{#each ...}` block without an `as` clause cannot have a key
```
### effect_invalid_placement ### effect_invalid_placement
``` ```

@ -179,6 +179,10 @@ The same applies to components:
> `%type%` name cannot be empty > `%type%` name cannot be empty
## each_key_without_as
> An `{#each ...}` block without an `as` clause cannot have a key
## element_invalid_closing_tag ## element_invalid_closing_tag
> `</%name%>` attempted to close an element that was not open > `</%name%>` attempted to close an element that was not open

@ -992,7 +992,7 @@ export function const_tag_invalid_placement(node) {
* @returns {never} * @returns {never}
*/ */
export function const_tag_invalid_reference(node, name) { export function const_tag_invalid_reference(node, name) {
e(node, 'const_tag_invalid_reference', `The \`{@const ${name} = ...}\` declaration is not available in this snippet \nhttps://svelte.dev/e/const_tag_invalid_reference`); e(node, 'const_tag_invalid_reference', `The \`{@const ${name} = ...}\` declaration is not available in this snippet\nhttps://svelte.dev/e/const_tag_invalid_reference`);
} }
/** /**
@ -1023,6 +1023,15 @@ export function directive_missing_name(node, type) {
e(node, 'directive_missing_name', `\`${type}\` name cannot be empty\nhttps://svelte.dev/e/directive_missing_name`); e(node, 'directive_missing_name', `\`${type}\` name cannot be empty\nhttps://svelte.dev/e/directive_missing_name`);
} }
/**
* An `{#each ...}` block without an `as` clause cannot have a key
* @param {null | number | NodeLike} node
* @returns {never}
*/
export function each_key_without_as(node) {
e(node, 'each_key_without_as', `An \`{#each ...}\` block without an \`as\` clause cannot have a key\nhttps://svelte.dev/e/each_key_without_as`);
}
/** /**
* `</%name%>` attempted to close an element that was not open * `</%name%>` attempted to close an element that was not open
* @param {null | number | NodeLike} node * @param {null | number | NodeLike} node

@ -28,6 +28,10 @@ export function EachBlock(node, context) {
node.key.type !== 'Identifier' || !node.index || node.key.name !== node.index; node.key.type !== 'Identifier' || !node.index || node.key.name !== node.index;
} }
if (node.metadata.keyed && !node.context) {
e.each_key_without_as(node);
}
// evaluate expression in parent scope // evaluate expression in parent scope
context.visit(node.expression, { context.visit(node.expression, {
...context.state, ...context.state,

@ -4,7 +4,7 @@ export default test({
async: true, async: true,
error: { error: {
code: 'const_tag_invalid_reference', code: 'const_tag_invalid_reference',
message: 'The `{@const foo = ...}` declaration is not available in this snippet ', message: 'The `{@const foo = ...}` declaration is not available in this snippet',
position: [376, 379] position: [376, 379]
} }
}); });

@ -4,7 +4,7 @@ export default test({
async: true, async: true,
error: { error: {
code: 'const_tag_invalid_reference', code: 'const_tag_invalid_reference',
message: 'The `{@const foo = ...}` declaration is not available in this snippet ', message: 'The `{@const foo = ...}` declaration is not available in this snippet',
position: [298, 301] position: [298, 301]
} }
}); });

@ -0,0 +1,8 @@
import { test } from '../../test';
export default test({
error: {
code: 'each_key_without_as',
message: 'An `{#each ...}` block without an `as` clause cannot have a key'
}
});

@ -0,0 +1,7 @@
<script>
let items = [{ id: 3 }, { id: 2 }, { id: 1 }];
</script>
{#each items, i (items[i].id)}
<p>{items[i].id}</p>
{/each}
Loading…
Cancel
Save