Skip to content

Commit 4418ba6

Browse files
authored
fix: add top level snippets to instance scope (#9467)
fixes #9460
1 parent 1beb5e8 commit 4418ba6

File tree

4 files changed

+38
-17
lines changed

4 files changed

+38
-17
lines changed

.changeset/rich-sheep-burn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: add top level snippets to instance scope

packages/svelte/src/compiler/phases/scope.js

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -273,15 +273,6 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
273273
next({ scope });
274274
};
275275

276-
/**
277-
* @type {import('zimmerframe').Visitor<import('#compiler').SvelteNode, State, import('#compiler').SvelteNode>}
278-
*/
279-
const CreateBlock = (node, { state, next }) => {
280-
const scope = state.scope.child();
281-
scopes.set(node, scope);
282-
next({ scope });
283-
};
284-
285276
/**
286277
* @param {import('#compiler').ElementLike} node
287278
* @param {Scope} parent
@@ -566,18 +557,24 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
566557
},
567558

568559
SnippetBlock(node, context) {
569-
state.scope.declare(node.expression, 'normal', 'function', node.expression);
560+
// Special-case for root-level snippets: they become part of the instance scope
561+
const is_top_level = !context.path.at(-2);
562+
let scope = state.scope;
563+
if (is_top_level) {
564+
scope = /** @type {Scope} */ (parent);
565+
}
566+
scope.declare(node.expression, 'normal', 'function', node.expression);
570567

571-
const scope = state.scope.child();
572-
scopes.set(node, scope);
568+
const child_scope = state.scope.child();
569+
scopes.set(node, child_scope);
573570

574571
if (node.context) {
575572
for (const id of extract_identifiers(node.context)) {
576-
scope.declare(id, 'each', 'let');
573+
child_scope.declare(id, 'each', 'let');
577574
}
578575
}
579576

580-
context.next({ scope });
577+
context.next({ scope: child_scope });
581578
},
582579

583580
Fragment: (node, context) => {
@@ -586,9 +583,6 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
586583
context.next({ scope });
587584
},
588585

589-
// TODO this will be unnecessary when we switch to fragments
590-
IfBlock: CreateBlock,
591-
592586
BindDirective(node, context) {
593587
updates.push([
594588
context.state.scope,
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { ok, test } from '../../test';
2+
3+
export default test({
4+
test({ target }) {
5+
const button = target.querySelector('button');
6+
ok(button);
7+
button.click();
8+
}
9+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script>
2+
function log() {
3+
// Test that the log function is not hoisted. If it was, this would make the test
4+
// pass still, but Vitest would error because it sees that there are unhandled errors
5+
snippet;
6+
}
7+
</script>
8+
9+
{#snippet snippet()}Hello{/snippet}
10+
11+
<button on:click={log}>
12+
log snippet
13+
</button>

0 commit comments

Comments
 (0)