diff --git a/.changeset/angry-mayflies-matter.md b/.changeset/angry-mayflies-matter.md new file mode 100644 index 000000000000..289fbf87b67a --- /dev/null +++ b/.changeset/angry-mayflies-matter.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: correctly validate `undefined` snippet params with default value diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/SnippetBlock.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/SnippetBlock.js index 7eb043aa5d11..f28f8c8a596c 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/SnippetBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/SnippetBlock.js @@ -21,6 +21,10 @@ export function SnippetBlock(node, context) { /** @type {Statement[]} */ const declarations = []; + if (dev) { + declarations.push(b.stmt(b.call('$.validate_snippet_args', b.spread(b.id('arguments'))))); + } + const transform = { ...context.state.transform }; const child_state = { ...context.state, transform }; @@ -30,12 +34,7 @@ export function SnippetBlock(node, context) { if (!argument) continue; if (argument.type === 'Identifier') { - args.push({ - type: 'AssignmentPattern', - left: argument, - right: b.id('$.noop') - }); - + args.push(b.assignment_pattern(argument, b.id('$.noop'))); transform[argument.name] = { read: b.call }; continue; @@ -66,29 +65,16 @@ export function SnippetBlock(node, context) { } } } - if (dev) { - declarations.unshift( - b.stmt( - b.call( - '$.validate_snippet_args', - .../** @type {Identifier[]} */ ( - args.map((arg) => (arg?.type === 'Identifier' ? arg : arg?.left)) - ) - ) - ) - ); - } + body = b.block([ ...declarations, .../** @type {BlockStatement} */ (context.visit(node.body, child_state)).body ]); - /** @type {Expression} */ - let snippet = b.arrow(args, body); - - if (dev) { - snippet = b.call('$.wrap_snippet', b.id(context.state.analysis.name), snippet); - } + // in dev we use a FunctionExpression (not arrow function) so we can use `arguments` + let snippet = dev + ? b.call('$.wrap_snippet', b.id(context.state.analysis.name), b.function(null, args, body)) + : b.arrow(args, body); const declaration = b.const(node.expression, snippet); diff --git a/packages/svelte/tests/runtime-runes/samples/validate-undefined-snippet-default-arg/_config.js b/packages/svelte/tests/runtime-runes/samples/validate-undefined-snippet-default-arg/_config.js new file mode 100644 index 000000000000..bddb75e67785 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/validate-undefined-snippet-default-arg/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: `
default
` +}); diff --git a/packages/svelte/tests/runtime-runes/samples/validate-undefined-snippet-default-arg/main.svelte b/packages/svelte/tests/runtime-runes/samples/validate-undefined-snippet-default-arg/main.svelte new file mode 100644 index 000000000000..3f00eba46bc2 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/validate-undefined-snippet-default-arg/main.svelte @@ -0,0 +1,5 @@ +{#snippet test(param = "default")} +{param}
+{/snippet} + +{@render test()} \ No newline at end of file