From 67c3f696a029829f45fd9ae31a1dd3cfe141b958 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Wed, 15 Nov 2023 15:20:23 +0100 Subject: [PATCH 1/2] fix: add top level snippets to instance scope fixes #9460 --- .changeset/rich-sheep-burn.md | 5 +++ packages/svelte/src/compiler/phases/scope.js | 28 +++++++---------- .../_expected/client/input.svelte.js | 31 +++++++++++++++++++ .../_expected/server/input.svelte.js | 22 +++++++++++++ .../samples/snippet-hoisting/input.svelte | 11 +++++++ 5 files changed, 80 insertions(+), 17 deletions(-) create mode 100644 .changeset/rich-sheep-burn.md create mode 100644 packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/client/input.svelte.js create mode 100644 packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/server/input.svelte.js create mode 100644 packages/svelte/tests/snapshot/samples/snippet-hoisting/input.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/snapshot/samples/snippet-hoisting/_expected/client/input.svelte.js b/packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/client/input.svelte.js new file mode 100644 index 000000000000..37b7b9244068 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/client/input.svelte.js @@ -0,0 +1,31 @@ +// input.svelte (Svelte VERSION) +// Note: compiler output will change before 5.0 is released! +import "svelte/internal/disclose-version"; +import * as $ from "svelte/internal"; + +function log(_, snippet) { + console.log(snippet); +} + +var frag_1 = $.template(`Hello`, true); +var frag = $.template(``); + +export default function Input($$anchor, $$props) { + $.push($$props, false); + + /* Init */ + var button = $.open($$anchor, true, frag); + + function snippet($$anchor) { + /* Init */ + var fragment = $.open_frag($$anchor, true, frag_1); + + $.close_frag($$anchor, fragment); + } + + button.__click = [log, snippet]; + $.close($$anchor, button); + $.pop(); +} + +$.delegate(["click"]); \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/server/input.svelte.js b/packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/server/input.svelte.js new file mode 100644 index 000000000000..46a0310c845c --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/server/input.svelte.js @@ -0,0 +1,22 @@ +// input.svelte (Svelte VERSION) +// Note: compiler output will change before 5.0 is released! +import * as $ from "svelte/internal/server"; + +export default function Input($$payload, $$props) { + $.push(false); + + function log() { + console.log(snippet); + } + + function snippet($$payload) { + const anchor = $.create_anchor($$payload); + + $$payload.out += anchor; + $$payload.out += `Hello`; + $$payload.out += anchor; + } + + $$payload.out += ``; + $.pop(); +} \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/snippet-hoisting/input.svelte b/packages/svelte/tests/snapshot/samples/snippet-hoisting/input.svelte new file mode 100644 index 000000000000..3fa3bf930111 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/snippet-hoisting/input.svelte @@ -0,0 +1,11 @@ + + +{#snippet snippet()}Hello{/snippet} + + From be4e594cd5689abe02702ea6925e91e4e533b03a Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Thu, 16 Nov 2023 12:56:10 +0100 Subject: [PATCH 2/2] make it a runtime test --- .../samples/snippet-hoisting/_config.js | 9 ++++++ .../samples/snippet-hoisting/main.svelte | 13 ++++++++ .../_expected/client/input.svelte.js | 31 ------------------- .../_expected/server/input.svelte.js | 22 ------------- .../samples/snippet-hoisting/input.svelte | 11 ------- 5 files changed, 22 insertions(+), 64 deletions(-) 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 delete mode 100644 packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/client/input.svelte.js delete mode 100644 packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/server/input.svelte.js delete mode 100644 packages/svelte/tests/snapshot/samples/snippet-hoisting/input.svelte 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} + + diff --git a/packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/client/input.svelte.js b/packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/client/input.svelte.js deleted file mode 100644 index 37b7b9244068..000000000000 --- a/packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/client/input.svelte.js +++ /dev/null @@ -1,31 +0,0 @@ -// input.svelte (Svelte VERSION) -// Note: compiler output will change before 5.0 is released! -import "svelte/internal/disclose-version"; -import * as $ from "svelte/internal"; - -function log(_, snippet) { - console.log(snippet); -} - -var frag_1 = $.template(`Hello`, true); -var frag = $.template(``); - -export default function Input($$anchor, $$props) { - $.push($$props, false); - - /* Init */ - var button = $.open($$anchor, true, frag); - - function snippet($$anchor) { - /* Init */ - var fragment = $.open_frag($$anchor, true, frag_1); - - $.close_frag($$anchor, fragment); - } - - button.__click = [log, snippet]; - $.close($$anchor, button); - $.pop(); -} - -$.delegate(["click"]); \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/server/input.svelte.js b/packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/server/input.svelte.js deleted file mode 100644 index 46a0310c845c..000000000000 --- a/packages/svelte/tests/snapshot/samples/snippet-hoisting/_expected/server/input.svelte.js +++ /dev/null @@ -1,22 +0,0 @@ -// input.svelte (Svelte VERSION) -// Note: compiler output will change before 5.0 is released! -import * as $ from "svelte/internal/server"; - -export default function Input($$payload, $$props) { - $.push(false); - - function log() { - console.log(snippet); - } - - function snippet($$payload) { - const anchor = $.create_anchor($$payload); - - $$payload.out += anchor; - $$payload.out += `Hello`; - $$payload.out += anchor; - } - - $$payload.out += ``; - $.pop(); -} \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/snippet-hoisting/input.svelte b/packages/svelte/tests/snapshot/samples/snippet-hoisting/input.svelte deleted file mode 100644 index 3fa3bf930111..000000000000 --- a/packages/svelte/tests/snapshot/samples/snippet-hoisting/input.svelte +++ /dev/null @@ -1,11 +0,0 @@ - - -{#snippet snippet()}Hello{/snippet} - -