fix: allow accessing snippet in script tag (#15789)

* fix: allow accessing snippet in script tag

* branches are identical

* update test

* rename test

* fix validation (we were mutating the wrong array)

* tidy up

* remove submodule

* changeset

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/15790/head
Paolo Ricciuti 5 months ago committed by GitHub
parent 707682eaa9
commit 7f473f618d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: use function declaration for snippets in server output to avoid TDZ violation

@ -1,4 +1,4 @@
/** @import { ArrowFunctionExpression, BlockStatement, CallExpression } from 'estree' */
/** @import { BlockStatement } from 'estree' */
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../types.js' */
import { dev } from '../../../../state.js';
@ -9,27 +9,21 @@ import * as b from '#compiler/builders';
* @param {ComponentContext} context
*/
export function SnippetBlock(node, context) {
const body = /** @type {BlockStatement} */ (context.visit(node.body));
let fn = b.function_declaration(
node.expression,
[b.id('$$payload'), ...node.parameters],
/** @type {BlockStatement} */ (context.visit(node.body))
);
if (dev) {
body.body.unshift(b.stmt(b.call('$.validate_snippet_args', b.id('$$payload'))));
}
// @ts-expect-error - TODO remove this hack once $$render_inner for legacy bindings is gone
fn.___snippet = true;
/** @type {ArrowFunctionExpression | CallExpression} */
let fn = b.arrow([b.id('$$payload'), ...node.parameters], body);
const statements = node.metadata.can_hoist ? context.state.hoisted : context.state.init;
if (dev) {
fn = b.call('$.prevent_snippet_stringification', fn);
fn.body.body.unshift(b.stmt(b.call('$.validate_snippet_args', b.id('$$payload'))));
statements.push(b.stmt(b.call('$.prevent_snippet_stringification', fn.id)));
}
const declaration = b.declaration('const', [b.declarator(node.expression, fn)]);
// @ts-expect-error - TODO remove this hack once $$render_inner for legacy bindings is gone
fn.___snippet = true;
if (node.metadata.can_hoist) {
context.state.hoisted.push(declaration);
} else {
context.state.init.push(declaration);
}
statements.push(fn);
}

@ -0,0 +1,7 @@
import { test } from '../../test';
export default test({
compileOptions: {
dev: true
}
});

@ -0,0 +1,3 @@
export function fn(snippet) {
return snippet;
}

@ -0,0 +1,10 @@
<script>
import { fn } from "./fn.js";
let variable = $state("var");
fn(test);
</script>
{#snippet test()}
{variable}
{/snippet}

@ -0,0 +1,9 @@
import { test } from '../../test';
export default test({
compileOptions: {
dev: true
},
error: 'invalid_snippet_arguments'
});

@ -0,0 +1,7 @@
<script>
test();
</script>
{#snippet test()}
<p>hello</p>
{/snippet}

@ -1,9 +1,9 @@
import * as $ from 'svelte/internal/server';
import TextInput from './Child.svelte';
const snippet = ($$payload) => {
function snippet($$payload) {
$$payload.out += `<!---->Something`;
};
}
export default function Bind_component_snippet($$payload) {
let value = '';

Loading…
Cancel
Save