Skip to content

Commit 8de5605

Browse files
fix: prevent migrated snippet from shadow snippet prop (#14127)
1 parent 74a2c6b commit 8de5605

File tree

4 files changed

+97
-0
lines changed

4 files changed

+97
-0
lines changed

.changeset/silent-tigers-lay.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: prevent migrated snippet from shadow snippet prop

packages/svelte/src/compiler/migrate/index.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ export function migrate(source, { filename, use_ts } = {}) {
168168
legacy_imports: new Set(),
169169
script_insertions: new Set(),
170170
derived_components: new Map(),
171+
derived_conflicting_slots: new Map(),
171172
derived_labeled_statements: new Set(),
172173
has_svelte_self: false,
173174
uses_ts:
@@ -199,6 +200,7 @@ export function migrate(source, { filename, use_ts } = {}) {
199200
const need_script =
200201
state.legacy_imports.size > 0 ||
201202
state.derived_components.size > 0 ||
203+
state.derived_conflicting_slots.size > 0 ||
202204
state.script_insertions.size > 0 ||
203205
state.props.length > 0 ||
204206
analysis.uses_rest_props ||
@@ -365,6 +367,13 @@ export function migrate(source, { filename, use_ts } = {}) {
365367
);
366368
}
367369

370+
if (state.derived_conflicting_slots.size > 0) {
371+
str.appendRight(
372+
insertion_point,
373+
`\n${indent}${[...state.derived_conflicting_slots.entries()].map(([name, init]) => `const ${name} = $derived(${init});`).join(`\n${indent}`)}\n`
374+
);
375+
}
376+
368377
if (state.props.length > 0 && state.analysis.accessors) {
369378
str.appendRight(
370379
insertion_point,
@@ -414,6 +423,7 @@ export function migrate(source, { filename, use_ts } = {}) {
414423
* legacy_imports: Set<string>;
415424
* script_insertions: Set<string>;
416425
* derived_components: Map<string, string>;
426+
* derived_conflicting_slots: Map<string, string>;
417427
* derived_labeled_statements: Set<LabeledStatement>;
418428
* has_svelte_self: boolean;
419429
* uses_ts: boolean;
@@ -1133,6 +1143,7 @@ const template = {
11331143
let name = 'children';
11341144
let slot_name = 'default';
11351145
let slot_props = '{ ';
1146+
let aliased_slot_name;
11361147

11371148
for (const attr of node.attributes) {
11381149
if (attr.type === 'SpreadAttribute') {
@@ -1144,6 +1155,37 @@ const template = {
11441155

11451156
if (attr.name === 'name') {
11461157
slot_name = /** @type {any} */ (attr.value)[0].data;
1158+
// if some of the parents or this node itself har a slot
1159+
// attribute with the sane name of this slot
1160+
// we want to create a derived or the migrated snippet
1161+
// will shadow the slot prop
1162+
if (
1163+
path.some(
1164+
(parent) =>
1165+
(parent.type === 'RegularElement' ||
1166+
parent.type === 'SvelteElement' ||
1167+
parent.type === 'Component' ||
1168+
parent.type === 'SvelteComponent' ||
1169+
parent.type === 'SvelteFragment') &&
1170+
parent.attributes.some(
1171+
(attribute) =>
1172+
attribute.type === 'Attribute' &&
1173+
attribute.name === 'slot' &&
1174+
is_text_attribute(attribute) &&
1175+
attribute.value[0].data === slot_name
1176+
)
1177+
) ||
1178+
node.attributes.some(
1179+
(attribute) =>
1180+
attribute.type === 'Attribute' &&
1181+
attribute.name === 'slot' &&
1182+
is_text_attribute(attribute) &&
1183+
attribute.value[0].data === slot_name
1184+
)
1185+
) {
1186+
aliased_slot_name = `${slot_name}_render`;
1187+
state.derived_conflicting_slots.set(aliased_slot_name, slot_name);
1188+
}
11471189
} else {
11481190
const attr_value =
11491191
attr.value === true || Array.isArray(attr.value) ? attr.value : [attr.value];
@@ -1200,6 +1242,8 @@ const template = {
12001242
existing_prop.needs_refine_type = false;
12011243
}
12021244

1245+
name = aliased_slot_name ?? name;
1246+
12031247
if (node.fragment.nodes.length > 0) {
12041248
next();
12051249
state.str.update(
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{#if $$slots.label}
2+
<slot name="label" />
3+
{/if}
4+
<MyInput>
5+
<slot name="label" slot="label"/>
6+
</MyInput>
7+
<MyInput>
8+
<div slot="label">
9+
<MyComponent>
10+
<div slot="label">
11+
<slot name="label" />
12+
</div>
13+
</MyComponent>
14+
</div>
15+
</MyInput>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<script>
2+
/**
3+
* @typedef {Object} Props
4+
* @property {import('svelte').Snippet} [label]
5+
*/
6+
7+
/** @type {Props} */
8+
let { label } = $props();
9+
const label_render = $derived(label);
10+
11+
</script>
12+
13+
{#if label}
14+
{@render label?.()}
15+
{/if}
16+
<MyInput>
17+
{#snippet label()}
18+
{@render label_render?.()}
19+
{/snippet}
20+
</MyInput>
21+
<MyInput>
22+
{#snippet label()}
23+
<div >
24+
<MyComponent>
25+
{#snippet label()}
26+
<div >
27+
{@render label_render?.()}
28+
</div>
29+
{/snippet}
30+
</MyComponent>
31+
</div>
32+
{/snippet}
33+
</MyInput>

0 commit comments

Comments
 (0)