diff --git a/.changeset/giant-planets-shake.md b/.changeset/giant-planets-shake.md
new file mode 100644
index 0000000000..1197567abd
--- /dev/null
+++ b/.changeset/giant-planets-shake.md
@@ -0,0 +1,5 @@
+---
+"svelte": patch
+---
+
+fix: improve namespace inference when having `{@render}` and `{@html}` tags
diff --git a/packages/svelte/src/compiler/phases/3-transform/utils.js b/packages/svelte/src/compiler/phases/3-transform/utils.js
index 97fc45d7a8..3429748e29 100644
--- a/packages/svelte/src/compiler/phases/3-transform/utils.js
+++ b/packages/svelte/src/compiler/phases/3-transform/utils.js
@@ -5,6 +5,7 @@ import {
regex_whitespaces_strict
} from '../patterns.js';
import * as b from '../../utils/builders.js';
+import { walk } from 'zimmerframe';
/**
* @param {string} s
@@ -249,51 +250,49 @@ export function infer_namespace(namespace, parent, nodes, path) {
* @param {import('#compiler').Namespace | 'keep' | 'maybe_html'} namespace
*/
function check_nodes_for_namespace(nodes, namespace) {
+ /**
+ * @param {import('#compiler').SvelteElement | import('#compiler').RegularElement} node}
+ * @param {{stop: () => void}} context
+ */
+ const RegularElement = (node, { stop }) => {
+ if (!node.metadata.svg) {
+ namespace = 'html';
+ stop();
+ } else if (namespace === 'keep') {
+ namespace = 'svg';
+ }
+ };
+
for (const node of nodes) {
- if (node.type === 'RegularElement' || node.type === 'SvelteElement') {
- if (!node.metadata.svg) {
- namespace = 'html';
- break;
- } else if (namespace === 'keep') {
- namespace = 'svg';
- }
- } else if (
- (node.type === 'Text' && node.data.trim() !== '') ||
- node.type === 'HtmlTag' ||
- node.type === 'RenderTag'
- ) {
- namespace = 'maybe_html';
- } else if (node.type === 'EachBlock') {
- namespace = check_nodes_for_namespace(node.body.nodes, namespace);
- if (namespace === 'html') break;
- if (node.fallback) {
- namespace = check_nodes_for_namespace(node.fallback.nodes, namespace);
- if (namespace === 'html') break;
- }
- } else if (node.type === 'IfBlock') {
- namespace = check_nodes_for_namespace(node.consequent.nodes, namespace);
- if (namespace === 'html') break;
- if (node.alternate) {
- namespace = check_nodes_for_namespace(node.alternate.nodes, namespace);
- if (namespace === 'html') break;
- }
- } else if (node.type === 'AwaitBlock') {
- if (node.pending) {
- namespace = check_nodes_for_namespace(node.pending.nodes, namespace);
- if (namespace === 'html') break;
+ walk(
+ node,
+ {},
+ {
+ _(node, { next }) {
+ if (
+ node.type === 'EachBlock' ||
+ node.type === 'IfBlock' ||
+ node.type === 'AwaitBlock' ||
+ node.type === 'Fragment' ||
+ node.type === 'KeyBlock' ||
+ node.type === 'RegularElement' ||
+ node.type === 'SvelteElement' ||
+ node.type === 'Text'
+ ) {
+ next();
+ }
+ },
+ SvelteElement: RegularElement,
+ RegularElement,
+ Text(node) {
+ if (node.data.trim() !== '') {
+ namespace = 'maybe_html';
+ }
+ }
}
- if (node.then) {
- namespace = check_nodes_for_namespace(node.then.nodes, namespace);
- if (namespace === 'html') break;
- }
- if (node.catch) {
- namespace = check_nodes_for_namespace(node.catch.nodes, namespace);
- if (namespace === 'html') break;
- }
- } else if (node.type === 'KeyBlock') {
- namespace = check_nodes_for_namespace(node.fragment.nodes, namespace);
- if (namespace === 'html') break;
- }
+ );
+
+ if (namespace === 'html') return namespace;
}
return namespace;
diff --git a/packages/svelte/tests/runtime-runes/samples/svg-namespace-infer/Wrapper.svelte b/packages/svelte/tests/runtime-runes/samples/svg-namespace-infer/Wrapper.svelte
index 41f3f38fa8..5231a0c44a 100644
--- a/packages/svelte/tests/runtime-runes/samples/svg-namespace-infer/Wrapper.svelte
+++ b/packages/svelte/tests/runtime-runes/samples/svg-namespace-infer/Wrapper.svelte
@@ -2,12 +2,18 @@
{#if true}
true
-{:else}
- false
{/if}
-{#each Array(3).fill(0) as item, idx}
+{#each Array(2).fill(0) as item, idx}
{idx}
{/each}
-
+{@html 'html'}
+
+{@render test("snippet")}
+
+{#snippet test(text)}
+{text}
+{/snippet}
+
+
diff --git a/packages/svelte/tests/runtime-runes/samples/svg-namespace-infer/_config.js b/packages/svelte/tests/runtime-runes/samples/svg-namespace-infer/_config.js
index 46118026af..9ea299b21a 100644
--- a/packages/svelte/tests/runtime-runes/samples/svg-namespace-infer/_config.js
+++ b/packages/svelte/tests/runtime-runes/samples/svg-namespace-infer/_config.js
@@ -7,7 +7,8 @@ export default test({
true
0
1
- 2
+ html
+ snippet
`,
test({ assert, target }) {
@@ -18,7 +19,7 @@ export default test({
const text_elements = target.querySelectorAll('text');
- assert.equal(text_elements.length, 5);
+ assert.equal(text_elements.length, 6);
for (const { namespaceURI } of text_elements)
assert.equal(namespaceURI, 'http://www.w3.org/2000/svg');