Repository: LadybirdBrowser/ladybird
File: Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSPropertyID.cpp (C++)

Code before:
    default:
        return false;
    }
}

AcceptedTypeRangeMap property_accepted_type_ranges(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;

        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();
            auto property_generator = generator.fork();
            property_generator.set("name:titlecase", title_casify(name));

            StringBuilder ranges_builder;

            // Opacity values are unique in that the range which calculated and interpolated values should be clamped
            // to [0,1] is different from the range of allowed values [-∞,∞]. To handle this we set the allowed range
            // in Properties.json to [-∞,∞] but overwrite it to [0,1] here.
            if (first_is_one_of(name, "opacity"sv, "fill-opacity"sv, "flood-opacity"sv, "stop-opacity"sv, "stroke-opacity"sv)) {
                ranges_builder.append("{ ValueType::Number, { 0, 1 } }, { ValueType::Percentage, { 0, 100 } }"sv);
            } else {
                for (auto& type : valid_types.values()) {
                    VERIFY(type.is_string());

                    Vector<String> type_parts = MUST(type.as_string().split(' '));

                    if (type_parts.size() < 2)
                        continue;

                    auto type_name = type_parts.first();

                    if (type_name == "custom-ident")
                        continue;

                    // Drop the brackets on the range e.g. "[-∞,∞]" -> "-∞,∞"
                    auto type_range = MUST(type_parts.get(1)->substring_from_byte_offset(1, type_parts.get(1)->byte_count() - 2));

                    auto limits = MUST(type_range.split(','));

                    if (limits.size() != 2)
                        VERIFY_NOT_REACHED();

                    // FIXME: Use min and max values for i32 instead of float where applicable (e.g. for "integer")

Review comment (suggestion):
Can you mark this as a FIXME? With this, we'd now have different functions `property_accepts_number/percentage()` and `property_accepted_type_ranges()` which sound very similar, but produce different results. I don't like that much, even though it does solve the problem and those functions are used at different stages.

These properties all take [`<opacity-value>`](https://drafts.csswg.org/css-color-4/#typedef-opacity-opacity-value), so it might be possible to instead parse/compute that in a special way instead. Though I'm struggling to think how that would work.

Code after:
    default:
        return false;
    }
}

AcceptedTypeRangeMap property_accepted_type_ranges(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;

        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();
            auto property_generator = generator.fork();
            property_generator.set("name:titlecase", title_casify(name));

            StringBuilder ranges_builder;

            // Opacity values are unique in that the range which calculated and interpolated values should be clamped
            // to [0,1] is different from the range of allowed values [-∞,∞]. To handle this we set the allowed range
            // in Properties.json to [-∞,∞] but overwrite it to [0,1] here.
            // FIXME: This is confusing as property_accepts_{number,percentage}() has a different range from this
            //        despite the names sounding similar.
            if (first_is_one_of(name, "opacity"sv, "fill-opacity"sv, "flood-opacity"sv, "stop-opacity"sv, "stroke-opacity"sv)) {
                ranges_builder.append("{ ValueType::Number, { 0, 1 } }, { ValueType::Percentage, { 0, 100 } }"sv);
            } else {
                for (auto& type : valid_types.values()) {
                    VERIFY(type.is_string());

                    Vector<String> type_parts = MUST(type.as_string().split(' '));

                    if (type_parts.size() < 2)
                        continue;

                    auto type_name = type_parts.first();

                    if (type_name == "custom-ident")
                        continue;

                    // Drop the brackets on the range e.g. "[-∞,∞]" -> "-∞,∞"
                    auto type_range = MUST(type_parts.get(1)->substring_from_byte_offset(1, type_parts.get(1)->byte_count() - 2));

                    auto limits = MUST(type_range.split(','));

                    if (limits.size() != 2)
                        VERIFY_NOT_REACHED();