1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 17:07:34 +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() };

View file

@ -349,7 +349,11 @@ private:
ParseErrorOr<NonnullRefPtr<Selector>> parse_complex_selector(TokenStream<ComponentValue>&, SelectorType);
ParseErrorOr<Optional<Selector::CompoundSelector>> parse_compound_selector(TokenStream<ComponentValue>&);
Optional<Selector::Combinator> parse_selector_combinator(TokenStream<ComponentValue>&);
enum class AllowWildcardName {
No,
Yes,
};
Optional<Selector::SimpleSelector::QualifiedName> parse_selector_qualified_name(TokenStream<ComponentValue>&, AllowWildcardName);
ParseErrorOr<Selector::SimpleSelector> parse_attribute_simple_selector(ComponentValue const&);
ParseErrorOr<Selector::SimpleSelector> parse_pseudo_simple_selector(TokenStream<ComponentValue>&);
ParseErrorOr<Optional<Selector::SimpleSelector>> parse_simple_selector(TokenStream<ComponentValue>&);

View file

@ -136,6 +136,31 @@ public:
Vector<FlyString> languages {};
};
struct Name {
Name(FlyString n)
: name(move(n))
, lowercase_name(name.to_string().to_lowercase().release_value_but_fixme_should_propagate_errors())
{
}
FlyString name;
FlyString lowercase_name;
};
// Equivalent to `<wq-name>`
// https://www.w3.org/TR/selectors-4/#typedef-wq-name
struct QualifiedName {
enum class NamespaceType {
Default, // `E`
None, // `|E`
Any, // `*|E`
Named, // `ns|E`
};
NamespaceType namespace_type { NamespaceType::Default };
FlyString namespace_ {};
Name name;
};
struct Attribute {
enum class MatchType {
HasAttribute,
@ -157,17 +182,6 @@ public:
CaseType case_type;
};
struct Name {
Name(FlyString n)
: name(move(n))
, lowercase_name(name.to_string().to_lowercase().release_value_but_fixme_should_propagate_errors())
{
}
FlyString name;
FlyString lowercase_name;
};
Type type;
Variant<Empty, Attribute, PseudoClass, PseudoElement, Name> value {};