fix: prevent migrated snippet from shadow snippet prop (#14127)

pull/13429/merge
Paolo Ricciuti 2 days ago committed by GitHub
parent 74a2c6b580
commit 8de5605b6a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: prevent migrated snippet from shadow snippet prop

@ -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:
@ -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 ||
@ -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,
@ -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;
@ -1133,6 +1143,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') {
@ -1144,6 +1155,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];
@ -1200,6 +1242,8 @@ const template = {
existing_prop.needs_refine_type = false;
}
name = aliased_slot_name ?? name;
if (node.fragment.nodes.length > 0) {
next();
state.str.update(

@ -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>

@ -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>
Loading…
Cancel
Save