Skip to content

Commit aa2654d

Browse files
committed
fix: ensure if block paths retain correct template namespacing
1 parent 7aa80fc commit aa2654d

File tree

2 files changed

+54
-3
lines changed

2 files changed

+54
-3
lines changed

.changeset/giant-moons-accept.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: ensure if block paths retain correct template namespacing

packages/svelte/src/compiler/phases/3-transform/client/visitors/IfBlock.js

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,42 @@
11
/** @import { BlockStatement, Expression } from 'estree' */
2-
/** @import { AST } from '#compiler' */
2+
/** @import { AST, Namespace } from '#compiler' */
33
/** @import { ComponentContext } from '../types' */
44
import * as b from '../../../../utils/builders.js';
55

6+
/**
7+
* @param {AST.Fragment} fragment
8+
* @return {Namespace}
9+
*/
10+
function get_namespace(fragment) {
11+
const elements = fragment.nodes.filter((n) => n.type === 'RegularElement');
12+
/** @type {Namespace | null} */
13+
let namespace = null;
14+
15+
// Check the elements within the fragment and look for consistent namespaces.
16+
// If we have no namespaces or they are mixed, then fallback to `html`
17+
for (const element of elements) {
18+
const metadata = element.metadata;
19+
20+
if (metadata.mathml) {
21+
if (namespace === null || namespace === 'mathml') {
22+
namespace = 'mathml';
23+
} else {
24+
namespace = 'html';
25+
}
26+
} else if (metadata.svg) {
27+
if (namespace === null || namespace === 'svg') {
28+
namespace = 'svg';
29+
} else {
30+
namespace = 'html';
31+
}
32+
} else {
33+
namespace = 'html';
34+
}
35+
}
36+
37+
return namespace ?? 'html';
38+
}
39+
640
/**
741
* @param {AST.IfBlock} node
842
* @param {ComponentContext} context
@@ -11,15 +45,27 @@ export function IfBlock(node, context) {
1145
context.state.template.push('<!>');
1246
const statements = [];
1347

14-
const consequent = /** @type {BlockStatement} */ (context.visit(node.consequent));
48+
const consequent_namespace = get_namespace(node.consequent);
49+
const consequent = /** @type {BlockStatement} */ (
50+
context.visit(node.consequent, {
51+
...context.state,
52+
metadata: { ...context.state.metadata, namespace: consequent_namespace }
53+
})
54+
);
1555
const consequent_id = context.state.scope.generate('consequent');
1656

1757
statements.push(b.var(b.id(consequent_id), b.arrow([b.id('$$anchor')], consequent)));
1858

1959
let alternate_id;
2060

2161
if (node.alternate) {
22-
const alternate = /** @type {BlockStatement} */ (context.visit(node.alternate));
62+
const alternate_namespace = get_namespace(node.consequent);
63+
const alternate = /** @type {BlockStatement} */ (
64+
context.visit(node.alternate, {
65+
...context.state,
66+
metadata: { ...context.state.metadata, namespace: alternate_namespace }
67+
})
68+
);
2369
alternate_id = context.state.scope.generate('alternate');
2470
statements.push(b.var(b.id(alternate_id), b.arrow([b.id('$$anchor')], alternate)));
2571
}

0 commit comments

Comments
 (0)