Skip to content

Commit 4285e6d

Browse files
authored
fix: prevent snippet children conflict (#10700)
closes #10385
1 parent eedb593 commit 4285e6d

File tree

6 files changed

+62
-3
lines changed

6 files changed

+62
-3
lines changed

.changeset/wet-wombats-repeat.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 snippet children conflict

packages/svelte/src/compiler/errors.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,9 @@ const slots = {
296296
/** @param {string} name @param {string} component */
297297
'duplicate-slot-name': (name, component) => `Duplicate slot name '${name}' in <${component}>`,
298298
'invalid-default-slot-content': () =>
299-
`Found default slot content alongside an explicit slot="default"`
299+
`Found default slot content alongside an explicit slot="default"`,
300+
'conflicting-children-snippet': () =>
301+
`Cannot use explicit children snippet at the same time as implicit children content. Remove either the non-whitespace content or the children snippet block`
300302
};
301303

302304
/** @satisfies {Errors} */

packages/svelte/src/compiler/phases/2-analyze/validation.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,24 @@ const validation = {
521521
);
522522
}
523523
},
524+
SnippetBlock(node, { path }) {
525+
if (node.expression.name !== 'children') return;
526+
const parent = path.at(-2);
527+
if (!parent) return;
528+
if (
529+
parent.type === 'Component' ||
530+
parent.type === 'SvelteComponent' ||
531+
parent.type === 'SvelteSelf'
532+
) {
533+
if (
534+
parent.fragment.nodes.some(
535+
(node) => node.type !== 'SnippetBlock' && (node.type !== 'Text' || node.data.trim())
536+
)
537+
) {
538+
error(node, 'conflicting-children-snippet');
539+
}
540+
}
541+
},
524542
SvelteHead(node) {
525543
const attribute = node.attributes[0];
526544
if (attribute) {

packages/svelte/src/compiler/phases/3-transform/utils.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import {
22
regex_ends_with_whitespaces,
33
regex_not_whitespace,
4-
regex_starts_with_whitespaces,
5-
regex_whitespaces_strict
4+
regex_starts_with_whitespaces
65
} from '../patterns.js';
76
import * as b from '../../utils/builders.js';
87
import { walk } from 'zimmerframe';
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
error: {
5+
code: 'conflicting-children-snippet',
6+
message:
7+
'Cannot use explicit children snippet at the same time as implicit children content. Remove either the non-whitespace content or the children snippet block',
8+
position: [320, 353]
9+
}
10+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!-- ok -->
2+
<Button>
3+
hello
4+
</Button>
5+
<Button>
6+
{#snippet children()}hi{/snippet}
7+
</Button>
8+
<Button>
9+
hello
10+
{#snippet foo()}x{/snippet}
11+
</Button>
12+
<Button>
13+
{#snippet children()}hi{/snippet}
14+
{#snippet foo()}x{/snippet}
15+
</Button>
16+
<div>
17+
hello
18+
{#snippet children()}hi{/snippet}
19+
</div>
20+
21+
<!-- invalid -->
22+
<Button>
23+
hello
24+
{#snippet children()}hi{/snippet}
25+
</Button>

0 commit comments

Comments
 (0)