Skip to content

Commit 5fd493d

Browse files
committed
pass location info, remove unnecessary if (DEV) block
1 parent 356dd05 commit 5fd493d

File tree

2 files changed

+115
-1
lines changed

2 files changed

+115
-1
lines changed

packages/svelte/src/compiler/phases/3-transform/server/transform-server.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { DOMBooleanAttributes, HYDRATION_END, HYDRATION_START } from '../../../.
2727
import { escape_html } from '../../../../escaping.js';
2828
import { sanitize_template_string } from '../../../utils/sanitize_template_string.js';
2929
import { BLOCK_CLOSE, BLOCK_CLOSE_ELSE } from '../../../../internal/server/hydration.js';
30+
import { locator } from '../../../state.js';
3031

3132
export const block_open = t_string(`<!--${HYDRATION_START}-->`);
3233
export const block_close = t_string(`<!--${HYDRATION_END}-->`);
@@ -1364,8 +1365,19 @@ const template_visitors = {
13641365
}
13651366

13661367
if (context.state.options.dev) {
1368+
const location = /** @type {import('locate-character').Location} */ (locator(node.start));
13671369
context.state.template.push(
1368-
t_statement(b.stmt(b.call('$.push_element', b.literal(node.name), b.id('$$payload'))))
1370+
t_statement(
1371+
b.stmt(
1372+
b.call(
1373+
'$.push_element',
1374+
b.id('$$payload'),
1375+
b.literal(node.name),
1376+
b.literal(location.line),
1377+
b.literal(location.column)
1378+
)
1379+
)
1380+
)
13691381
);
13701382
}
13711383

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import {
2+
disallowed_paragraph_contents,
3+
interactive_elements,
4+
is_tag_valid_with_parent
5+
} from '../../constants.js';
6+
import { current_component } from './context.js';
7+
8+
/**
9+
* @typedef {{
10+
* tag: string;
11+
* parent: null | Element;
12+
* file: string;
13+
* }} Element
14+
*/
15+
16+
/**
17+
* @type {Element | null}
18+
*/
19+
let current_element = null;
20+
21+
/**
22+
* @param {import('#server').Payload} payload
23+
* @param {string} message
24+
*/
25+
function error_on_client(payload, message) {
26+
message =
27+
`Svelte SSR validation error:\n\n${message}\n\n` +
28+
'Ensure your components render valid HTML as the browser will try to repair invalid HTML, ' +
29+
'which may result in content being shifted around and will likely result in a hydration mismatch.';
30+
// eslint-disable-next-line no-console
31+
console.error(message);
32+
payload.head.out += `<script>console.error(\`${message}\`)</script>`;
33+
}
34+
35+
/**
36+
* @param {string} file
37+
*/
38+
function print_file(file) {
39+
return file ? `(${file})` : '';
40+
}
41+
42+
/**
43+
* @param {import('#server').Payload} payload
44+
* @param {string} tag
45+
* @param {number} line
46+
* @param {number} column
47+
*/
48+
export function push_element(payload, tag, line, column) {
49+
var file;
50+
51+
if (current_component !== null) {
52+
const filename = current_component.function.filename;
53+
if (filename) {
54+
file = filename.split('/').at(-1);
55+
}
56+
}
57+
58+
if (current_element !== null && !is_tag_valid_with_parent(tag, current_element.tag)) {
59+
error_on_client(
60+
payload,
61+
`<${tag}> ${print_file(file)} is not a valid child element of <${current_element.tag}> ${print_file(current_element.file)}`
62+
);
63+
}
64+
65+
if (interactive_elements.has(tag)) {
66+
let element = current_element;
67+
while (element !== null) {
68+
if (interactive_elements.has(element.tag)) {
69+
error_on_client(
70+
payload,
71+
`<${tag}> ${print_file(file)} is not a valid child element of <${element.tag}> ${print_file(element.file)}`
72+
);
73+
}
74+
element = element.parent;
75+
}
76+
}
77+
78+
if (disallowed_paragraph_contents.includes(tag)) {
79+
let element = current_element;
80+
while (element !== null) {
81+
if (element.tag === 'p') {
82+
error_on_client(
83+
payload,
84+
`<${tag}> ${print_file(file)} is not a valid child element of <p> ${print_file(element.file)}`
85+
);
86+
}
87+
element = element.parent;
88+
}
89+
}
90+
91+
current_element = {
92+
tag,
93+
parent: current_element,
94+
file
95+
};
96+
}
97+
98+
export function pop_element() {
99+
if (current_element !== null) {
100+
current_element = current_element.parent;
101+
}
102+
}

0 commit comments

Comments
 (0)