Skip to content

Commit

Permalink
fix: check that snippet is not rendered as a component (#9423)
Browse files Browse the repository at this point in the history
Co-authored-by: Rich Harris <[email protected]>
  • Loading branch information
dummdidumm and Rich-Harris authored Nov 13, 2023
1 parent 1fd77d7 commit 9aa06bd
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/good-pianos-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: check that snippet is not rendered as a component
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,14 @@ function serialize_inline_component(node, component_name, context) {
b.thunk(b.array(props_and_spreads.map((p) => (Array.isArray(p) ? b.object(p) : p))))
);
/** @param {import('estree').Identifier} node_id */
let fn = (node_id) => b.call(component_name, node_id, props_expression);
let fn = (node_id) =>
b.call(
context.state.options.dev
? b.call('$.validate_component', b.id(component_name))
: component_name,
node_id,
props_expression
);

if (bind_this !== null) {
const prev = fn;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,12 @@ function serialize_inline_component(node, component_name, context) {
/** @type {import('estree').Statement} */
let statement = b.stmt(
(typeof component_name === 'string' ? b.call : b.maybe_call)(
component_name,
context.state.options.dev
? b.call(
'$.validate_component',
typeof component_name === 'string' ? b.id(component_name) : component_name
)
: component_name,
b.id('$$payload'),
props_expression
)
Expand Down
17 changes: 14 additions & 3 deletions packages/svelte/src/internal/client/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,13 @@ export function loop_guard(timeout) {
};
}

const symbol = Symbol.for('svelte.snippet');
const snippet_symbol = Symbol.for('svelte.snippet');

/**
* @param {any} fn
*/
export function add_snippet_symbol(fn) {
fn[symbol] = true;
fn[snippet_symbol] = true;
return fn;
}

Expand All @@ -117,11 +117,22 @@ export function add_snippet_symbol(fn) {
* @param {any} snippet_fn
*/
export function validate_snippet(snippet_fn) {
if (snippet_fn[symbol] !== true) {
if (snippet_fn[snippet_symbol] !== true) {
throw new Error(
'The argument to `{@render ...}` must be a snippet function, not a component or some other kind of function. ' +
'If you want to dynamically render one snippet or another, use `$derived` and pass its result to `{@render ...}`.'
);
}
return snippet_fn;
}

/**
* Validate that the function behind `<Component />` isn't a snippet.
* @param {any} component_fn
*/
export function validate_component(component_fn) {
if (component_fn?.[snippet_symbol] === true) {
throw new Error('A snippet must be rendered with `{@render ...}`');
}
return component_fn;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { test } from '../../test';

export default test({
compileOptions: {
dev: true
},
error: 'A snippet must be rendered with `{@render ...}`'
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{#snippet Foo()}
<p>hello</p>
{/snippet}

<Foo />

1 comment on commit 9aa06bd

@vercel
Copy link

@vercel vercel bot commented on 9aa06bd Nov 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

svelte-5-preview – ./sites/svelte-5-preview

svelte-octane.vercel.app
svelte-5-preview-svelte.vercel.app
svelte-5-preview.vercel.app
svelte-5-preview-git-main-svelte.vercel.app

Please sign in to comment.