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
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(')');
}