From 191245930831c37ce36cb19adc7474c8310f34b3 Mon Sep 17 00:00:00 2001
From: Rich Harris <rich.harris@vercel.com>
Date: Mon, 25 Nov 2024 14:03:28 -0500
Subject: [PATCH] chore: initialize snippet binding correctly (#14430)

---
 packages/svelte/src/compiler/phases/2-analyze/index.js      | 5 +++--
 .../svelte/src/compiler/phases/3-transform/client/utils.js  | 3 ++-
 packages/svelte/src/compiler/phases/scope.js                | 6 +++---
 packages/svelte/src/compiler/types/index.d.ts               | 3 ++-
 4 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js
index 0a61fdbd88d1..0d8caa0a4b62 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/index.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/index.js
@@ -287,6 +287,7 @@ export function analyze_component(root, source, options) {
 
 		const store_name = name.slice(1);
 		const declaration = instance.scope.get(store_name);
+		const init = /** @type {Node | undefined} */ (declaration?.initial);
 
 		// If we're not in legacy mode through the compiler option, assume the user
 		// is referencing a rune and not a global store.
@@ -295,9 +296,9 @@ export function analyze_component(root, source, options) {
 			!is_rune(name) ||
 			(declaration !== null &&
 				// const state = $state(0) is valid
-				(get_rune(declaration.initial, instance.scope) === null ||
+				(get_rune(init, instance.scope) === null ||
 					// rune-line names received as props are valid too (but we have to protect against $props as store)
-					(store_name !== 'props' && get_rune(declaration.initial, instance.scope) === '$props')) &&
+					(store_name !== 'props' && get_rune(init, instance.scope) === '$props')) &&
 				// allow `import { derived } from 'svelte/store'` in the same file as `const x = $derived(..)` because one is not a subscription to the other
 				!(
 					name === '$derived' &&
diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js
index 0b49d18ee922..de821bbc45c7 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js
@@ -259,7 +259,8 @@ export function should_proxy(node, scope) {
 			binding.initial.type !== 'FunctionDeclaration' &&
 			binding.initial.type !== 'ClassDeclaration' &&
 			binding.initial.type !== 'ImportDeclaration' &&
-			binding.initial.type !== 'EachBlock'
+			binding.initial.type !== 'EachBlock' &&
+			binding.initial.type !== 'SnippetBlock'
 		) {
 			return should_proxy(binding.initial, null);
 		}
diff --git a/packages/svelte/src/compiler/phases/scope.js b/packages/svelte/src/compiler/phases/scope.js
index 0542a20708e9..454bb8c34eee 100644
--- a/packages/svelte/src/compiler/phases/scope.js
+++ b/packages/svelte/src/compiler/phases/scope.js
@@ -75,7 +75,7 @@ export class Scope {
 	 * @param {Identifier} node
 	 * @param {Binding['kind']} kind
 	 * @param {DeclarationKind} declaration_kind
-	 * @param {null | Expression | FunctionDeclaration | ClassDeclaration | ImportDeclaration | AST.EachBlock} initial
+	 * @param {null | Expression | FunctionDeclaration | ClassDeclaration | ImportDeclaration | AST.EachBlock | AST.SnippetBlock} initial
 	 * @returns {Binding}
 	 */
 	declare(node, kind, declaration_kind, initial = null) {
@@ -632,7 +632,7 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
 			if (is_top_level) {
 				scope = /** @type {Scope} */ (parent);
 			}
-			scope.declare(node.expression, 'normal', 'function', node.expression);
+			scope.declare(node.expression, 'normal', 'function', node);
 
 			const child_scope = state.scope.child();
 			scopes.set(node, child_scope);
@@ -726,7 +726,7 @@ export function set_scope(node, { next, state }) {
 
 /**
  * Returns the name of the rune if the given expression is a `CallExpression` using a rune.
- * @param {Node | AST.EachBlock | null | undefined} node
+ * @param {Node | null | undefined} node
  * @param {Scope} scope
  */
 export function get_rune(node, scope) {
diff --git a/packages/svelte/src/compiler/types/index.d.ts b/packages/svelte/src/compiler/types/index.d.ts
index 8a45f2d4fd84..f8aa3db69ddd 100644
--- a/packages/svelte/src/compiler/types/index.d.ts
+++ b/packages/svelte/src/compiler/types/index.d.ts
@@ -291,7 +291,8 @@ export interface Binding {
 		| FunctionDeclaration
 		| ClassDeclaration
 		| ImportDeclaration
-		| AST.EachBlock;
+		| AST.EachBlock
+		| AST.SnippetBlock;
 	is_called: boolean;
 	references: { node: Identifier; path: SvelteNode[] }[];
 	mutated: boolean;