Skip to content

Commit

Permalink
fix: prevent migrated snippet from shadow snippet prop
Browse files Browse the repository at this point in the history
  • Loading branch information
paoloricciuti committed Nov 3, 2024
1 parent 8d0937a commit 06593a0
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/silent-tigers-lay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: prevent migrated snippet from shadow snippet prop
44 changes: 44 additions & 0 deletions packages/svelte/src/compiler/migrate/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ export function migrate(source, { filename, use_ts } = {}) {
legacy_imports: new Set(),
script_insertions: new Set(),
derived_components: new Map(),
derived_conflicting_slots: new Map(),
derived_labeled_statements: new Set(),
has_svelte_self: false,
uses_ts:
Expand Down Expand Up @@ -199,6 +200,7 @@ export function migrate(source, { filename, use_ts } = {}) {
const need_script =
state.legacy_imports.size > 0 ||
state.derived_components.size > 0 ||
state.derived_conflicting_slots.size > 0 ||
state.script_insertions.size > 0 ||
state.props.length > 0 ||
analysis.uses_rest_props ||
Expand Down Expand Up @@ -365,6 +367,13 @@ export function migrate(source, { filename, use_ts } = {}) {
);
}

if (state.derived_conflicting_slots.size > 0) {
str.appendRight(
insertion_point,
`\n${indent}${[...state.derived_conflicting_slots.entries()].map(([name, init]) => `const ${name} = $derived(${init});`).join(`\n${indent}`)}\n`
);
}

if (state.props.length > 0 && state.analysis.accessors) {
str.appendRight(
insertion_point,
Expand Down Expand Up @@ -414,6 +423,7 @@ export function migrate(source, { filename, use_ts } = {}) {
* legacy_imports: Set<string>;
* script_insertions: Set<string>;
* derived_components: Map<string, string>;
* derived_conflicting_slots: Map<string, string>;
* derived_labeled_statements: Set<LabeledStatement>;
* has_svelte_self: boolean;
* uses_ts: boolean;
Expand Down Expand Up @@ -1106,6 +1116,7 @@ const template = {
let name = 'children';
let slot_name = 'default';
let slot_props = '{ ';
let aliased_slot_name;

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

if (attr.name === 'name') {
slot_name = /** @type {any} */ (attr.value)[0].data;
// if some of the parents or this node itself har a slot
// attribute with the sane name of this slot
// we want to create a derived or the migrated snippet
// will shadow the slot prop
if (
path.some(
(parent) =>
(parent.type === 'RegularElement' ||
parent.type === 'SvelteElement' ||
parent.type === 'Component' ||
parent.type === 'SvelteComponent' ||
parent.type === 'SvelteFragment') &&
parent.attributes.some(
(attribute) =>
attribute.type === 'Attribute' &&
attribute.name === 'slot' &&
is_text_attribute(attribute) &&
attribute.value[0].data === slot_name
)
) ||
node.attributes.some(
(attribute) =>
attribute.type === 'Attribute' &&
attribute.name === 'slot' &&
is_text_attribute(attribute) &&
attribute.value[0].data === slot_name
)
) {
aliased_slot_name = `${slot_name}_render`;
state.derived_conflicting_slots.set(aliased_slot_name, slot_name);
}
} else {
const attr_value =
attr.value === true || Array.isArray(attr.value) ? attr.value : [attr.value];
Expand Down Expand Up @@ -1173,6 +1215,8 @@ const template = {
existing_prop.needs_refine_type = false;
}

name = aliased_slot_name ?? name;

if (node.fragment.nodes.length > 0) {
next();
state.str.update(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{#if $$slots.label}
<slot name="label" />
{/if}
<MyInput>
<slot name="label" slot="label"/>
</MyInput>
<MyInput>
<div slot="label">
<MyComponent>
<div slot="label">
<slot name="label" />
</div>
</MyComponent>
</div>
</MyInput>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script>
/**
* @typedef {Object} Props
* @property {import('svelte').Snippet} [label]
*/
/** @type {Props} */
let { label } = $props();
const label_render = $derived(label);
</script>

{#if label}
{@render label?.()}
{/if}
<MyInput>
{#snippet label()}
{@render label_render?.()}
{/snippet}
</MyInput>
<MyInput>
{#snippet label()}
<div >
<MyComponent>
{#snippet label()}
<div >
{@render label_render?.()}
</div>
{/snippet}
</MyComponent>
</div>
{/snippet}
</MyInput>

0 comments on commit 06593a0

Please sign in to comment.