Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/ten-plants-carry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: don't spread away `$$slots` from `$props` is it's used
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** @import { VariableDeclaration, VariableDeclarator, Expression, CallExpression, Pattern, Identifier } from 'estree' */
/** @import { Binding } from '#compiler' */
/** @import { Context } from '../types.js' */
/** @import { ComponentAnalysis } from '../../../types.js' */
/** @import { Scope } from '../../../scope.js' */
import { build_fallback, extract_paths } from '../../../../utils/ast.js';
import * as b from '#compiler/builders';
Expand Down Expand Up @@ -50,20 +51,26 @@ export function VariableDeclaration(node, context) {
}
}
});

// if `$$slots` is declared separately, deconflict
const slots_name = /** @type {ComponentAnalysis} */ (context.state.analysis).uses_slots
? b.id('$$slots_')
: b.id('$$slots');

if (id.type === 'ObjectPattern' && has_rest) {
// If a rest pattern is used within an object pattern, we need to ensure we don't expose $$slots or $$events
id.properties.splice(
id.properties.length - 1,
0,
// @ts-ignore
b.prop('init', b.id('$$slots'), b.id('$$slots')),
b.prop('init', b.id('$$slots'), slots_name),
b.prop('init', b.id('$$events'), b.id('$$events'))
);
} else if (id.type === 'Identifier') {
// If $props is referenced as an identifier, we need to ensure we don't expose $$slots or $$events as properties
// on the identifier reference
id = b.object_pattern([
b.prop('init', b.id('$$slots'), b.id('$$slots')),
b.prop('init', b.id('$$slots'), slots_name),
b.prop('init', b.id('$$events'), b.id('$$events')),
b.rest(b.id(id.name))
]);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script>
const props = $props();
</script>

<p>{Object.keys(props)}</p>

{#if $$slots.foo}
<p>foo exists</p>
{/if}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { test } from '../../test';

export default test({
html: `
<p>a</p>
<p>foo exists</p>
`
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script>
import Child from './Child.svelte';
</script>

<Child a="b">
<div slot="foo">foo</div>
</Child>