From 4418ba6535064c4f04540670ddc50858a2075621 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Fri, 17 Nov 2023 12:33:11 +0100 Subject: [PATCH] fix: add top level snippets to instance scope (#9467) fixes #9460 --- .changeset/rich-sheep-burn.md | 5 ++++ packages/svelte/src/compiler/phases/scope.js | 28 ++++++++----------- .../samples/snippet-hoisting/_config.js | 9 ++++++ .../samples/snippet-hoisting/main.svelte | 13 +++++++++ 4 files changed, 38 insertions(+), 17 deletions(-) create mode 100644 .changeset/rich-sheep-burn.md create mode 100644 packages/svelte/tests/runtime-runes/samples/snippet-hoisting/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/snippet-hoisting/main.svelte diff --git a/.changeset/rich-sheep-burn.md b/.changeset/rich-sheep-burn.md new file mode 100644 index 000000000000..4a2128d6aa56 --- /dev/null +++ b/.changeset/rich-sheep-burn.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: add top level snippets to instance scope diff --git a/packages/svelte/src/compiler/phases/scope.js b/packages/svelte/src/compiler/phases/scope.js index bcb30d7f114b..5c18e78f7c24 100644 --- a/packages/svelte/src/compiler/phases/scope.js +++ b/packages/svelte/src/compiler/phases/scope.js @@ -273,15 +273,6 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) { next({ scope }); }; - /** - * @type {import('zimmerframe').Visitor} - */ - const CreateBlock = (node, { state, next }) => { - const scope = state.scope.child(); - scopes.set(node, scope); - next({ scope }); - }; - /** * @param {import('#compiler').ElementLike} node * @param {Scope} parent @@ -566,18 +557,24 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) { }, SnippetBlock(node, context) { - state.scope.declare(node.expression, 'normal', 'function', node.expression); + // Special-case for root-level snippets: they become part of the instance scope + const is_top_level = !context.path.at(-2); + let scope = state.scope; + if (is_top_level) { + scope = /** @type {Scope} */ (parent); + } + scope.declare(node.expression, 'normal', 'function', node.expression); - const scope = state.scope.child(); - scopes.set(node, scope); + const child_scope = state.scope.child(); + scopes.set(node, child_scope); if (node.context) { for (const id of extract_identifiers(node.context)) { - scope.declare(id, 'each', 'let'); + child_scope.declare(id, 'each', 'let'); } } - context.next({ scope }); + context.next({ scope: child_scope }); }, Fragment: (node, context) => { @@ -586,9 +583,6 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) { context.next({ scope }); }, - // TODO this will be unnecessary when we switch to fragments - IfBlock: CreateBlock, - BindDirective(node, context) { updates.push([ context.state.scope, diff --git a/packages/svelte/tests/runtime-runes/samples/snippet-hoisting/_config.js b/packages/svelte/tests/runtime-runes/samples/snippet-hoisting/_config.js new file mode 100644 index 000000000000..24fcbed65947 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/snippet-hoisting/_config.js @@ -0,0 +1,9 @@ +import { ok, test } from '../../test'; + +export default test({ + test({ target }) { + const button = target.querySelector('button'); + ok(button); + button.click(); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/snippet-hoisting/main.svelte b/packages/svelte/tests/runtime-runes/samples/snippet-hoisting/main.svelte new file mode 100644 index 000000000000..8c871d3de487 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/snippet-hoisting/main.svelte @@ -0,0 +1,13 @@ + + +{#snippet snippet()}Hello{/snippet} + +