diff --git a/.changeset/chatty-cups-drop.md b/.changeset/chatty-cups-drop.md new file mode 100644 index 0000000000..282a9b25de --- /dev/null +++ b/.changeset/chatty-cups-drop.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: add support for `{@const}` inside snippet block diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index 73b6f2e86d..c083604b87 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -333,7 +333,7 @@ const compiler_options = { /** @satisfies {Errors} */ const const_tag = { 'invalid-const-placement': () => - `{@const} must be the immediate child of {#if}, {:else if}, {:else}, {#each}, {:then}, {:catch}, or ` + `{@const} must be the immediate child of {#snippet}, {#if}, {:else if}, {:else}, {#each}, {:then}, {:catch}, or ` }; /** @satisfies {Errors} */ diff --git a/packages/svelte/src/compiler/phases/2-analyze/validation.js b/packages/svelte/src/compiler/phases/2-analyze/validation.js index 8dad40e238..08402009ab 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/validation.js +++ b/packages/svelte/src/compiler/phases/2-analyze/validation.js @@ -476,6 +476,7 @@ export const validation = { grand_parent?.type !== 'SvelteComponent' && grand_parent?.type !== 'EachBlock' && grand_parent?.type !== 'AwaitBlock' && + grand_parent?.type !== 'SnippetBlock' && ((grand_parent?.type !== 'RegularElement' && grand_parent?.type !== 'SvelteElement') || !grand_parent.attributes.some((a) => a.type === 'Attribute' && a.name === 'slot'))) ) { diff --git a/packages/svelte/tests/runtime-runes/samples/snippet-const/_config.js b/packages/svelte/tests/runtime-runes/samples/snippet-const/_config.js new file mode 100644 index 0000000000..8867993dbb --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/snippet-const/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +export default test({ + html: ``, + async test({ assert, target }) { + const btn = target.querySelector('button'); + + assert.htmlEqual(target.innerHTML, ''); + + await btn?.click(); + assert.htmlEqual(target.innerHTML, ''); + + await btn?.click(); + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/snippet-const/main.svelte b/packages/svelte/tests/runtime-runes/samples/snippet-const/main.svelte new file mode 100644 index 0000000000..cad63519bf --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/snippet-const/main.svelte @@ -0,0 +1,10 @@ + + +{#snippet counter()} + {@const doubled = count * 2} + +{/snippet} + +{@render counter()} diff --git a/packages/svelte/tests/validator/samples/const-tag-placement-1/errors.json b/packages/svelte/tests/validator/samples/const-tag-placement-1/errors.json index f90fcf80ab..66ff86663f 100644 --- a/packages/svelte/tests/validator/samples/const-tag-placement-1/errors.json +++ b/packages/svelte/tests/validator/samples/const-tag-placement-1/errors.json @@ -1,7 +1,7 @@ [ { "code": "invalid-const-placement", - "message": "{@const} must be the immediate child of {#if}, {:else if}, {:else}, {#each}, {:then}, {:catch}, or ", + "message": "{@const} must be the immediate child of {#snippet}, {#if}, {:else if}, {:else}, {#each}, {:then}, {:catch}, or ", "start": { "line": 5, "column": 0 }, "end": { "line": 5, "column": 18 } } diff --git a/packages/svelte/tests/validator/samples/const-tag-placement-2/errors.json b/packages/svelte/tests/validator/samples/const-tag-placement-2/errors.json index 1124d0b4f8..6c14fdbaf7 100644 --- a/packages/svelte/tests/validator/samples/const-tag-placement-2/errors.json +++ b/packages/svelte/tests/validator/samples/const-tag-placement-2/errors.json @@ -1,7 +1,7 @@ [ { "code": "invalid-const-placement", - "message": "{@const} must be the immediate child of {#if}, {:else if}, {:else}, {#each}, {:then}, {:catch}, or ", + "message": "{@const} must be the immediate child of {#snippet}, {#if}, {:else if}, {:else}, {#each}, {:then}, {:catch}, or ", "start": { "line": 7, "column": 4 }, "end": { "line": 7, "column": 18 } }