From 86ae349bcc0acc613b6f91757ce661a3a33f0855 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Wed, 4 Dec 2024 15:32:02 +0100 Subject: [PATCH] fix: better error messages for invalid HTML trees (#14445) * fix: better error messages for invalid HTML trees closes #13331 * fix test * more concise * tweak * tweak messages * adjust tests * tweak message slightly, so it doesn't sound like the bad element is the one we're currently encountering * put locations in generated message * tidy up * consistency * fix --------- Co-authored-by: Rich Harris --- .changeset/green-pumpkins-ring.md | 5 ++ .../98-reference/.generated/compile-errors.md | 4 +- .../.generated/compile-warnings.md | 4 +- .../messages/compile-errors/template.md | 4 +- .../messages/compile-warnings/template.md | 4 +- packages/svelte/src/compiler/errors.js | 9 +- .../2-analyze/visitors/ExpressionTag.js | 5 +- .../2-analyze/visitors/RegularElement.js | 18 ++-- .../phases/2-analyze/visitors/Text.js | 5 +- packages/svelte/src/compiler/warnings.js | 9 +- packages/svelte/src/html-tree-validation.js | 85 ++++++++++++------- packages/svelte/src/internal/server/dev.js | 29 ++++--- .../invalid-html-ssr-ancestor/_config.js | 21 +++++ .../invalid-html-ssr-ancestor/form.svelte | 1 + .../invalid-html-ssr-ancestor/main.svelte | 9 ++ .../samples/invalid-html-ssr/_config.js | 4 +- .../invalid-nested-svelte-element/_config.js | 2 +- .../_expected_head.html | 2 +- .../invalid-node-placement-2/errors.json | 2 +- .../invalid-node-placement-4/errors.json | 2 +- .../invalid-node-placement-5/warnings.json | 2 +- .../invalid-node-placement-6/errors.json | 2 +- .../invalid-node-placement-7/errors.json | 2 +- .../invalid-node-placement-8/errors.json | 2 +- .../invalid-node-placement/errors.json | 2 +- 25 files changed, 150 insertions(+), 84 deletions(-) create mode 100644 .changeset/green-pumpkins-ring.md create mode 100644 packages/svelte/tests/runtime-runes/samples/invalid-html-ssr-ancestor/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/invalid-html-ssr-ancestor/form.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/invalid-html-ssr-ancestor/main.svelte diff --git a/.changeset/green-pumpkins-ring.md b/.changeset/green-pumpkins-ring.md new file mode 100644 index 0000000000..20bed8e347 --- /dev/null +++ b/.changeset/green-pumpkins-ring.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: better error messages for invalid HTML trees diff --git a/documentation/docs/98-reference/.generated/compile-errors.md b/documentation/docs/98-reference/.generated/compile-errors.md index e1925324e6..3bd162d8d7 100644 --- a/documentation/docs/98-reference/.generated/compile-errors.md +++ b/documentation/docs/98-reference/.generated/compile-errors.md @@ -487,12 +487,12 @@ A component cannot have a default export ### node_invalid_placement ``` -%thing% is invalid inside `<%parent%>` +%message%. The browser will 'repair' the HTML (by moving, removing, or inserting elements) which breaks Svelte's assumptions about the structure of your components. ``` HTML restricts where certain elements can appear. In case of a violation the browser will 'repair' the HTML in a way that breaks Svelte's assumptions about the structure of your components. Some examples: -- `

hello

world

` will result in `

hello

world

` for example (the `
` autoclosed the `

` because `

` cannot contain block-level elements) +- `

hello

world

` will result in `

hello

world

` (the `
` autoclosed the `

` because `

` cannot contain block-level elements) - `

option a
` will result in `` (the `
` is removed) - `
cell
` will result in `
cell
` (a `` is auto-inserted) diff --git a/documentation/docs/98-reference/.generated/compile-warnings.md b/documentation/docs/98-reference/.generated/compile-warnings.md index cc948e2547..481959ba3d 100644 --- a/documentation/docs/98-reference/.generated/compile-warnings.md +++ b/documentation/docs/98-reference/.generated/compile-warnings.md @@ -643,12 +643,12 @@ Svelte 5 components are no longer classes. Instantiate them using `mount` or `hy ### node_invalid_placement_ssr ``` -%thing% is invalid inside `<%parent%>`. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a `hydration_mismatch` warning +%message%. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a `hydration_mismatch` warning ``` HTML restricts where certain elements can appear. In case of a violation the browser will 'repair' the HTML in a way that breaks Svelte's assumptions about the structure of your components. Some examples: -- `

hello

world

` will result in `

hello

world

` for example (the `
` autoclosed the `

` because `

` cannot contain block-level elements) +- `

hello

world

` will result in `

hello

world

` (the `
` autoclosed the `

` because `

` cannot contain block-level elements) - `

option a
` will result in `` (the `
` is removed) - `
cell
` will result in `
cell
` (a `` is auto-inserted) diff --git a/packages/svelte/messages/compile-errors/template.md b/packages/svelte/messages/compile-errors/template.md index 613d11ae51..9621a6457b 100644 --- a/packages/svelte/messages/compile-errors/template.md +++ b/packages/svelte/messages/compile-errors/template.md @@ -190,11 +190,11 @@ ## node_invalid_placement -> %thing% is invalid inside `<%parent%>` +> %message%. The browser will 'repair' the HTML (by moving, removing, or inserting elements) which breaks Svelte's assumptions about the structure of your components. HTML restricts where certain elements can appear. In case of a violation the browser will 'repair' the HTML in a way that breaks Svelte's assumptions about the structure of your components. Some examples: -- `

hello

world

` will result in `

hello

world

` for example (the `
` autoclosed the `

` because `

` cannot contain block-level elements) +- `

hello

world

` will result in `

hello

world

` (the `
` autoclosed the `

` because `

` cannot contain block-level elements) - `

option a
` will result in `` (the `
` is removed) - `
cell
` will result in `
cell
` (a `` is auto-inserted) diff --git a/packages/svelte/messages/compile-warnings/template.md b/packages/svelte/messages/compile-warnings/template.md index bfa75ac7f0..690681c172 100644 --- a/packages/svelte/messages/compile-warnings/template.md +++ b/packages/svelte/messages/compile-warnings/template.md @@ -40,11 +40,11 @@ ## node_invalid_placement_ssr -> %thing% is invalid inside `<%parent%>`. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a `hydration_mismatch` warning +> %message%. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a `hydration_mismatch` warning HTML restricts where certain elements can appear. In case of a violation the browser will 'repair' the HTML in a way that breaks Svelte's assumptions about the structure of your components. Some examples: -- `

hello

world

` will result in `

hello

world

` for example (the `
` autoclosed the `

` because `

` cannot contain block-level elements) +- `

hello

world

` will result in `

hello

world

` (the `
` autoclosed the `

` because `

` cannot contain block-level elements) - `

option a
` will result in `` (the `
` is removed) - `
cell
` will result in `
cell
` (a `` is auto-inserted) diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index a6e4549e2f..901ea1983e 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -1043,14 +1043,13 @@ export function mixed_event_handler_syntaxes(node, name) { } /** - * %thing% is invalid inside `<%parent%>` + * %message%. The browser will 'repair' the HTML (by moving, removing, or inserting elements) which breaks Svelte's assumptions about the structure of your components. * @param {null | number | NodeLike} node - * @param {string} thing - * @param {string} parent + * @param {string} message * @returns {never} */ -export function node_invalid_placement(node, thing, parent) { - e(node, "node_invalid_placement", `${thing} is invalid inside \`<${parent}>\``); +export function node_invalid_placement(node, message) { + e(node, "node_invalid_placement", `${message}. The browser will 'repair' the HTML (by moving, removing, or inserting elements) which breaks Svelte's assumptions about the structure of your components.`); } /** diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/ExpressionTag.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/ExpressionTag.js index e0d2710a08..88fe4e6afa 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/ExpressionTag.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/ExpressionTag.js @@ -12,8 +12,9 @@ export function ExpressionTag(node, context) { const in_template = context.path.at(-1)?.type === 'Fragment'; if (in_template && context.state.parent_element) { - if (!is_tag_valid_with_parent('#text', context.state.parent_element)) { - e.node_invalid_placement(node, '`{expression}`', context.state.parent_element); + const message = is_tag_valid_with_parent('#text', context.state.parent_element); + if (message) { + e.node_invalid_placement(node, message); } } diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js index fa6ca0f6e9..7454ab8103 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js @@ -114,15 +114,12 @@ export function RegularElement(node, context) { if (!past_parent) { if (ancestor.type === 'RegularElement' && ancestor.name === context.state.parent_element) { - if (!is_tag_valid_with_parent(node.name, context.state.parent_element)) { + const message = is_tag_valid_with_parent(node.name, context.state.parent_element); + if (message) { if (only_warn) { - w.node_invalid_placement_ssr( - node, - `\`<${node.name}>\``, - context.state.parent_element - ); + w.node_invalid_placement_ssr(node, message); } else { - e.node_invalid_placement(node, `\`<${node.name}>\``, context.state.parent_element); + e.node_invalid_placement(node, message); } } @@ -131,11 +128,12 @@ export function RegularElement(node, context) { } else if (ancestor.type === 'RegularElement') { ancestors.push(ancestor.name); - if (!is_tag_valid_with_ancestor(node.name, ancestors)) { + const message = is_tag_valid_with_ancestor(node.name, ancestors); + if (message) { if (only_warn) { - w.node_invalid_placement_ssr(node, `\`<${node.name}>\``, ancestor.name); + w.node_invalid_placement_ssr(node, message); } else { - e.node_invalid_placement(node, `\`<${node.name}>\``, ancestor.name); + e.node_invalid_placement(node, message); } } } else if ( diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/Text.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/Text.js index b60030f638..363a111b7d 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/Text.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/Text.js @@ -12,8 +12,9 @@ export function Text(node, context) { const in_template = context.path.at(-1)?.type === 'Fragment'; if (in_template && context.state.parent_element && regex_not_whitespace.test(node.data)) { - if (!is_tag_valid_with_parent('#text', context.state.parent_element)) { - e.node_invalid_placement(node, 'Text node', context.state.parent_element); + const message = is_tag_valid_with_parent('#text', context.state.parent_element); + if (message) { + e.node_invalid_placement(node, message); } } } diff --git a/packages/svelte/src/compiler/warnings.js b/packages/svelte/src/compiler/warnings.js index f6ed7de7d5..e193ad0f11 100644 --- a/packages/svelte/src/compiler/warnings.js +++ b/packages/svelte/src/compiler/warnings.js @@ -754,13 +754,12 @@ export function event_directive_deprecated(node, name) { } /** - * %thing% is invalid inside `<%parent%>`. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a `hydration_mismatch` warning + * %message%. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a `hydration_mismatch` warning * @param {null | NodeLike} node - * @param {string} thing - * @param {string} parent + * @param {string} message */ -export function node_invalid_placement_ssr(node, thing, parent) { - w(node, "node_invalid_placement_ssr", `${thing} is invalid inside \`<${parent}>\`. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a \`hydration_mismatch\` warning`); +export function node_invalid_placement_ssr(node, message) { + w(node, "node_invalid_placement_ssr", `${message}. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a \`hydration_mismatch\` warning`); } /** diff --git a/packages/svelte/src/html-tree-validation.js b/packages/svelte/src/html-tree-validation.js index 0ebf45e166..98e74b638f 100644 --- a/packages/svelte/src/html-tree-validation.js +++ b/packages/svelte/src/html-tree-validation.js @@ -135,59 +135,85 @@ const disallowed_children = { }; /** - * Returns false if the tag is not allowed inside the ancestor tag (which is grandparent and above) such that it will result + * Returns an error message if the tag is not allowed inside the ancestor tag (which is grandparent and above) such that it will result * in the browser repairing the HTML, which will likely result in an error during hydration. - * @param {string} tag + * @param {string} child_tag * @param {string[]} ancestors All nodes starting with the parent, up until the ancestor, which means two entries minimum - * @returns {boolean} + * @param {string} [child_loc] + * @param {string} [ancestor_loc] + * @returns {string | null} */ -export function is_tag_valid_with_ancestor(tag, ancestors) { - if (tag.includes('-')) return true; // custom elements can be anything +export function is_tag_valid_with_ancestor(child_tag, ancestors, child_loc, ancestor_loc) { + if (child_tag.includes('-')) return null; // custom elements can be anything - const target = ancestors[ancestors.length - 1]; - const disallowed = disallowed_children[target]; - if (!disallowed) return true; + const ancestor_tag = ancestors[ancestors.length - 1]; + const disallowed = disallowed_children[ancestor_tag]; + if (!disallowed) return null; if ('reset_by' in disallowed && disallowed.reset_by) { for (let i = ancestors.length - 2; i >= 0; i--) { const ancestor = ancestors[i]; - if (ancestor.includes('-')) return true; // custom elements can be anything + if (ancestor.includes('-')) return null; // custom elements can be anything // A reset means that forbidden descendants are allowed again if (disallowed.reset_by.includes(ancestors[i])) { - return true; + return null; } } } - return 'descendant' in disallowed ? !disallowed.descendant.includes(tag) : true; + if ('descendant' in disallowed && disallowed.descendant.includes(child_tag)) { + const child = child_loc ? `\`<${child_tag}>\` (${child_loc})` : `\`<${child_tag}>\``; + const ancestor = ancestor_loc + ? `\`<${ancestor_tag}>\` (${ancestor_loc})` + : `\`<${ancestor_tag}>\``; + + return `${child} cannot be a descendant of ${ancestor}`; + } + + return null; } /** - * Returns false if the tag is not allowed inside the parent tag such that it will result + * Returns an error message if the tag is not allowed inside the parent tag such that it will result * in the browser repairing the HTML, which will likely result in an error during hydration. - * @param {string} tag + * @param {string} child_tag * @param {string} parent_tag - * @returns {boolean} + * @param {string} [child_loc] + * @param {string} [parent_loc] + * @returns {string | null} */ -export function is_tag_valid_with_parent(tag, parent_tag) { - if (tag.includes('-') || parent_tag?.includes('-')) return true; // custom elements can be anything +export function is_tag_valid_with_parent(child_tag, parent_tag, child_loc, parent_loc) { + if (child_tag.includes('-') || parent_tag?.includes('-')) return null; // custom elements can be anything const disallowed = disallowed_children[parent_tag]; + const child = child_loc ? `\`<${child_tag}>\` (${child_loc})` : `\`<${child_tag}>\``; + const parent = parent_loc ? `\`<${parent_tag}>\` (${parent_loc})` : `\`<${parent_tag}>\``; + if (disallowed) { - if ('direct' in disallowed && disallowed.direct.includes(tag)) { - return false; + if ('direct' in disallowed && disallowed.direct.includes(child_tag)) { + return `${child} cannot be a direct child of ${parent}`; } - if ('descendant' in disallowed && disallowed.descendant.includes(tag)) { - return false; + + if ('descendant' in disallowed && disallowed.descendant.includes(child_tag)) { + return `${child} cannot be a child of ${parent}`; } + if ('only' in disallowed && disallowed.only) { - return disallowed.only.includes(tag); + if (disallowed.only.includes(child_tag)) { + return null; + } else { + return `${child} cannot be a child of ${parent}. \`<${parent_tag}>\` only allows these children: ${disallowed.only.map((d) => `\`<${d}>\``).join(', ')}`; + } } } - switch (tag) { + // These tags are only valid with a few parents that have special child + // parsing rules - if we're down here, then none of those matched and + // so we allow it only if we don't know what the parent is, as all other + // cases are invalid (and we only get into this function if we know the parent). + switch (child_tag) { case 'body': case 'caption': case 'col': @@ -196,18 +222,17 @@ export function is_tag_valid_with_parent(tag, parent_tag) { case 'frame': case 'head': case 'html': + return `${child} cannot be a child of ${parent}`; + case 'thead': case 'tbody': - case 'td': case 'tfoot': + return `${child} must be the child of a \`\`, not a ${parent}`; + case 'td': case 'th': - case 'thead': + return `${child} must be the child of a \`\`, not a ${parent}`; case 'tr': - // These tags are only valid with a few parents that have special child - // parsing rules - if we're down here, then none of those matched and - // so we allow it only if we don't know what the parent is, as all other - // cases are invalid (and we only get into this function if we know the parent). - return false; + return `\`\` must be the child of a \`\`, \`\`, or \`\`, not a ${parent}`; } - return true; + return null; } diff --git a/packages/svelte/src/internal/server/dev.js b/packages/svelte/src/internal/server/dev.js index 145b37479b..ecf4e67429 100644 --- a/packages/svelte/src/internal/server/dev.js +++ b/packages/svelte/src/internal/server/dev.js @@ -34,12 +34,11 @@ function stringify(element) { /** * @param {Payload} payload - * @param {Element} parent - * @param {Element} child + * @param {string} message */ -function print_error(payload, parent, child) { - var message = - `node_invalid_placement_ssr: ${stringify(parent)} cannot contain ${stringify(child)}\n\n` + +function print_error(payload, message) { + message = + `node_invalid_placement_ssr: ${message}\n\n` + 'This can cause content to shift around as the browser repairs the HTML, and will likely result in a `hydration_mismatch` warning.'; if ((seen ??= new Set()).has(message)) return; @@ -72,15 +71,23 @@ export function push_element(payload, tag, line, column) { var ancestor = parent.parent; var ancestors = [parent.tag]; - if (!is_tag_valid_with_parent(tag, parent.tag)) { - print_error(payload, parent, child); - } + const child_loc = filename ? `${filename}:${line}:${column}` : undefined; + const parent_loc = parent.filename + ? `${parent.filename}:${parent.line}:${parent.column}` + : undefined; + + const message = is_tag_valid_with_parent(tag, parent.tag, child_loc, parent_loc); + if (message) print_error(payload, message); while (ancestor != null) { ancestors.push(ancestor.tag); - if (!is_tag_valid_with_ancestor(tag, ancestors)) { - print_error(payload, ancestor, child); - } + const ancestor_loc = ancestor.filename + ? `${ancestor.filename}:${ancestor.line}:${ancestor.column}` + : undefined; + + const message = is_tag_valid_with_ancestor(tag, ancestors, child_loc, ancestor_loc); + if (message) print_error(payload, message); + ancestor = ancestor.parent; } } diff --git a/packages/svelte/tests/runtime-runes/samples/invalid-html-ssr-ancestor/_config.js b/packages/svelte/tests/runtime-runes/samples/invalid-html-ssr-ancestor/_config.js new file mode 100644 index 0000000000..4c45b26179 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/invalid-html-ssr-ancestor/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + + html: `
`, + + recover: true, + + mode: ['hydrate'], + + errors: [ + 'node_invalid_placement_ssr: `` (form.svelte:1:0) cannot be a descendant of `` (main.svelte:5:0)\n\nThis can cause content to shift around as the browser repairs the HTML, and will likely result in a `hydration_mismatch` warning.' + ], + + warnings: [ + 'Hydration failed because the initial UI does not match what was rendered on the server' + ] +}); diff --git a/packages/svelte/tests/runtime-runes/samples/invalid-html-ssr-ancestor/form.svelte b/packages/svelte/tests/runtime-runes/samples/invalid-html-ssr-ancestor/form.svelte new file mode 100644 index 0000000000..cddb6e3794 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/invalid-html-ssr-ancestor/form.svelte @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/runtime-runes/samples/invalid-html-ssr-ancestor/main.svelte b/packages/svelte/tests/runtime-runes/samples/invalid-html-ssr-ancestor/main.svelte new file mode 100644 index 0000000000..8aea343322 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/invalid-html-ssr-ancestor/main.svelte @@ -0,0 +1,9 @@ + + + +
+ +
+ diff --git a/packages/svelte/tests/runtime-runes/samples/invalid-html-ssr/_config.js b/packages/svelte/tests/runtime-runes/samples/invalid-html-ssr/_config.js index d815d10fc7..bc4d709b19 100644 --- a/packages/svelte/tests/runtime-runes/samples/invalid-html-ssr/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/invalid-html-ssr/_config.js @@ -12,8 +12,8 @@ export default test({ mode: ['hydrate'], errors: [ - 'node_invalid_placement_ssr: `

` (main.svelte:6:0) cannot contain `

` (h1.svelte:1:0)\n\nThis can cause content to shift around as the browser repairs the HTML, and will likely result in a `hydration_mismatch` warning.', - 'node_invalid_placement_ssr: `
` (main.svelte:9:0) cannot contain `` (form.svelte:1:0)\n\nThis can cause content to shift around as the browser repairs the HTML, and will likely result in a `hydration_mismatch` warning.' + 'node_invalid_placement_ssr: `

` (h1.svelte:1:0) cannot be a child of `

` (main.svelte:6:0)\n\nThis can cause content to shift around as the browser repairs the HTML, and will likely result in a `hydration_mismatch` warning.', + 'node_invalid_placement_ssr: `` (form.svelte:1:0) cannot be a child of `` (main.svelte:9:0)\n\nThis can cause content to shift around as the browser repairs the HTML, and will likely result in a `hydration_mismatch` warning.' ], warnings: [ diff --git a/packages/svelte/tests/server-side-rendering/samples/invalid-nested-svelte-element/_config.js b/packages/svelte/tests/server-side-rendering/samples/invalid-nested-svelte-element/_config.js index 9b2688711d..71edff6a68 100644 --- a/packages/svelte/tests/server-side-rendering/samples/invalid-nested-svelte-element/_config.js +++ b/packages/svelte/tests/server-side-rendering/samples/invalid-nested-svelte-element/_config.js @@ -6,6 +6,6 @@ export default test({ }, errors: [ - 'node_invalid_placement_ssr: `

` (packages/svelte/tests/server-side-rendering/samples/invalid-nested-svelte-element/main.svelte:1:0) cannot contain `

` (packages/svelte/tests/server-side-rendering/samples/invalid-nested-svelte-element/main.svelte:2:1)\n\nThis can cause content to shift around as the browser repairs the HTML, and will likely result in a `hydration_mismatch` warning.' + 'node_invalid_placement_ssr: `

` (packages/svelte/tests/server-side-rendering/samples/invalid-nested-svelte-element/main.svelte:2:1) cannot be a child of `

` (packages/svelte/tests/server-side-rendering/samples/invalid-nested-svelte-element/main.svelte:1:0)\n\nThis can cause content to shift around as the browser repairs the HTML, and will likely result in a `hydration_mismatch` warning.' ] }); diff --git a/packages/svelte/tests/server-side-rendering/samples/invalid-nested-svelte-element/_expected_head.html b/packages/svelte/tests/server-side-rendering/samples/invalid-nested-svelte-element/_expected_head.html index 27c37f693b..6d9ea9de5f 100644 --- a/packages/svelte/tests/server-side-rendering/samples/invalid-nested-svelte-element/_expected_head.html +++ b/packages/svelte/tests/server-side-rendering/samples/invalid-nested-svelte-element/_expected_head.html @@ -1 +1 @@ - \ No newline at end of file + diff --git a/packages/svelte/tests/validator/samples/invalid-node-placement-2/errors.json b/packages/svelte/tests/validator/samples/invalid-node-placement-2/errors.json index 3d97865823..abbded296a 100644 --- a/packages/svelte/tests/validator/samples/invalid-node-placement-2/errors.json +++ b/packages/svelte/tests/validator/samples/invalid-node-placement-2/errors.json @@ -1,7 +1,7 @@ [ { "code": "node_invalid_placement", - "message": "`

` is invalid inside `

`", + "message": "`

` cannot be a descendant of `

`. The browser will 'repair' the HTML (by moving, removing, or inserting elements) which breaks Svelte's assumptions about the structure of your components.", "start": { "line": 4, "column": 3 diff --git a/packages/svelte/tests/validator/samples/invalid-node-placement-4/errors.json b/packages/svelte/tests/validator/samples/invalid-node-placement-4/errors.json index 4d637aed80..727bf6c258 100644 --- a/packages/svelte/tests/validator/samples/invalid-node-placement-4/errors.json +++ b/packages/svelte/tests/validator/samples/invalid-node-placement-4/errors.json @@ -1,7 +1,7 @@ [ { "code": "node_invalid_placement", - "message": "`` is invalid inside ``", + "message": "`` cannot be a descendant of ``. The browser will 'repair' the HTML (by moving, removing, or inserting elements) which breaks Svelte's assumptions about the structure of your components.", "start": { "line": 4, "column": 3 diff --git a/packages/svelte/tests/validator/samples/invalid-node-placement-5/warnings.json b/packages/svelte/tests/validator/samples/invalid-node-placement-5/warnings.json index e85050beb7..59c73c4e73 100644 --- a/packages/svelte/tests/validator/samples/invalid-node-placement-5/warnings.json +++ b/packages/svelte/tests/validator/samples/invalid-node-placement-5/warnings.json @@ -1,7 +1,7 @@ [ { "code": "node_invalid_placement_ssr", - "message": "`` is invalid inside ``. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a `hydration_mismatch` warning", + "message": "`` cannot be a child of ``. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a `hydration_mismatch` warning", "start": { "line": 4, "column": 3 diff --git a/packages/svelte/tests/validator/samples/invalid-node-placement-6/errors.json b/packages/svelte/tests/validator/samples/invalid-node-placement-6/errors.json index 63fc9c517e..4849717e14 100644 --- a/packages/svelte/tests/validator/samples/invalid-node-placement-6/errors.json +++ b/packages/svelte/tests/validator/samples/invalid-node-placement-6/errors.json @@ -1,7 +1,7 @@ [ { "code": "node_invalid_placement", - "message": "`

` is invalid inside `
`", + "message": "`
` cannot be a descendant of `
`. The browser will 'repair' the HTML (by moving, removing, or inserting elements) which breaks Svelte's assumptions about the structure of your components.", "start": { "line": 16, "column": 3 diff --git a/packages/svelte/tests/validator/samples/invalid-node-placement-7/errors.json b/packages/svelte/tests/validator/samples/invalid-node-placement-7/errors.json index edfc158c9d..a1422c001a 100644 --- a/packages/svelte/tests/validator/samples/invalid-node-placement-7/errors.json +++ b/packages/svelte/tests/validator/samples/invalid-node-placement-7/errors.json @@ -1,7 +1,7 @@ [ { "code": "node_invalid_placement", - "message": "`

` is invalid inside `
`", + "message": "`
` must be the child of a `
`, not a `
`. The browser will 'repair' the HTML (by moving, removing, or inserting elements) which breaks Svelte's assumptions about the structure of your components.", "start": { "line": 8, "column": 1 diff --git a/packages/svelte/tests/validator/samples/invalid-node-placement-8/errors.json b/packages/svelte/tests/validator/samples/invalid-node-placement-8/errors.json index 1127a76336..d75d5d4105 100644 --- a/packages/svelte/tests/validator/samples/invalid-node-placement-8/errors.json +++ b/packages/svelte/tests/validator/samples/invalid-node-placement-8/errors.json @@ -1,7 +1,7 @@ [ { "code": "node_invalid_placement", - "message": "Text node is invalid inside `
`", + "message": "`<#text>` cannot be a child of ``. `` only allows these children: ``, `