diff --git a/.changeset/shy-scissors-smile.md b/.changeset/shy-scissors-smile.md new file mode 100644 index 000000000000..b50108241e9c --- /dev/null +++ b/.changeset/shy-scissors-smile.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: properly validate snippet/slot interop diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index 8e545e2d0d29..574ec82c69b3 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -887,7 +887,12 @@ function serialize_inline_component(node, component_name, context, anchor = cont ]) ); - if (slot_name === 'default' && !has_children_prop) { + if ( + slot_name === 'default' && + !has_children_prop && + lets.length === 0 && + children.default.every((node) => node.type !== 'SvelteFragment') + ) { push_prop( b.init( 'children', @@ -1867,7 +1872,9 @@ export const template_visitors = { snippet_function = b.call( '$.validate_snippet', snippet_function, - args.length ? b.id('$$props') : undefined + args.length && callee.type === 'Identifier' && callee.name === 'children' + ? b.id('$$props') + : undefined ); } diff --git a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js index 687984b3950d..2445470a3d0b 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js @@ -959,7 +959,12 @@ function serialize_inline_component(node, expression, context) { ]) ); - if (slot_name === 'default' && !has_children_prop) { + if ( + slot_name === 'default' && + !has_children_prop && + lets.length === 0 && + children.default.every((node) => node.type !== 'SvelteFragment') + ) { push_prop( b.prop( 'init', @@ -1202,7 +1207,13 @@ const template_visitors = { const expression = /** @type {import('estree').Expression} */ (context.visit(callee)); const snippet_function = context.state.options.dev - ? b.call('$.validate_snippet', expression) + ? b.call( + '$.validate_snippet', + expression, + raw_args.length && callee.type === 'Identifier' && callee.name === 'children' + ? b.id('$$props') + : undefined + ) : expression; const snippet_args = raw_args.map((arg) => { diff --git a/packages/svelte/src/internal/shared/validate.js b/packages/svelte/src/internal/shared/validate.js index 1fb1644d97e0..12d852d53782 100644 --- a/packages/svelte/src/internal/shared/validate.js +++ b/packages/svelte/src/internal/shared/validate.js @@ -15,10 +15,13 @@ export function add_snippet_symbol(fn) { /** * Validate that the function handed to `{@render ...}` is a snippet function, and not some other kind of function. * @param {any} snippet_fn - * @param {Record | undefined} $$props Only passed if render tag receives arguments + * @param {Record | undefined} $$props Only passed if render tag receives arguments and is for the children prop */ export function validate_snippet(snippet_fn, $$props) { - if ($$props?.$$slots?.default || (snippet_fn && snippet_fn[snippet_symbol] !== true)) { + if ( + ($$props?.$$slots?.default && typeof $$props.$$slots.default !== 'boolean') || + (snippet_fn && snippet_fn[snippet_symbol] !== true) + ) { e.render_tag_invalid_argument(); } diff --git a/packages/svelte/tests/runtime-runes/samples/snippet-slot-no-error/_config.js b/packages/svelte/tests/runtime-runes/samples/snippet-slot-no-error/_config.js new file mode 100644 index 000000000000..ed0ead960bdb --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/snippet-slot-no-error/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/snippet-slot-no-error/inner.svelte b/packages/svelte/tests/runtime-runes/samples/snippet-slot-no-error/inner.svelte new file mode 100644 index 000000000000..c0d85745dda9 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/snippet-slot-no-error/inner.svelte @@ -0,0 +1,5 @@ + + +{@render children(true)} diff --git a/packages/svelte/tests/runtime-runes/samples/snippet-slot-no-error/main.svelte b/packages/svelte/tests/runtime-runes/samples/snippet-slot-no-error/main.svelte new file mode 100644 index 000000000000..b037aedea031 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/snippet-slot-no-error/main.svelte @@ -0,0 +1,5 @@ + + +I don't need to use the argument if I don't want to