throw error if tag is void and it has content in dev mode

pull/7453/head
baseballyama 4 years ago
parent 5918b02406
commit b5fe7e8a90

@ -277,8 +277,11 @@ export default class ElementWrapper extends Wrapper {
const tag = this.node.tag_expr.manipulate(block);
block.add_variable(previous_tag, tag);
const has_children_of_dynamic_element = block.get_unique_name('has_children_of_dynamic_element');
block.add_variable(has_children_of_dynamic_element, x`${this.node.children.length > 0 ? 'true' : 'false'}`);
block.chunks.init.push(b`
${this.renderer.options.dev && b`@validate_dynamic_element(${tag});`}
${this.renderer.options.dev && b`@validate_dynamic_element(${tag}, ${has_children_of_dynamic_element});`}
let ${this.var} = ${tag} && ${this.child_dynamic_element_block.name}(#ctx);
`);
@ -309,7 +312,7 @@ export default class ElementWrapper extends Wrapper {
${this.var}.m(${this.get_update_mount_node(anchor)}, ${anchor});
} else if (${not_equal}(${previous_tag}, ${tag})) {
${this.var}.d(1);
${this.renderer.options.dev && b`@validate_dynamic_element(${tag});`}
${this.renderer.options.dev && b`@validate_dynamic_element(${tag}, ${has_children_of_dynamic_element});`}
${this.var} = ${this.child_dynamic_element_block.name}(#ctx);
${this.var}.c();
${this.var}.m(${this.get_update_mount_node(anchor)}, ${anchor});

@ -1,5 +1,6 @@
import { custom_event, append, append_hydration, insert, insert_hydration, detach, listen, attr } from './dom';
import { SvelteComponent } from './Component';
import { is_void } from '../../shared/utils/names';
export function dispatch_dev<T=any>(type: string, detail?: T) {
document.dispatchEvent(custom_event(type, { version: '__VERSION__', ...detail }, { bubbles: true }));
@ -107,10 +108,14 @@ export function validate_slots(name, slot, keys) {
}
}
export function validate_dynamic_element(tag: unknown) {
if (tag && typeof tag !== 'string') {
export function validate_dynamic_element(tag: unknown, has_children: boolean) {
const is_string = typeof tag === 'string';
if (tag && !is_string) {
throw new Error('<svelte:element> expects "this" attribute to be a string.');
}
if (is_string && is_void(tag as string) && has_children) {
throw new Error(`<${tag}> element is self-closing and cannot have content.`);
}
}
type Props = Record<string, any>;

@ -0,0 +1,9 @@
export default {
compileOptions: {
dev: true
},
props: {
tag: 'br'
},
error: '<br> element is self-closing and cannot have content.'
};

@ -0,0 +1,5 @@
<script>
export let tag;
</script>
<svelte:element this='{tag}'>foo</svelte:element>

@ -0,0 +1,9 @@
export default {
compileOptions: {
dev: true
},
props: {
tag: 'br'
},
error: '<br> element is self-closing and cannot have content.'
};

@ -0,0 +1,5 @@
<script>
export let tag;
</script>
<svelte:element this='{tag}'><div>bar</div></svelte:element>

@ -0,0 +1,9 @@
export default {
compileOptions: {
dev: true
},
props: {
tag: 'br'
},
error: '<br> element is self-closing and cannot have content.'
};

@ -0,0 +1,6 @@
<script>
import Nested from './Nested.svelte';
export let tag;
</script>
<svelte:element this='{tag}'><Nested/></svelte:element>
Loading…
Cancel
Save