Skip to content

Commit 06593a0

Browse files
committed
fix: prevent migrated snippet from shadow snippet prop
1 parent 8d0937a commit 06593a0

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;
@@ -1106,6 +1116,7 @@ const template = {
11061116
let name = 'children';
11071117
let slot_name = 'default';
11081118
let slot_props = '{ ';
1119+
let aliased_slot_name;
11091120

11101121
for (const attr of node.attributes) {
11111122
if (attr.type === 'SpreadAttribute') {
@@ -1117,6 +1128,37 @@ const template = {
11171128

11181129
if (attr.name === 'name') {
11191130
slot_name = /** @type {any} */ (attr.value)[0].data;
1131+
// if some of the parents or this node itself har a slot
1132+
// attribute with the sane name of this slot
1133+
// we want to create a derived or the migrated snippet
1134+
// will shadow the slot prop
1135+
if (
1136+
path.some(
1137+
(parent) =>
1138+
(parent.type === 'RegularElement' ||
1139+
parent.type === 'SvelteElement' ||
1140+
parent.type === 'Component' ||
1141+
parent.type === 'SvelteComponent' ||
1142+
parent.type === 'SvelteFragment') &&
1143+
parent.attributes.some(
1144+
(attribute) =>
1145+
attribute.type === 'Attribute' &&
1146+
attribute.name === 'slot' &&
1147+
is_text_attribute(attribute) &&
1148+
attribute.value[0].data === slot_name
1149+
)
1150+
) ||
1151+
node.attributes.some(
1152+
(attribute) =>
1153+
attribute.type === 'Attribute' &&
1154+
attribute.name === 'slot' &&
1155+
is_text_attribute(attribute) &&
1156+
attribute.value[0].data === slot_name
1157+
)
1158+
) {
1159+
aliased_slot_name = `${slot_name}_render`;
1160+
state.derived_conflicting_slots.set(aliased_slot_name, slot_name);
1161+
}
11201162
} else {
11211163
const attr_value =
11221164
attr.value === true || Array.isArray(attr.value) ? attr.value : [attr.value];
@@ -1173,6 +1215,8 @@ const template = {
11731215
existing_prop.needs_refine_type = false;
11741216
}
11751217

1218+
name = aliased_slot_name ?? name;
1219+
11761220
if (node.fragment.nodes.length > 0) {
11771221
next();
11781222
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)