Skip to content

Commit 2d38184

Browse files
Rich-Harrisadigubadummdidumm
authored
chore: check namespace inside set attributes (#15443)
* set_attributes for <svelte:element> * changeset * Update .changeset/wise-hats-wonder.md Co-authored-by: Simon H <[email protected]> * add changeset * remove `chore` changeset — no need for non-user-facing changes to appear in changelog * Update packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js * determine element traits inside set_attributes * unused * stash lookup --------- Co-authored-by: adiguba <[email protected]> Co-authored-by: Simon H <[email protected]>
1 parent 43ff304 commit 2d38184

File tree

6 files changed

+37
-41
lines changed

6 files changed

+37
-41
lines changed

.changeset/quiet-baboons-listen.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: respect `svelte-ignore hydration_attribute_changed` on elements with spread attributes

packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -221,16 +221,7 @@ export function RegularElement(node, context) {
221221
if (has_spread) {
222222
const attributes_id = b.id(context.state.scope.generate('attributes'));
223223

224-
build_set_attributes(
225-
attributes,
226-
class_directives,
227-
context,
228-
node,
229-
node_id,
230-
attributes_id,
231-
(node.metadata.svg || node.metadata.mathml || is_custom_element_node(node)) && b.true,
232-
is_custom_element_node(node) && b.true
233-
);
224+
build_set_attributes(attributes, class_directives, context, node, node_id, attributes_id);
234225

235226
// If value binding exists, that one takes care of calling $.init_select
236227
if (node.name === 'select' && !bindings.has('value')) {

packages/svelte/src/compiler/phases/3-transform/client/visitors/SvelteElement.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,7 @@ export function SvelteElement(node, context) {
114114
inner_context,
115115
node,
116116
element_id,
117-
attributes_id,
118-
b.binary('===', b.member(element_id, 'namespaceURI'), b.id('$.NAMESPACE_SVG')),
119-
b.call(b.member(b.member(element_id, 'nodeName'), 'includes'), b.literal('-'))
117+
attributes_id
120118
);
121119
}
122120

packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,14 @@ import { build_template_chunk, get_expression_id } from './utils.js';
1717
* @param {AST.RegularElement | AST.SvelteElement} element
1818
* @param {Identifier} element_id
1919
* @param {Identifier} attributes_id
20-
* @param {false | Expression} preserve_attribute_case
21-
* @param {false | Expression} is_custom_element
2220
*/
2321
export function build_set_attributes(
2422
attributes,
2523
class_directives,
2624
context,
2725
element,
2826
element_id,
29-
attributes_id,
30-
preserve_attribute_case,
31-
is_custom_element
27+
attributes_id
3228
) {
3329
let is_dynamic = false;
3430

@@ -91,8 +87,6 @@ export function build_set_attributes(
9187
element.metadata.scoped &&
9288
context.state.analysis.css.hash !== '' &&
9389
b.literal(context.state.analysis.css.hash),
94-
preserve_attribute_case,
95-
is_custom_element,
9690
is_ignored(element, 'hydration_attribute_changed') && b.true
9791
);
9892

packages/svelte/src/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export const UNINITIALIZED = Symbol();
3333
export const FILENAME = Symbol('filename');
3434
export const HMR = Symbol('hmr');
3535

36+
export const NAMESPACE_HTML = 'http://www.w3.org/1999/xhtml';
3637
export const NAMESPACE_SVG = 'http://www.w3.org/2000/svg';
3738
export const NAMESPACE_MATHML = 'http://www.w3.org/1998/Math/MathML';
3839

packages/svelte/src/internal/client/dom/elements/attributes.js

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@ import {
1515
} from '../../runtime.js';
1616
import { clsx } from '../../../shared/attributes.js';
1717
import { set_class } from './class.js';
18+
import { NAMESPACE_HTML } from '../../../../constants.js';
1819

1920
export const CLASS = Symbol('class');
2021
export const STYLE = Symbol('style');
2122

23+
const IS_CUSTOM_ELEMENT = Symbol('is custom element');
24+
const IS_HTML = Symbol('is html');
25+
2226
/**
2327
* The value/checked attribute in the template actually corresponds to the defaultValue property, so we need
2428
* to remove it upon hydration to avoid a bug when someone resets the form value.
@@ -63,8 +67,7 @@ export function remove_input_defaults(input) {
6367
* @param {any} value
6468
*/
6569
export function set_value(element, value) {
66-
// @ts-expect-error
67-
var attributes = (element.__attributes ??= {});
70+
var attributes = get_attributes(element);
6871

6972
if (
7073
attributes.value ===
@@ -87,8 +90,7 @@ export function set_value(element, value) {
8790
* @param {boolean} checked
8891
*/
8992
export function set_checked(element, checked) {
90-
// @ts-expect-error
91-
var attributes = (element.__attributes ??= {});
93+
var attributes = get_attributes(element);
9294

9395
if (
9496
attributes.checked ===
@@ -151,8 +153,7 @@ export function set_default_value(element, value) {
151153
* @param {boolean} [skip_warning]
152154
*/
153155
export function set_attribute(element, attribute, value, skip_warning) {
154-
// @ts-expect-error
155-
var attributes = (element.__attributes ??= {});
156+
var attributes = get_attributes(element);
156157

157158
if (hydrating) {
158159
attributes[attribute] = element.getAttribute(attribute);
@@ -261,20 +262,15 @@ export function set_custom_element_data(node, prop, value) {
261262
* @param {Record<string | symbol, any> | undefined} prev
262263
* @param {Record<string | symbol, any>} next New attributes - this function mutates this object
263264
* @param {string} [css_hash]
264-
* @param {boolean} [preserve_attribute_case]
265-
* @param {boolean} [is_custom_element]
266265
* @param {boolean} [skip_warning]
267266
* @returns {Record<string, any>}
268267
*/
269-
export function set_attributes(
270-
element,
271-
prev,
272-
next,
273-
css_hash,
274-
preserve_attribute_case = false,
275-
is_custom_element = false,
276-
skip_warning = false
277-
) {
268+
export function set_attributes(element, prev, next, css_hash, skip_warning = false) {
269+
var attributes = get_attributes(element);
270+
271+
var is_custom_element = attributes[IS_CUSTOM_ELEMENT];
272+
var preserve_attribute_case = !attributes[IS_HTML];
273+
278274
// If we're hydrating but the custom element is from Svelte, and it already scaffolded,
279275
// then it might run block logic in hydration mode, which we have to prevent.
280276
let is_hydrating_custom_element = hydrating && is_custom_element;
@@ -299,9 +295,6 @@ export function set_attributes(
299295

300296
var setters = get_setters(element);
301297

302-
// @ts-expect-error
303-
var attributes = /** @type {Record<string, unknown>} **/ (element.__attributes ??= {});
304-
305298
// since key is captured we use const
306299
for (const key in next) {
307300
// let instead of var because referenced in a closure
@@ -432,7 +425,7 @@ export function set_attributes(
432425
// @ts-ignore
433426
element[name] = value;
434427
} else if (typeof value !== 'function') {
435-
set_attribute(element, name, value);
428+
set_attribute(element, name, value, skip_warning);
436429
}
437430
}
438431
if (key === 'style' && '__styles' in element) {
@@ -448,6 +441,20 @@ export function set_attributes(
448441
return current;
449442
}
450443

444+
/**
445+
*
446+
* @param {Element} element
447+
*/
448+
function get_attributes(element) {
449+
return /** @type {Record<string | symbol, unknown>} **/ (
450+
// @ts-expect-error
451+
element.__attributes ??= {
452+
[IS_CUSTOM_ELEMENT]: element.nodeName.includes('-'),
453+
[IS_HTML]: element.namespaceURI === NAMESPACE_HTML
454+
}
455+
);
456+
}
457+
451458
/** @type {Map<string, string[]>} */
452459
var setters_cache = new Map();
453460

0 commit comments

Comments
 (0)