Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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/fix-layout-children-forwarding-warning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

fix: suppress false-positive inner content warning when children prop is forwarded to a child component
6 changes: 2 additions & 4 deletions packages/kit/src/exports/vite/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import {
} from './module_ids.js';
import { import_peer } from '../../utils/import.js';
import { compact } from '../../utils/array.js';
import { should_ignore } from './static_analysis/utils.js';
import { should_ignore, has_children } from './static_analysis/utils.js';

const cwd = posixify(process.cwd());

Expand Down Expand Up @@ -112,10 +112,8 @@ const warning_preprocessor = {
if (!filename) return;

const basename = path.basename(filename);
const has_children =
content.includes('<slot') || (isSvelte5Plus() && content.includes('{@render'));

if (basename.startsWith('+layout.') && !has_children) {
if (basename.startsWith('+layout.') && !has_children(content, isSvelte5Plus())) {
const message =
`\n${colors.bold().red(path.relative('.', filename))}\n` +
`\`<slot />\`${isSvelte5Plus() ? ' or `{@render ...}` tag' : ''}` +
Expand Down
17 changes: 17 additions & 0 deletions packages/kit/src/exports/vite/static_analysis/utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
/**
* Check if content has children rendering (slot, @render, or children prop forwarding)
* @param {string} content - The markup content
* @param {boolean} is_svelte_5_plus - Whether the project uses Svelte 5+
* @returns {boolean}
*/
export function has_children(content, is_svelte_5_plus) {
return (
content.includes('<slot') ||
(is_svelte_5_plus &&
(content.includes('{@render') ||
// children may be forwarded to a child component as a prop
content.includes('{children}') ||
content.includes('children={')))
);
}

/**
* Check if a match position is within a comment or a string
* @param {string} content - The full content
Expand Down
26 changes: 25 additions & 1 deletion packages/kit/src/exports/vite/static_analysis/utils.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect, test, vi } from 'vitest';
import path from 'node:path';
import { should_ignore } from './utils.js';
import { should_ignore, has_children } from './utils.js';

// Mock the colors module to avoid issues in tests
vi.mock('kleur', () => ({
Expand Down Expand Up @@ -153,3 +153,27 @@ test.each([
const result = should_warn_for_content(content, filename);
expect(result).toBe(should_warn);
});

test.each([
['layout with @render children()', '{@render children()}', true],
['layout with slot', '<slot />', true],
['layout with named slot', '<slot name="default" />', true],
[
'layout forwarding children as shorthand prop',
'<script>\n\tlet { children } = $props();\n</script>\n<Layout {children} />',
true
],
[
'layout forwarding children as explicit prop',
'<script>\n\tlet { children } = $props();\n</script>\n<Layout children={children} />',
true
],
[
'layout with no children handling',
'<script>\n\tlet { data } = $props();\n</script>\n<div>{data}</div>',
false
],
['empty layout', '', false]
])('layout children detection: %s', (_description, content, expected) => {
expect(has_children(content, true)).toBe(expected);
});
Loading