Skip to content

Commit 3cf0b9e

Browse files
committed
Merge branch 'better-normalize-html' into async
2 parents 1a094e7 + 73796c4 commit 3cf0b9e

File tree

15 files changed

+188
-113
lines changed

15 files changed

+188
-113
lines changed

.changeset/orange-tips-pull.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.changeset/rude-drinks-relate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: correctly transform reassignments to class fields in SSR mode

packages/svelte/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# svelte
22

3+
## 5.33.11
4+
5+
### Patch Changes
6+
7+
- fix: treat transitive dependencies of each blocks as mutable in legacy mode if item is mutated ([#16038](https://github.com/sveltejs/svelte/pull/16038))
8+
39
## 5.33.10
410

511
### Patch Changes

packages/svelte/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "svelte",
33
"description": "Cybernetically enhanced web apps",
44
"license": "MIT",
5-
"version": "5.33.10",
5+
"version": "5.33.11",
66
"type": "module",
77
"types": "./types/index.d.ts",
88
"engines": {

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ export function AssignmentExpression(node, context) {
2424
* @returns {Expression | null}
2525
*/
2626
function build_assignment(operator, left, right, context) {
27-
if (context.state.analysis.runes && left.type === 'MemberExpression') {
27+
if (
28+
context.state.analysis.runes &&
29+
left.type === 'MemberExpression' &&
30+
left.object.type === 'ThisExpression' &&
31+
!left.computed
32+
) {
2833
const name = get_name(left.property);
2934
const field = name && context.state.state_fields.get(name);
3035

@@ -44,7 +49,11 @@ function build_assignment(operator, left, right, context) {
4449
/** @type {Expression} */ (context.visit(right))
4550
);
4651
}
47-
} else if (field && (field.type === '$derived' || field.type === '$derived.by')) {
52+
} else if (
53+
field &&
54+
(field.type === '$derived' || field.type === '$derived.by') &&
55+
left.property.type === 'PrivateIdentifier'
56+
) {
4857
let value = /** @type {Expression} */ (
4958
context.visit(build_assignment_value(operator, left, right))
5059
);

packages/svelte/src/version.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
* The current version, as set in package.json.
55
* @type {string}
66
*/
7-
export const VERSION = '5.33.10';
7+
export const VERSION = '5.33.11';
88
export const PUBLIC_VERSION = '5';
Lines changed: 106 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
11
import { assert } from 'vitest';
22

3-
/** @param {Element} node */
4-
function clean_children(node) {
3+
/**
4+
* @param {Element} node
5+
* @param {{ preserveComments: boolean }} opts
6+
*/
7+
function clean_children(node, opts) {
58
let previous = null;
9+
let has_element_children = false;
10+
let template =
11+
node.nodeName === 'TEMPLATE' ? /** @type {HTMLTemplateElement} */ (node) : undefined;
12+
13+
if (template) {
14+
const div = document.createElement('div');
15+
div.append(template.content);
16+
node = div;
17+
}
618

719
// sort attributes
820
const attributes = Array.from(node.attributes).sort((a, b) => {
@@ -14,6 +26,10 @@ function clean_children(node) {
1426
});
1527

1628
attributes.forEach((attr) => {
29+
if ((attr.name === 'onload' || attr.name === 'onerror') && attr.value === 'this.__e=event') {
30+
return;
31+
}
32+
1733
node.setAttribute(attr.name, attr.value);
1834
});
1935

@@ -27,24 +43,42 @@ function clean_children(node) {
2743
node.tagName !== 'tspan'
2844
) {
2945
node.removeChild(child);
46+
continue;
3047
}
3148

32-
text.data = text.data.replace(/[ \t\n\r\f]+/g, '\n');
49+
text.data = text.data.replace(/[^\S]+/g, ' ');
3350

3451
if (previous && previous.nodeType === 3) {
3552
const prev = /** @type {Text} */ (previous);
3653

3754
prev.data += text.data;
38-
prev.data = prev.data.replace(/[ \t\n\r\f]+/g, '\n');
39-
4055
node.removeChild(text);
56+
4157
text = prev;
58+
text.data = text.data.replace(/[^\S]+/g, ' ');
59+
60+
continue;
4261
}
43-
} else if (child.nodeType === 8) {
62+
}
63+
64+
if (child.nodeType === 8 && !opts.preserveComments) {
4465
// comment
45-
// do nothing
46-
} else {
47-
clean_children(/** @type {Element} */ (child));
66+
child.remove();
67+
continue;
68+
}
69+
70+
if (child.nodeType === 1 || child.nodeType === 8) {
71+
if (previous?.nodeType === 3) {
72+
const prev = /** @type {Text} */ (previous);
73+
prev.data = prev.data.replace(/^[^\S]+$/, '\n');
74+
} else if (previous?.nodeType === 1 || previous?.nodeType === 8) {
75+
node.insertBefore(document.createTextNode('\n'), child);
76+
}
77+
78+
if (child.nodeType === 1) {
79+
has_element_children = true;
80+
clean_children(/** @type {Element} */ (child), opts);
81+
}
4882
}
4983

5084
previous = child;
@@ -53,37 +87,35 @@ function clean_children(node) {
5387
// collapse whitespace
5488
if (node.firstChild && node.firstChild.nodeType === 3) {
5589
const text = /** @type {Text} */ (node.firstChild);
56-
text.data = text.data.replace(/^[ \t\n\r\f]+/, '');
57-
if (!text.data.length) node.removeChild(text);
90+
text.data = text.data.trimStart();
5891
}
5992

6093
if (node.lastChild && node.lastChild.nodeType === 3) {
6194
const text = /** @type {Text} */ (node.lastChild);
62-
text.data = text.data.replace(/[ \t\n\r\f]+$/, '');
63-
if (!text.data.length) node.removeChild(text);
95+
text.data = text.data.trimEnd();
96+
}
97+
98+
if (has_element_children && node.parentNode) {
99+
node.innerHTML = `\n\t${node.innerHTML.replace(/\n/g, '\n\t')}\n`;
100+
}
101+
102+
if (template) {
103+
template.innerHTML = node.innerHTML;
64104
}
65105
}
66106

67107
/**
68108
* @param {Window} window
69109
* @param {string} html
70-
* @param {{ removeDataSvelte?: boolean, preserveComments?: boolean }} param2
110+
* @param {{ preserveComments?: boolean }} opts
71111
*/
72-
export function normalize_html(
73-
window,
74-
html,
75-
{ removeDataSvelte = false, preserveComments = false }
76-
) {
112+
export function normalize_html(window, html, { preserveComments = false } = {}) {
77113
try {
78114
const node = window.document.createElement('div');
79-
node.innerHTML = html
80-
.replace(/(<!(--)?.*?\2>)/g, preserveComments ? '$1' : '')
81-
.replace(/(data-svelte-h="[^"]+")/g, removeDataSvelte ? '' : '$1')
82-
.replace(/>[ \t\n\r\f]+</g, '><')
83-
// Strip out the special onload/onerror hydration events from the test output
84-
.replace(/\s?onerror="this.__e=event"|\s?onload="this.__e=event"/g, '')
85-
.trim();
86-
clean_children(node);
115+
116+
node.innerHTML = html.trim();
117+
clean_children(node, { preserveComments });
118+
87119
return node.innerHTML;
88120
} catch (err) {
89121
throw new Error(`Failed to normalize HTML:\n${html}\nCause: ${err}`);
@@ -99,67 +131,52 @@ export function normalize_new_line(html) {
99131
}
100132

101133
/**
102-
* @param {{ removeDataSvelte?: boolean }} options
134+
* @param {string} actual
135+
* @param {string} expected
136+
* @param {string} [message]
103137
*/
104-
export function setup_html_equal(options = {}) {
105-
/**
106-
* @param {string} actual
107-
* @param {string} expected
108-
* @param {string} [message]
109-
*/
110-
const assert_html_equal = (actual, expected, message) => {
111-
try {
112-
assert.deepEqual(
113-
normalize_html(window, actual, options),
114-
normalize_html(window, expected, options),
115-
message
116-
);
117-
} catch (e) {
118-
if (Error.captureStackTrace)
119-
Error.captureStackTrace(/** @type {Error} */ (e), assert_html_equal);
120-
throw e;
121-
}
122-
};
123-
124-
/**
125-
*
126-
* @param {string} actual
127-
* @param {string} expected
128-
* @param {{ preserveComments?: boolean, withoutNormalizeHtml?: boolean }} param2
129-
* @param {string} [message]
130-
*/
131-
const assert_html_equal_with_options = (
132-
actual,
133-
expected,
134-
{ preserveComments, withoutNormalizeHtml },
135-
message
136-
) => {
137-
try {
138-
assert.deepEqual(
139-
withoutNormalizeHtml
140-
? normalize_new_line(actual.trim())
141-
.replace(/(\sdata-svelte-h="[^"]+")/g, options.removeDataSvelte ? '' : '$1')
142-
.replace(/(<!(--)?.*?\2>)/g, preserveComments !== false ? '$1' : '')
143-
: normalize_html(window, actual.trim(), { ...options, preserveComments }),
144-
withoutNormalizeHtml
145-
? normalize_new_line(expected.trim())
146-
.replace(/(\sdata-svelte-h="[^"]+")/g, options.removeDataSvelte ? '' : '$1')
147-
.replace(/(<!(--)?.*?\2>)/g, preserveComments !== false ? '$1' : '')
148-
: normalize_html(window, expected.trim(), { ...options, preserveComments }),
149-
message
150-
);
151-
} catch (e) {
152-
if (Error.captureStackTrace)
153-
Error.captureStackTrace(/** @type {Error} */ (e), assert_html_equal_with_options);
154-
throw e;
155-
}
156-
};
157-
158-
return {
159-
assert_html_equal,
160-
assert_html_equal_with_options
161-
};
162-
}
138+
export const assert_html_equal = (actual, expected, message) => {
139+
try {
140+
assert.deepEqual(normalize_html(window, actual), normalize_html(window, expected), message);
141+
} catch (e) {
142+
if (Error.captureStackTrace)
143+
Error.captureStackTrace(/** @type {Error} */ (e), assert_html_equal);
144+
throw e;
145+
}
146+
};
163147

164-
// Common case without options
165-
export const { assert_html_equal, assert_html_equal_with_options } = setup_html_equal();
148+
/**
149+
*
150+
* @param {string} actual
151+
* @param {string} expected
152+
* @param {{ preserveComments?: boolean, withoutNormalizeHtml?: boolean }} param2
153+
* @param {string} [message]
154+
*/
155+
export const assert_html_equal_with_options = (
156+
actual,
157+
expected,
158+
{ preserveComments, withoutNormalizeHtml },
159+
message
160+
) => {
161+
try {
162+
assert.deepEqual(
163+
withoutNormalizeHtml
164+
? normalize_new_line(actual.trim()).replace(
165+
/(<!(--)?.*?\2>)/g,
166+
preserveComments !== false ? '$1' : ''
167+
)
168+
: normalize_html(window, actual.trim(), { preserveComments }),
169+
withoutNormalizeHtml
170+
? normalize_new_line(expected.trim()).replace(
171+
/(<!(--)?.*?\2>)/g,
172+
preserveComments !== false ? '$1' : ''
173+
)
174+
: normalize_html(window, expected.trim(), { preserveComments }),
175+
message
176+
);
177+
} catch (e) {
178+
if (Error.captureStackTrace)
179+
Error.captureStackTrace(/** @type {Error} */ (e), assert_html_equal_with_options);
180+
throw e;
181+
}
182+
};

packages/svelte/tests/runtime-legacy/samples/binding-select/_config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export default test({
2525
<p>selected: one</p>
2626
2727
<select>
28-
<option${variant === 'hydrate' ? ' selected' : ''}>one</option$>
28+
<option${variant === 'hydrate' ? ' selected' : ''}>one</option>
2929
<option>two</option>
3030
<option>three</option>
3131
</select>
@@ -54,7 +54,7 @@ export default test({
5454
<p>selected: two</p>
5555
5656
<select>
57-
<option${variant === 'hydrate' ? ' selected' : ''}>one</option$>
57+
<option${variant === 'hydrate' ? ' selected' : ''}>one</option>
5858
<option>two</option>
5959
<option>three</option>
6060
</select>

packages/svelte/tests/runtime-legacy/samples/input-list/_config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ export default test({
44
html: `
55
<input list='suggestions'>
66
<datalist id='suggestions'>
7-
<option value='foo'/><option value='bar'/><option value='baz'/>
7+
<option value='foo'></option>
8+
<option value='bar'></option>
9+
<option value='baz'></option>
810
</datalist>
911
`
1012
});

packages/svelte/tests/runtime-legacy/samples/namespace-html/_config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default test({
99
1010
<math>
1111
<mrow></mrow>
12-
</svg>
12+
</math>
1313
1414
<div class="hi">hi</div>
1515
`,

0 commit comments

Comments
 (0)