fix: ensure if block paths retain correct template namespacing

pull/14685/head
Dominic Gannaway 2 years ago
parent 7aa80fc2a7
commit aa2654d633

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: ensure if block paths retain correct template namespacing

@ -1,8 +1,42 @@
/** @import { BlockStatement, Expression } from 'estree' */
/** @import { AST } from '#compiler' */
/** @import { AST, Namespace } from '#compiler' */
/** @import { ComponentContext } from '../types' */
import * as b from '../../../../utils/builders.js';
/**
* @param {AST.Fragment} fragment
* @return {Namespace}
*/
function get_namespace(fragment) {
const elements = fragment.nodes.filter((n) => n.type === 'RegularElement');
/** @type {Namespace | null} */
let namespace = null;
// Check the elements within the fragment and look for consistent namespaces.
// If we have no namespaces or they are mixed, then fallback to `html`
for (const element of elements) {
const metadata = element.metadata;
if (metadata.mathml) {
if (namespace === null || namespace === 'mathml') {
namespace = 'mathml';
} else {
namespace = 'html';
}
} else if (metadata.svg) {
if (namespace === null || namespace === 'svg') {
namespace = 'svg';
} else {
namespace = 'html';
}
} else {
namespace = 'html';
}
}
return namespace ?? 'html';
}
/**
* @param {AST.IfBlock} node
* @param {ComponentContext} context
@ -11,7 +45,13 @@ export function IfBlock(node, context) {
context.state.template.push('<!>');
const statements = [];
const consequent = /** @type {BlockStatement} */ (context.visit(node.consequent));
const consequent_namespace = get_namespace(node.consequent);
const consequent = /** @type {BlockStatement} */ (
context.visit(node.consequent, {
...context.state,
metadata: { ...context.state.metadata, namespace: consequent_namespace }
})
);
const consequent_id = context.state.scope.generate('consequent');
statements.push(b.var(b.id(consequent_id), b.arrow([b.id('$$anchor')], consequent)));
@ -19,7 +59,13 @@ export function IfBlock(node, context) {
let alternate_id;
if (node.alternate) {
const alternate = /** @type {BlockStatement} */ (context.visit(node.alternate));
const alternate_namespace = get_namespace(node.consequent);
const alternate = /** @type {BlockStatement} */ (
context.visit(node.alternate, {
...context.state,
metadata: { ...context.state.metadata, namespace: alternate_namespace }
})
);
alternate_id = context.state.scope.generate('alternate');
statements.push(b.var(b.id(alternate_id), b.arrow([b.id('$$anchor')], alternate)));
}

Loading…
Cancel
Save