LibWeb/CSS: Add custom-ident blacklists to Properties.json

These excluded values use a similar notation to the ranges for numeric
types: `![foo,bar,baz]` to exclude `foo`, `bar`, and `baz`.
This commit is contained in:
Sam Atkins 2025-02-24 14:59:03 +00:00
commit c729c3fcee
Notes: github-actions[bot] 2025-02-26 11:24:14 +00:00
3 changed files with 64 additions and 7 deletions

View file

@ -72,6 +72,7 @@ The `valid-types` array lists the names of CSS value types, as defined in the la
[CSS Values and Units spec](https://www.w3.org/TR/css-values/), without the `<>` around them. [CSS Values and Units spec](https://www.w3.org/TR/css-values/), without the `<>` around them.
For numeric types, we use the [bracketed range notation](https://www.w3.org/TR/css-values-4/#css-bracketed-range-notation), For numeric types, we use the [bracketed range notation](https://www.w3.org/TR/css-values-4/#css-bracketed-range-notation),
for example `width` can take any non-negative length, so it has `"length [0,∞]"` in its `valid-types` array. for example `width` can take any non-negative length, so it has `"length [0,∞]"` in its `valid-types` array.
For `<custom-ident>`s, the excluded identifiers are placed within `![]`, for example `"custom-ident ![all,none]"`.
## Keywords.json ## Keywords.json

View file

@ -247,7 +247,7 @@
"initial": "none", "initial": "none",
"valid-types": [ "valid-types": [
"string", "string",
"custom-ident" "custom-ident ![none]"
], ],
"valid-identifiers": [ "valid-identifiers": [
"none" "none"
@ -880,7 +880,15 @@
"affects-layout": false, "affects-layout": false,
"animation-type": "discrete", "animation-type": "discrete",
"inherited": true, "inherited": true,
"initial": "normal" "initial": "normal",
"valid-types": [
"custom-ident ![normal,light,dark,only]"
],
"valid-identifiers": [
"normal",
"light",
"dark"
]
}, },
"column-count": { "column-count": {
"animation-type": "by-computed-value", "animation-type": "by-computed-value",
@ -975,7 +983,7 @@
"inherited": false, "inherited": false,
"initial": "none", "initial": "none",
"valid-types": [ "valid-types": [
"custom-ident", "custom-ident ![none]",
"integer [-∞,∞]" "integer [-∞,∞]"
], ],
"valid-identifiers": [ "valid-identifiers": [
@ -987,7 +995,7 @@
"inherited": false, "inherited": false,
"initial": "none", "initial": "none",
"valid-types": [ "valid-types": [
"custom-ident", "custom-ident ![none]",
"integer [-∞,∞]" "integer [-∞,∞]"
], ],
"valid-identifiers": [ "valid-identifiers": [
@ -999,7 +1007,7 @@
"inherited": false, "inherited": false,
"initial": "none", "initial": "none",
"valid-types": [ "valid-types": [
"custom-ident", "custom-ident ![none]",
"integer [-∞,∞]" "integer [-∞,∞]"
], ],
"valid-identifiers": [ "valid-identifiers": [
@ -2841,7 +2849,7 @@
"initial": "all", "initial": "all",
"valid-types": [ "valid-types": [
"string", "string",
"custom-ident" "custom-ident ![all,none]"
], ],
"valid-identifiers": [ "valid-identifiers": [
"all", "all",
@ -2902,7 +2910,7 @@
"inherited": false, "inherited": false,
"initial": "none", "initial": "none",
"valid-types": [ "valid-types": [
"custom-ident" "custom-ident ![auto,none]"
], ],
"valid-identifiers": [ "valid-identifiers": [
"none" "none"

View file

@ -250,6 +250,7 @@ enum class ValueType {
bool property_accepts_type(PropertyID, ValueType); bool property_accepts_type(PropertyID, ValueType);
bool property_accepts_keyword(PropertyID, Keyword); bool property_accepts_keyword(PropertyID, Keyword);
Optional<ValueType> property_resolves_percentages_relative_to(PropertyID); Optional<ValueType> property_resolves_percentages_relative_to(PropertyID);
Vector<StringView> property_custom_ident_blacklist(PropertyID);
// These perform range-checking, but are also safe to call with properties that don't accept that type. (They'll just return false.) // These perform range-checking, but are also safe to call with properties that don't accept that type. (They'll just return false.)
bool property_accepts_angle(PropertyID, Angle const&); bool property_accepts_angle(PropertyID, Angle const&);
@ -938,6 +939,53 @@ Optional<ValueType> property_resolves_percentages_relative_to(PropertyID propert
} }
} }
Vector<StringView> property_custom_ident_blacklist(PropertyID property_id)
{
switch (property_id) {
)~~~");
properties.for_each_member([&](auto& name, auto& value) {
VERIFY(value.is_object());
auto& object = value.as_object();
if (is_legacy_alias(object))
return;
// We only have a custom-ident blacklist if we accept custom idents!
if (auto maybe_valid_types = object.get_array("valid-types"sv); maybe_valid_types.has_value() && !maybe_valid_types->is_empty()) {
auto& valid_types = maybe_valid_types.value();
for (auto const& valid_type : valid_types.values()) {
auto type_and_parameters = MUST(valid_type.as_string().split(' '));
if (type_and_parameters.first() != "custom-ident"sv || type_and_parameters.size() == 1)
continue;
VERIFY(type_and_parameters.size() == 2);
auto parameters_string = type_and_parameters[1].bytes_as_string_view();
VERIFY(parameters_string.starts_with("!["sv) && parameters_string.ends_with(']'));
auto blacklisted_keywords = parameters_string.substring_view(2, parameters_string.length() - 3).split_view(',');
auto property_generator = generator.fork();
property_generator.set("property_name:titlecase", title_casify(name));
property_generator.append(R"~~~(
case PropertyID::@property_name:titlecase@:
return Vector { )~~~");
for (auto const& keyword : blacklisted_keywords) {
auto value_generator = property_generator.fork();
value_generator.set("keyword", keyword);
value_generator.append("\"@keyword@\"sv, ");
}
property_generator.appendln("};");
}
}
});
generator.append(R"~~~(
default:
return {};
}
}
size_t property_maximum_value_count(PropertyID property_id) size_t property_maximum_value_count(PropertyID property_id)
{ {
switch (property_id) { switch (property_id) {