1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-09 17:44:56 +09:00

LibWeb/CSS: Automatically serialize functional pseudo-class arguments

The spec gives us a hard-coded list of functional pseudo-classes and how
to serialize them - but this list is incomplete and likely to always be
outdated compared to the list of pseudo-classes that exist. So instead,
use the generated metadata we already have to serialize their arguments
based on their type.

This fixes :dir() and :has(), which previously did not serialize their
arguments.

Gets us 26 passes (including 6 from that as-yet-unmerged :dir() test).
This commit is contained in:
Sam Atkins 2025-05-16 14:24:40 +01:00 committed by Andreas Kling
parent 5f144f366d
commit 7aed541ed0
Notes: github-actions[bot] 2025-05-16 22:32:00 +00:00
3 changed files with 49 additions and 39 deletions

View file

@ -444,21 +444,31 @@ String Selector::SimpleSelector::serialize() const
s.append(':');
s.append(pseudo_class_name(pseudo_class.type));
s.append('(');
if (pseudo_class.type == PseudoClass::NthChild
|| pseudo_class.type == PseudoClass::NthLastChild
|| pseudo_class.type == PseudoClass::NthOfType
|| pseudo_class.type == PseudoClass::NthLastOfType) {
// NB: The spec list is incomplete. For ease of maintenance, we use the data from PseudoClasses.json for
// this instead of a hard-coded list.
switch (metadata.parameter_type) {
case PseudoClassMetadata::ParameterType::None:
break;
case PseudoClassMetadata::ParameterType::ANPlusB:
case PseudoClassMetadata::ParameterType::ANPlusBOf:
// The result of serializing the value using the rules to serialize an <an+b> value.
s.append(pseudo_class.nth_child_pattern.serialize());
} else if (pseudo_class.type == PseudoClass::Not
|| pseudo_class.type == PseudoClass::Is
|| pseudo_class.type == PseudoClass::Where) {
break;
case PseudoClassMetadata::ParameterType::CompoundSelector:
case PseudoClassMetadata::ParameterType::ForgivingSelectorList:
case PseudoClassMetadata::ParameterType::ForgivingRelativeSelectorList:
case PseudoClassMetadata::ParameterType::RelativeSelectorList:
case PseudoClassMetadata::ParameterType::SelectorList:
// The result of serializing the value using the rules for serializing a group of selectors.
// NOTE: `:is()` and `:where()` aren't in the spec for this yet, but it should be!
s.append(serialize_a_group_of_selectors(pseudo_class.argument_selector_list));
} else if (pseudo_class.type == PseudoClass::Lang) {
break;
case PseudoClassMetadata::ParameterType::Ident:
s.append(string_from_keyword(pseudo_class.keyword.value()));
break;
case PseudoClassMetadata::ParameterType::LanguageRanges:
// The serialization of a comma-separated list of each arguments serialization as a string, preserving relative order.
s.join(", "sv, pseudo_class.languages);
break;
}
s.append(')');
}

View file

@ -2,14 +2,14 @@ Harness status: OK
Found 10 tests
3 Pass
7 Fail
Fail ":dir(rtl)" should be a valid selector
Fail ":dir( rtl )" should be a valid selector
Fail ":dir(ltr):dir(rtl)" should be a valid selector
Fail "foo:dir(RTL)" should be a valid selector
Fail ":dir(auto)" should be a valid selector
Fail ":dir(none)" should be a valid selector
9 Pass
1 Fail
Pass ":dir(rtl)" should be a valid selector
Pass ":dir( rtl )" should be a valid selector
Pass ":dir(ltr):dir(rtl)" should be a valid selector
Pass "foo:dir(RTL)" should be a valid selector
Pass ":dir(auto)" should be a valid selector
Pass ":dir(none)" should be a valid selector
Fail ":dir(something-made-up)" should be a valid selector
Pass ":dir()" should be an invalid selector
Pass ":dir(\"ltr\")" should be an invalid selector

View file

@ -2,31 +2,31 @@ Harness status: OK
Found 29 tests
6 Pass
23 Fail
Fail ":has(a)" should be a valid selector
Fail ":has(#a)" should be a valid selector
Fail ":has(.a)" should be a valid selector
Fail ":has([a])" should be a valid selector
Fail ":has([a=\"b\"])" should be a valid selector
Fail ":has([a|=\"b\"])" should be a valid selector
Fail ":has(:hover)" should be a valid selector
Fail "*:has(.a)" should be a valid selector
Fail ".a:has(.b)" should be a valid selector
26 Pass
3 Fail
Pass ":has(a)" should be a valid selector
Pass ":has(#a)" should be a valid selector
Pass ":has(.a)" should be a valid selector
Pass ":has([a])" should be a valid selector
Pass ":has([a=\"b\"])" should be a valid selector
Pass ":has([a|=\"b\"])" should be a valid selector
Pass ":has(:hover)" should be a valid selector
Pass "*:has(.a)" should be a valid selector
Pass ".a:has(.b)" should be a valid selector
Fail ".a:has(> .b)" should be a valid selector
Fail ".a:has(~ .b)" should be a valid selector
Fail ".a:has(+ .b)" should be a valid selector
Fail ".a:has(.b) .c" should be a valid selector
Fail ".a .b:has(.c)" should be a valid selector
Fail ".a .b:has(.c .d)" should be a valid selector
Fail ".a .b:has(.c .d) .e" should be a valid selector
Fail ".a:has(.b:is(.c .d))" should be a valid selector
Fail ".a:is(.b:has(.c) .d)" should be a valid selector
Fail ".a:not(:has(.b))" should be a valid selector
Fail ".a:has(:not(.b))" should be a valid selector
Fail ".a:has(.b):has(.c)" should be a valid selector
Fail "*|*:has(*)" should be a valid selector
Fail ":has(*|*)" should be a valid selector
Pass ".a:has(.b) .c" should be a valid selector
Pass ".a .b:has(.c)" should be a valid selector
Pass ".a .b:has(.c .d)" should be a valid selector
Pass ".a .b:has(.c .d) .e" should be a valid selector
Pass ".a:has(.b:is(.c .d))" should be a valid selector
Pass ".a:is(.b:has(.c) .d)" should be a valid selector
Pass ".a:not(:has(.b))" should be a valid selector
Pass ".a:has(:not(.b))" should be a valid selector
Pass ".a:has(.b):has(.c)" should be a valid selector
Pass "*|*:has(*)" should be a valid selector
Pass ":has(*|*)" should be a valid selector
Pass ":has" should be an invalid selector
Pass ".a:has" should be an invalid selector
Pass ".a:has b" should be an invalid selector