Skip to content

Commit c581b48

Browse files
teobgenokelvinsjk
authored andcommitted
fix: spreading attributes on option value attribute get's replaced by option's inner text (sveltejs#9125)
fixes sveltejs#9107 Apart from the problem with the option the same happens with the textarea.
1 parent 4af97ce commit c581b48

File tree

4 files changed

+45
-2
lines changed

4 files changed

+45
-2
lines changed

.changeset/tricky-planets-rush.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: recognize option value on spread attribute

packages/svelte/src/compiler/compile/nodes/Element.js

+30-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { is_html, is_svg, is_void } from '../../../shared/utils/names.js';
22
import Node from './shared/Node.js';
3+
import { walk } from 'estree-walker';
34
import Attribute from './Attribute.js';
45
import Binding from './Binding.js';
56
import EventHandler from './EventHandler.js';
@@ -430,7 +431,7 @@ export default class Element extends Node {
430431
}
431432
if (this.name === 'textarea') {
432433
if (info.children.length > 0) {
433-
const value_attribute = info.attributes.find((node) => node.name === 'value');
434+
const value_attribute = get_value_attribute(info.attributes);
434435
if (value_attribute) {
435436
component.error(value_attribute, compiler_errors.textarea_duplicate_value);
436437
return;
@@ -449,7 +450,7 @@ export default class Element extends Node {
449450
// Special case — treat these the same way:
450451
// <option>{foo}</option>
451452
// <option value={foo}>{foo}</option>
452-
const value_attribute = info.attributes.find((attribute) => attribute.name === 'value');
453+
const value_attribute = get_value_attribute(info.attributes);
453454
if (!value_attribute) {
454455
info.attributes.push({
455456
type: 'Attribute',
@@ -1420,3 +1421,30 @@ function within_custom_element(parent) {
14201421
}
14211422
return false;
14221423
}
1424+
1425+
/**
1426+
* @param {any[]} attributes
1427+
*/
1428+
function get_value_attribute(attributes) {
1429+
let node_value;
1430+
attributes.forEach((node) => {
1431+
if (node.type !== 'Spread' && node.name.toLowerCase() === 'value') {
1432+
node_value = node;
1433+
}
1434+
if (node.type === 'Spread') {
1435+
walk(/** @type {any} */ (node.expression), {
1436+
enter(/** @type {import('estree').Node} */ node) {
1437+
if (node_value) {
1438+
this.skip();
1439+
}
1440+
if (node.type === 'Identifier') {
1441+
if (/** @type {import('estree').Identifier} */ (node).name.toLowerCase() === 'value') {
1442+
node_value = node;
1443+
}
1444+
}
1445+
}
1446+
});
1447+
}
1448+
});
1449+
return node_value;
1450+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default {
2+
html: `
3+
<select>
4+
<option value="value" class="option">Label</option>
5+
</select>
6+
`
7+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<select>
2+
<option {...{ value: 'value', class: 'option' }}>Label</option>
3+
</select>

0 commit comments

Comments
 (0)