From 6fb64c99147d69dde4908d6e58f6e3d98108ffc8 Mon Sep 17 00:00:00 2001 From: Ahmad Date: Tue, 5 Mar 2024 02:28:25 +0200 Subject: [PATCH] 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> --- .changeset/giant-planets-shake.md | 5 ++ .../src/compiler/phases/3-transform/utils.js | 85 +++++++++---------- .../svg-namespace-infer/Wrapper.svelte | 14 ++- .../samples/svg-namespace-infer/_config.js | 5 +- 4 files changed, 60 insertions(+), 49 deletions(-) create mode 100644 .changeset/giant-planets-shake.md 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');