fix: improve namespace inference when having `{@render}` and `{@html}` tags (#10631)

* fix: treat snippets like normal components when inferring namespace

* n

* simplify

* better desc

* slight adjustment

* feedback

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>

* feedback

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>

* skip html tag

* test

* changeset name

* cleanup

---------

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
pull/10693/head
Ahmad 10 months ago committed by GitHub
parent 767b5a8824
commit 6fb64c9914
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: improve namespace inference when having `{@render}` and `{@html}` tags

@ -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;

@ -2,12 +2,18 @@
{#if true}
<text x="0" y="26">true</text>
{:else}
<text x="0" y="26">false</text>
{/if}
{#each Array(3).fill(0) as item, idx}
{#each Array(2).fill(0) as item, idx}
<text x={idx * 10} y={42}>{idx}</text>
{/each}
<!-- comment should not set infer html namespace -->
{@html '<text x="0" y="40">html</text>'}
{@render test("snippet")}
{#snippet test(text)}
<text x={20} y={42}>{text}</text>
{/snippet}
<!-- comment should not infer html namespace -->

@ -7,7 +7,8 @@ export default test({
<text x="0" y="26">true</text>
<text x="0" y="42">0</text>
<text x="10" y="42">1</text>
<text x="20" y="42">2</text>
<text x="0" y="40">html</text>
<text x="20" y="42">snippet</text>
</svg>
`,
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');

Loading…
Cancel
Save