1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 14:28:12 +00:00

LibWeb: Add SimpleSelector::QualifiedName, with parsing

This is basically a name with a namespace prefix. It will be used for
adding namespaces to Universal, TagName, and Attribute selectors.

For convenience, this can also optionally parse/store the `*` wildcard
character as the name.
This commit is contained in:
Sam Atkins 2023-08-07 16:48:44 +01:00 committed by Sam Atkins
parent 4b7b726888
commit 5042c903be
3 changed files with 104 additions and 12 deletions

View file

@ -285,6 +285,80 @@ Optional<Selector::Combinator> Parser::parse_selector_combinator(TokenStream<Com
return {};
}
Optional<Selector::SimpleSelector::QualifiedName> Parser::parse_selector_qualified_name(TokenStream<ComponentValue>& tokens, AllowWildcardName allow_wildcard_name)
{
auto is_name = [](ComponentValue const& token) {
return token.is_delim('*') || token.is(Token::Type::Ident);
};
auto get_name = [](ComponentValue const& token) {
if (token.is_delim('*'))
return FlyString::from_utf8("*"sv);
return FlyString::from_utf8(token.token().ident());
};
// There are 3 possibilities here:
// (Where <name> and <namespace> are either an <ident> or a `*` delim)
// 1) `|<name>`
// 2) `<namespace>|<name>`
// 3) `<name>`
// Whitespace is forbidden between any of these parts. https://www.w3.org/TR/selectors-4/#white-space
auto transaction = tokens.begin_transaction();
auto first_token = tokens.next_token();
if (first_token.is_delim('|')) {
// Case 1: `|<name>`
if (is_name(tokens.peek_token())) {
auto name_token = tokens.next_token();
if (allow_wildcard_name == AllowWildcardName::No && name_token.is_delim('*'))
return {};
transaction.commit();
return Selector::SimpleSelector::QualifiedName {
.namespace_type = Selector::SimpleSelector::QualifiedName::NamespaceType::None,
.name = get_name(name_token).release_value_but_fixme_should_propagate_errors(),
};
}
return {};
}
if (!is_name(first_token))
return {};
if (tokens.peek_token().is_delim('|') && is_name(tokens.peek_token(1))) {
// Case 2: `<namespace>|<name>`
(void)tokens.next_token(); // `|`
auto namespace_ = get_name(first_token).release_value_but_fixme_should_propagate_errors();
auto name = get_name(tokens.next_token()).release_value_but_fixme_should_propagate_errors();
if (allow_wildcard_name == AllowWildcardName::No && name == "*"sv)
return {};
auto namespace_type = namespace_ == "*"sv
? Selector::SimpleSelector::QualifiedName::NamespaceType::Any
: Selector::SimpleSelector::QualifiedName::NamespaceType::Named;
transaction.commit();
return Selector::SimpleSelector::QualifiedName {
.namespace_type = namespace_type,
.namespace_ = namespace_,
.name = name,
};
}
// Case 3: `<name>`
auto& name_token = first_token;
if (allow_wildcard_name == AllowWildcardName::No && name_token.is_delim('*'))
return {};
transaction.commit();
return Selector::SimpleSelector::QualifiedName {
.namespace_type = Selector::SimpleSelector::QualifiedName::NamespaceType::Default,
.name = get_name(name_token).release_value_but_fixme_should_propagate_errors(),
};
}
Parser::ParseErrorOr<Selector::SimpleSelector> Parser::parse_attribute_simple_selector(ComponentValue const& first_value)
{
auto attribute_tokens = TokenStream { first_value.block().values() };