mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 18:27:35 +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:
parent
4b7b726888
commit
5042c903be
3 changed files with 104 additions and 12 deletions
|
@ -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() };
|
||||
|
|
|
@ -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>&);
|
||||
|
|
|
@ -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 {};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue