diff --git a/.changeset/early-rockets-join.md b/.changeset/early-rockets-join.md
new file mode 100644
index 0000000000..c220930ef5
--- /dev/null
+++ b/.changeset/early-rockets-join.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: bail out if slot name changes and $$slots assigned to variable
diff --git a/packages/svelte/src/compiler/migrate/index.js b/packages/svelte/src/compiler/migrate/index.js
index b879c0b491..43d4720a75 100644
--- a/packages/svelte/src/compiler/migrate/index.js
+++ b/packages/svelte/src/compiler/migrate/index.js
@@ -418,7 +418,7 @@ const instance_script = {
state.str.remove(/** @type {number} */ (node.start), /** @type {number} */ (node.end));
}
},
- VariableDeclaration(node, { state, path, visit }) {
+ VariableDeclaration(node, { state, path, visit, next }) {
if (state.scope !== state.analysis.instance.scope) {
return;
}
@@ -439,12 +439,14 @@ const instance_script = {
bindings = state.scope.get_bindings(declarator);
} catch (e) {
// no bindings, so we can skip this
+ next();
continue;
}
const has_state = bindings.some((binding) => binding.kind === 'state');
const has_props = bindings.some((binding) => binding.kind === 'bindable_prop');
if (!has_state && !has_props) {
+ next();
continue;
}
@@ -491,25 +493,31 @@ const instance_script = {
const prop = state.props.find((prop) => prop.exported === (binding.prop_alias || name));
if (prop) {
+ next();
// $$Props type was used
prop.init = declarator.init
- ? state.str.original.substring(
- /** @type {number} */ (declarator.init.start),
- /** @type {number} */ (declarator.init.end)
- )
+ ? state.str
+ .snip(
+ /** @type {number} */ (declarator.init.start),
+ /** @type {number} */ (declarator.init.end)
+ )
+ .toString()
: '';
prop.bindable = binding.updated;
prop.exported = binding.prop_alias || name;
prop.type_only = false;
} else {
+ next();
state.props.push({
local: name,
exported: binding.prop_alias ? binding.prop_alias : name,
init: declarator.init
- ? state.str.original.substring(
- /** @type {number} */ (declarator.init.start),
- /** @type {number} */ (declarator.init.end)
- )
+ ? state.str
+ .snip(
+ /** @type {number} */ (declarator.init.start),
+ /** @type {number} */ (declarator.init.end)
+ )
+ .toString()
: '',
optional: !!declarator.init,
bindable: binding.updated,
@@ -1036,6 +1044,11 @@ const template = {
name = existing_prop.local;
} else if (slot_name !== 'default') {
name = state.scope.generate(slot_name);
+ if (name !== slot_name) {
+ throw new Error(
+ 'This migration would change the name of a slot making the component unusable'
+ );
+ }
}
if (!existing_prop) {
@@ -1462,7 +1475,12 @@ function handle_identifier(node, state, path) {
if (existing_prop) {
name = existing_prop.local;
} else if (name !== 'default') {
- name = state.scope.generate(name);
+ let new_name = state.scope.generate(name);
+ if (new_name !== name) {
+ throw new Error(
+ 'This migration would change the name of a slot making the component unusable'
+ );
+ }
}
name = name === 'default' ? 'children' : name;
@@ -1479,7 +1497,7 @@ function handle_identifier(node, state, path) {
// we start with any and delegate to when the slot
// is actually rendered (it might not happen in that case)
// any is still a safe bet
- type: `import('svelte').Snippet<[any]>}`,
+ type: `import('svelte').Snippet<[any]>`,
needs_refine_type: true
});
}
diff --git a/packages/svelte/tests/migrate/samples/$$slots-used-as-variable-$$props/input.svelte b/packages/svelte/tests/migrate/samples/$$slots-used-as-variable-$$props/input.svelte
new file mode 100644
index 0000000000..515e0fc906
--- /dev/null
+++ b/packages/svelte/tests/migrate/samples/$$slots-used-as-variable-$$props/input.svelte
@@ -0,0 +1,10 @@
+
+
+{#if showMessage}
+
+{/if}
+
+{$$props}
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/$$slots-used-as-variable-$$props/output.svelte b/packages/svelte/tests/migrate/samples/$$slots-used-as-variable-$$props/output.svelte
new file mode 100644
index 0000000000..72960b7e34
--- /dev/null
+++ b/packages/svelte/tests/migrate/samples/$$slots-used-as-variable-$$props/output.svelte
@@ -0,0 +1,12 @@
+
+
+{#if showMessage}
+ {@render props.message?.()}
+{/if}
+
+{props}
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/$$slots-used-as-variable/input.svelte b/packages/svelte/tests/migrate/samples/$$slots-used-as-variable/input.svelte
new file mode 100644
index 0000000000..94a29990ff
--- /dev/null
+++ b/packages/svelte/tests/migrate/samples/$$slots-used-as-variable/input.svelte
@@ -0,0 +1,11 @@
+
+
+{#if showMessage}
+
+{/if}
diff --git a/packages/svelte/tests/migrate/samples/$$slots-used-as-variable/output.svelte b/packages/svelte/tests/migrate/samples/$$slots-used-as-variable/output.svelte
new file mode 100644
index 0000000000..59c13366a0
--- /dev/null
+++ b/packages/svelte/tests/migrate/samples/$$slots-used-as-variable/output.svelte
@@ -0,0 +1,17 @@
+
+
+{#if showMessage}
+ {@render message?.()}
+{/if}
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/impossible-migrate-slot-change-name/_config.js b/packages/svelte/tests/migrate/samples/impossible-migrate-slot-change-name/_config.js
new file mode 100644
index 0000000000..ef889d5f23
--- /dev/null
+++ b/packages/svelte/tests/migrate/samples/impossible-migrate-slot-change-name/_config.js
@@ -0,0 +1,7 @@
+import { test } from '../../test';
+
+export default test({
+ logs: [
+ 'One or more `@migration-task` comments were added to `output.svelte`, please check them and complete the migration manually.'
+ ]
+});
diff --git a/packages/svelte/tests/migrate/samples/impossible-migrate-slot-change-name/input.svelte b/packages/svelte/tests/migrate/samples/impossible-migrate-slot-change-name/input.svelte
new file mode 100644
index 0000000000..810015eb98
--- /dev/null
+++ b/packages/svelte/tests/migrate/samples/impossible-migrate-slot-change-name/input.svelte
@@ -0,0 +1,5 @@
+
+
+
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/impossible-migrate-slot-change-name/output.svelte b/packages/svelte/tests/migrate/samples/impossible-migrate-slot-change-name/output.svelte
new file mode 100644
index 0000000000..2b6838a1d6
--- /dev/null
+++ b/packages/svelte/tests/migrate/samples/impossible-migrate-slot-change-name/output.svelte
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/impossible-migrate-slot-non-identifier/_config.js b/packages/svelte/tests/migrate/samples/impossible-migrate-slot-non-identifier/_config.js
new file mode 100644
index 0000000000..ef889d5f23
--- /dev/null
+++ b/packages/svelte/tests/migrate/samples/impossible-migrate-slot-non-identifier/_config.js
@@ -0,0 +1,7 @@
+import { test } from '../../test';
+
+export default test({
+ logs: [
+ 'One or more `@migration-task` comments were added to `output.svelte`, please check them and complete the migration manually.'
+ ]
+});
diff --git a/packages/svelte/tests/migrate/samples/impossible-migrate-slot-non-identifier/input.svelte b/packages/svelte/tests/migrate/samples/impossible-migrate-slot-non-identifier/input.svelte
new file mode 100644
index 0000000000..03428d30ac
--- /dev/null
+++ b/packages/svelte/tests/migrate/samples/impossible-migrate-slot-non-identifier/input.svelte
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/impossible-migrate-slot-non-identifier/output.svelte b/packages/svelte/tests/migrate/samples/impossible-migrate-slot-non-identifier/output.svelte
new file mode 100644
index 0000000000..6e5ab10310
--- /dev/null
+++ b/packages/svelte/tests/migrate/samples/impossible-migrate-slot-non-identifier/output.svelte
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/slots-multiple/input.svelte b/packages/svelte/tests/migrate/samples/slots-multiple/input.svelte
index 91c191990d..422e486c69 100644
--- a/packages/svelte/tests/migrate/samples/slots-multiple/input.svelte
+++ b/packages/svelte/tests/migrate/samples/slots-multiple/input.svelte
@@ -1,5 +1,2 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/slots-multiple/output.svelte b/packages/svelte/tests/migrate/samples/slots-multiple/output.svelte
index 5e561dd09f..c663f2bcdd 100644
--- a/packages/svelte/tests/migrate/samples/slots-multiple/output.svelte
+++ b/packages/svelte/tests/migrate/samples/slots-multiple/output.svelte
@@ -1,10 +1,7 @@
-
-
-{@render dashed_name?.()}
-{@render dashed_name?.()}
\ No newline at end of file
+
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/slots-with-$$props/input.svelte b/packages/svelte/tests/migrate/samples/slots-with-$$props/input.svelte
index 90812075c1..3ab9a4ff27 100644
--- a/packages/svelte/tests/migrate/samples/slots-with-$$props/input.svelte
+++ b/packages/svelte/tests/migrate/samples/slots-with-$$props/input.svelte
@@ -1,7 +1,7 @@
-{#if foo}
-
+{#if foos}
+
{/if}
{#if $$slots.bar}
@@ -13,8 +13,4 @@
{#if $$slots['default']}foo{/if}
-{#if $$slots['dashed-name']}foo{/if}
-
-
-
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/slots-with-$$props/output.svelte b/packages/svelte/tests/migrate/samples/slots-with-$$props/output.svelte
index c40d990157..c76c7d8283 100644
--- a/packages/svelte/tests/migrate/samples/slots-with-$$props/output.svelte
+++ b/packages/svelte/tests/migrate/samples/slots-with-$$props/output.svelte
@@ -1,14 +1,12 @@
-{#if foo}
- {@render props.foo_1?.({ foo, })}
+{#if foos}
+ {@render props.foo?.({ foo: foos, })}
{/if}
{#if props.bar}
@@ -20,8 +18,4 @@
{#if props.children}foo{/if}
-{#if props.dashed_name}foo{/if}
-
-{@render props.dashed_name?.()}
-
{@render props.children?.({ header: "something", title: props.cool, id, })}
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/slots/input.svelte b/packages/svelte/tests/migrate/samples/slots/input.svelte
index 3fea1b46f0..d9f3a8065b 100644
--- a/packages/svelte/tests/migrate/samples/slots/input.svelte
+++ b/packages/svelte/tests/migrate/samples/slots/input.svelte
@@ -1,7 +1,7 @@
-{#if foo}
-
+{#if foos}
+
{/if}
{#if $$slots.bar}
@@ -13,8 +13,4 @@
{#if $$slots['default']}foo{/if}
-{#if $$slots['dashed-name']}foo{/if}
-
-
-
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/slots/output.svelte b/packages/svelte/tests/migrate/samples/slots/output.svelte
index 9c56dbcf43..30fdf8dfbe 100644
--- a/packages/svelte/tests/migrate/samples/slots/output.svelte
+++ b/packages/svelte/tests/migrate/samples/slots/output.svelte
@@ -1,17 +1,12 @@
-{#if foo}
- {@render foo_1?.({ foo, })}
+{#if foos}
+ {@render foo?.({ foo: foos, })}
{/if}
{#if bar}
@@ -23,8 +18,4 @@
{#if children}foo{/if}
-{#if dashed_name}foo{/if}
-
-{@render dashed_name?.()}
-
{@render children?.({ header: "something", title: my_title, id, })}
\ No newline at end of file