LibWeb: Support [Reflect] on IDL String attributes that may return null

This change allows IDL interfaces to be compiled using new AK String
which have a attribute in the interface that may return null.

Without this change we would run into a compile error from code such as
the following example:

```
auto retval = impl->deprecated_attribute(HTML::AttributeNames::ref);

if (!retval.has_value()) {
    return JS::js_null();
 }
 return JS::PrimitiveString::create(vm, retval.release_value());
```

As `deprecated_attribute` returns a `DeprecatedString` instead of an
`Optional<String>`. Fix that by using the non-deprecated attribute
implementation, and falling back to the empty string for where we cannot
return null.

Also add a test here to cover a regression I almost introduced here
which was not previously covered by our test suite.

Ideally, all of this should actually just be calling
Element::get_attribute_value, but I'm not entirely sure at this stage
what the behavioral change would be to test for here. Since this
implementation preserves the previous behavior, stick with it, and add a
FIXME for now.
This commit is contained in:
Shannon Booth 2023-09-03 15:23:35 +12:00 committed by Tim Flynn
parent 6fb3586baa
commit f991e40d7f
Notes: sideshowbarker 2024-07-17 07:11:12 +09:00
3 changed files with 39 additions and 2 deletions

View file

@ -2450,9 +2450,22 @@ static void collect_attribute_values_of_an_inheritance_stack(SourceGenerator& fu
if (attribute.extended_attributes.contains("Reflect")) {
if (attribute.type->name() != "boolean") {
attribute_generator.append(R"~~~(
if (interface_in_chain.extended_attributes.contains("UseDeprecatedAKString")) {
attribute_generator.append(R"~~~(
auto @attribute.return_value_name@ = impl->deprecated_attribute(HTML::AttributeNames::@attribute.reflect_name@);
)~~~");
} else {
// FIXME: This should be calling Element::get_attribute_value: https://dom.spec.whatwg.org/#concept-element-attributes-get-value
if (attribute.type->is_nullable()) {
attribute_generator.append(R"~~~(
auto @attribute.return_value_name@ = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@);
)~~~");
} else {
attribute_generator.append(R"~~~(
auto @attribute.return_value_name@ = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@).value_or(String {});
)~~~");
}
}
} else {
attribute_generator.append(R"~~~(
auto @attribute.return_value_name@ = impl->has_attribute(HTML::AttributeNames::@attribute.reflect_name@);
@ -2776,9 +2789,22 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.getter_callback@)
if (attribute.extended_attributes.contains("Reflect")) {
if (attribute.type->name() != "boolean") {
attribute_generator.append(R"~~~(
if (interface.extended_attributes.contains("UseDeprecatedAKString")) {
attribute_generator.append(R"~~~(
auto retval = impl->deprecated_attribute(HTML::AttributeNames::@attribute.reflect_name@);
)~~~");
} else {
// FIXME: This should be calling Element::get_attribute_value: https://dom.spec.whatwg.org/#concept-element-attributes-get-value
if (attribute.type->is_nullable()) {
attribute_generator.append(R"~~~(
auto retval = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@);
)~~~");
} else {
attribute_generator.append(R"~~~(
auto retval = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@).value_or(String {});
)~~~");
}
}
} else {
attribute_generator.append(R"~~~(
auto retval = impl->has_attribute(HTML::AttributeNames::@attribute.reflect_name@);

View file

@ -0,0 +1,2 @@
initial type = ''
after setting to null = 'null'

View file

@ -0,0 +1,9 @@
<script src="include.js"></script>
<script id="script-element">
test(() => {
let s = document.getElementById("script-element");
println(`initial type = '${s.type}'`);
s.type = null;
println(`after setting to null = '${s.type}'`);
});
</script>