2020-01-18 09:38:21 +01:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
2023-05-10 17:28:15 +01:00
* Copyright ( c ) 2021 - 2023 , Sam Atkins < atkinssj @ serenityos . org >
2020-01-18 09:38:21 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 09:38:21 +01:00
*/
2022-03-08 14:36:18 +00:00
# include "GeneratorUtil.h"
2023-05-10 17:28:15 +01:00
# include <AK/GenericShorthands.h>
2020-10-23 18:37:35 +02:00
# include <AK/SourceGenerator.h>
2019-11-18 11:12:58 +01:00
# include <AK/StringBuilder.h>
2022-04-01 17:41:43 +01:00
# include <LibCore/ArgsParser.h>
2022-03-10 11:55:06 +00:00
# include <LibMain/Main.h>
2021-09-29 20:29:44 +02:00
2023-02-09 03:02:46 +01:00
ErrorOr < void > generate_header_file ( JsonObject & properties , Core : : File & file ) ;
ErrorOr < void > generate_implementation_file ( JsonObject & properties , Core : : File & file ) ;
2022-04-01 17:41:43 +01:00
2023-05-10 17:28:15 +01:00
static bool type_name_is_enum ( StringView type_name )
{
2023-05-25 12:43:52 +01:00
return ! AK : : first_is_one_of ( type_name , " angle " sv , " color " sv , " custom-ident " sv , " frequency " sv , " image " sv , " integer " sv , " length " sv , " number " sv , " percentage " sv , " rect " sv , " resolution " sv , " string " sv , " time " sv , " url " sv ) ;
2023-05-10 17:28:15 +01:00
}
2022-03-10 11:55:06 +00:00
ErrorOr < int > serenity_main ( Main : : Arguments arguments )
2019-11-18 11:12:58 +01:00
{
2022-04-01 17:41:43 +01:00
StringView generated_header_path ;
StringView generated_implementation_path ;
StringView properties_json_path ;
Core : : ArgsParser args_parser ;
args_parser . add_option ( generated_header_path , " Path to the PropertyID header file to generate " , " generated-header-path " , ' h ' , " generated-header-path " ) ;
args_parser . add_option ( generated_implementation_path , " Path to the PropertyID implementation file to generate " , " generated-implementation-path " , ' c ' , " generated-implementation-path " ) ;
args_parser . add_option ( properties_json_path , " Path to the JSON file to read from " , " json-path " , ' j ' , " json-path " ) ;
args_parser . parse ( arguments ) ;
2019-11-18 11:12:58 +01:00
2022-04-01 17:41:43 +01:00
auto json = TRY ( read_entire_file_as_json ( properties_json_path ) ) ;
2021-11-15 01:46:51 +01:00
VERIFY ( json . is_object ( ) ) ;
2022-04-01 17:41:43 +01:00
auto properties = json . as_object ( ) ;
2023-02-09 03:02:46 +01:00
auto generated_header_file = TRY ( Core : : File : : open ( generated_header_path , Core : : File : : OpenMode : : Write ) ) ;
auto generated_implementation_file = TRY ( Core : : File : : open ( generated_implementation_path , Core : : File : : OpenMode : : Write ) ) ;
2022-04-01 17:41:43 +01:00
TRY ( generate_header_file ( properties , * generated_header_file ) ) ;
TRY ( generate_implementation_file ( properties , * generated_implementation_file ) ) ;
return 0 ;
}
2023-02-09 03:02:46 +01:00
ErrorOr < void > generate_header_file ( JsonObject & properties , Core : : File & file )
2022-04-01 17:41:43 +01:00
{
StringBuilder builder ;
SourceGenerator generator { builder } ;
generator . append ( R " ~~~(
# pragma once
# include <AK/NonnullRefPtr.h>
# include <AK/StringView.h>
# include <AK/Traits.h>
2023-02-28 16:54:25 +00:00
# include <LibJS/Forward.h>
2022-04-01 17:41:43 +01:00
# include <LibWeb/Forward.h>
namespace Web : : CSS {
enum class PropertyID {
Invalid ,
Custom ,
) ~ ~ ~ " );
2022-12-04 18:02:33 +00:00
Vector < DeprecatedString > shorthand_property_ids ;
Vector < DeprecatedString > longhand_property_ids ;
2022-04-01 17:41:43 +01:00
properties . for_each_member ( [ & ] ( auto & name , auto & value ) {
VERIFY ( value . is_object ( ) ) ;
2022-07-11 17:32:29 +00:00
if ( value . as_object ( ) . has ( " longhands " sv ) )
2022-04-01 17:41:43 +01:00
shorthand_property_ids . append ( name ) ;
else
longhand_property_ids . append ( name ) ;
} ) ;
auto first_property_id = shorthand_property_ids . first ( ) ;
auto last_property_id = longhand_property_ids . last ( ) ;
2019-11-18 11:12:58 +01:00
2022-04-01 17:41:43 +01:00
for ( auto & name : shorthand_property_ids ) {
auto member_generator = generator . fork ( ) ;
member_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
member_generator . append ( R " ~~~(
@ name : titlecase @ ,
) ~ ~ ~ " );
}
for ( auto & name : longhand_property_ids ) {
auto member_generator = generator . fork ( ) ;
member_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
member_generator . append ( R " ~~~(
@ name : titlecase @ ,
) ~ ~ ~ " );
}
2021-09-11 17:26:38 +01:00
2022-04-01 17:41:43 +01:00
generator . set ( " first_property_id " , title_casify ( first_property_id ) ) ;
generator . set ( " last_property_id " , title_casify ( last_property_id ) ) ;
generator . set ( " first_shorthand_property_id " , title_casify ( shorthand_property_ids . first ( ) ) ) ;
generator . set ( " last_shorthand_property_id " , title_casify ( shorthand_property_ids . last ( ) ) ) ;
generator . set ( " first_longhand_property_id " , title_casify ( longhand_property_ids . first ( ) ) ) ;
generator . set ( " last_longhand_property_id " , title_casify ( longhand_property_ids . last ( ) ) ) ;
generator . append ( R " ~~~(
} ;
2023-05-10 13:01:30 +01:00
Optional < PropertyID > property_id_from_camel_case_string ( StringView ) ;
Optional < PropertyID > property_id_from_string ( StringView ) ;
2022-07-11 17:32:29 +00:00
StringView string_from_property_id ( PropertyID ) ;
2022-04-01 17:41:43 +01:00
bool is_inherited_property ( PropertyID ) ;
2023-05-02 15:09:46 +01:00
ErrorOr < NonnullRefPtr < StyleValue > > property_initial_value ( JS : : Realm & , PropertyID ) ;
2022-04-01 17:41:43 +01:00
2023-05-10 17:28:15 +01:00
enum class ValueType {
Angle ,
Color ,
2023-05-25 12:43:52 +01:00
CustomIdent ,
2023-05-10 17:28:15 +01:00
FilterValueList ,
Frequency ,
Image ,
Integer ,
Length ,
Number ,
Paint ,
Percentage ,
Position ,
Rect ,
Resolution ,
String ,
Time ,
Url ,
} ;
bool property_accepts_type ( PropertyID , ValueType ) ;
bool property_accepts_identifier ( PropertyID , ValueID ) ;
2022-04-01 17:41:43 +01:00
size_t property_maximum_value_count ( PropertyID ) ;
bool property_affects_layout ( PropertyID ) ;
bool property_affects_stacking_context ( PropertyID ) ;
constexpr PropertyID first_property_id = PropertyID : : @ first_property_id @ ;
constexpr PropertyID last_property_id = PropertyID : : @ last_property_id @ ;
constexpr PropertyID first_shorthand_property_id = PropertyID : : @ first_shorthand_property_id @ ;
constexpr PropertyID last_shorthand_property_id = PropertyID : : @ last_shorthand_property_id @ ;
constexpr PropertyID first_longhand_property_id = PropertyID : : @ first_longhand_property_id @ ;
constexpr PropertyID last_longhand_property_id = PropertyID : : @ last_longhand_property_id @ ;
enum class Quirk {
// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
HashlessHexColor ,
// https://quirks.spec.whatwg.org/#the-unitless-length-quirk
UnitlessLength ,
} ;
bool property_has_quirk ( PropertyID , Quirk ) ;
} // namespace Web::CSS
namespace AK {
template < >
struct Traits < Web : : CSS : : PropertyID > : public GenericTraits < Web : : CSS : : PropertyID > {
static unsigned hash ( Web : : CSS : : PropertyID property_id ) { return int_hash ( ( unsigned ) property_id ) ; }
} ;
} // namespace AK
) ~ ~ ~ " );
2023-03-01 16:28:32 +01:00
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
2022-04-01 17:41:43 +01:00
return { } ;
}
2023-02-09 03:02:46 +01:00
ErrorOr < void > generate_implementation_file ( JsonObject & properties , Core : : File & file )
2022-04-01 17:41:43 +01:00
{
2020-10-23 18:37:35 +02:00
StringBuilder builder ;
SourceGenerator generator { builder } ;
generator . append ( R " ~~~(
# include <AK/Assertions.h>
2022-04-14 11:23:23 +01:00
# include <LibWeb/CSS/Enums.h>
2021-08-16 17:42:09 +01:00
# include <LibWeb/CSS/Parser/Parser.h>
2020-10-23 18:37:35 +02:00
# include <LibWeb/CSS/PropertyID.h>
2021-08-16 17:42:09 +01:00
# include <LibWeb/CSS/StyleValue.h>
2023-03-24 17:28:43 +00:00
# include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
2023-02-17 16:43:28 +00:00
# include <LibWeb/Infra/Strings.h>
2020-10-23 18:37:35 +02:00
namespace Web : : CSS {
2019-11-18 11:12:58 +01:00
2023-05-10 13:01:30 +01:00
Optional < PropertyID > property_id_from_camel_case_string ( StringView string )
2021-09-29 20:29:44 +02:00
{
) ~ ~ ~ " );
properties . for_each_member ( [ & ] ( auto & name , auto & value ) {
VERIFY ( value . is_object ( ) ) ;
auto member_generator = generator . fork ( ) ;
member_generator . set ( " name " , name ) ;
member_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
member_generator . set ( " name:camelcase " , camel_casify ( name ) ) ;
member_generator . append ( R " ~~~(
2023-03-10 08:48:54 +01:00
if ( string . equals_ignoring_ascii_case ( " @name:camelcase@ " sv ) )
2021-09-29 20:29:44 +02:00
return PropertyID : : @ name : titlecase @ ;
) ~ ~ ~ " );
} ) ;
generator . append ( R " ~~~(
2023-05-10 13:01:30 +01:00
return { } ;
2021-09-29 20:29:44 +02:00
}
2023-05-10 13:01:30 +01:00
Optional < PropertyID > property_id_from_string ( StringView string )
2020-10-23 18:37:35 +02:00
{
) ~ ~ ~ " );
2019-11-18 11:12:58 +01:00
2021-09-11 17:26:38 +01:00
properties . for_each_member ( [ & ] ( auto & name , auto & value ) {
2021-02-23 20:42:32 +01:00
VERIFY ( value . is_object ( ) ) ;
2020-10-23 18:37:35 +02:00
auto member_generator = generator . fork ( ) ;
member_generator . set ( " name " , name ) ;
member_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
member_generator . append ( R " ~~~(
2023-02-17 16:43:28 +00:00
if ( Infra : : is_ascii_case_insensitive_match ( string , " @name@ " sv ) )
2020-10-23 18:37:35 +02:00
return PropertyID : : @ name : titlecase @ ;
) ~ ~ ~ " );
2019-11-18 11:12:58 +01:00
} ) ;
2020-10-23 18:37:35 +02:00
generator . append ( R " ~~~(
2023-05-10 13:01:30 +01:00
return { } ;
2020-10-23 18:37:35 +02:00
}
2019-11-18 11:12:58 +01:00
2022-07-11 17:32:29 +00:00
StringView string_from_property_id ( PropertyID property_id ) {
2020-10-23 18:37:35 +02:00
switch ( property_id ) {
) ~ ~ ~ " );
2019-11-18 11:12:58 +01:00
2021-09-11 17:26:38 +01:00
properties . for_each_member ( [ & ] ( auto & name , auto & value ) {
2021-02-23 20:42:32 +01:00
VERIFY ( value . is_object ( ) ) ;
2020-10-23 18:37:35 +02:00
auto member_generator = generator . fork ( ) ;
member_generator . set ( " name " , name ) ;
member_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
member_generator . append ( R " ~~~(
case PropertyID : : @ name : titlecase @ :
2022-07-11 17:32:29 +00:00
return " @name@ " sv ;
2021-08-16 16:07:13 +01:00
) ~ ~ ~ " );
2019-11-18 11:12:58 +01:00
} ) ;
2020-10-23 18:37:35 +02:00
generator . append ( R " ~~~(
default :
2022-07-11 17:32:29 +00:00
return " (invalid CSS::PropertyID) " sv ;
2020-10-23 18:37:35 +02:00
}
}
2021-08-16 16:07:13 +01:00
bool is_inherited_property ( PropertyID property_id )
{
switch ( property_id ) {
) ~ ~ ~ " );
2021-09-11 17:26:38 +01:00
properties . for_each_member ( [ & ] ( auto & name , auto & value ) {
2021-08-16 16:07:13 +01:00
VERIFY ( value . is_object ( ) ) ;
bool inherited = false ;
2022-07-11 17:32:29 +00:00
if ( value . as_object ( ) . has ( " inherited " sv ) ) {
2022-12-21 14:37:27 +00:00
auto inherited_value = value . as_object ( ) . get_bool ( " inherited " sv ) ;
VERIFY ( inherited_value . has_value ( ) ) ;
inherited = inherited_value . value ( ) ;
2021-08-16 16:07:13 +01:00
}
if ( inherited ) {
auto member_generator = generator . fork ( ) ;
member_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
member_generator . append ( R " ~~~(
case PropertyID : : @ name : titlecase @ :
return true ;
) ~ ~ ~ " );
}
} ) ;
generator . append ( R " ~~~(
default :
return false ;
}
}
2022-03-16 17:46:24 +01:00
bool property_affects_layout ( PropertyID property_id )
{
switch ( property_id ) {
) ~ ~ ~ " );
properties . for_each_member ( [ & ] ( auto & name , auto & value ) {
VERIFY ( value . is_object ( ) ) ;
bool affects_layout = true ;
2022-07-11 17:32:29 +00:00
if ( value . as_object ( ) . has ( " affects-layout " sv ) )
2022-12-21 14:37:27 +00:00
affects_layout = value . as_object ( ) . get_bool ( " affects-layout " sv ) . value_or ( false ) ;
2022-03-16 17:46:24 +01:00
if ( affects_layout ) {
auto member_generator = generator . fork ( ) ;
member_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
member_generator . append ( R " ~~~(
case PropertyID : : @ name : titlecase @ :
) ~ ~ ~ " );
}
} ) ;
generator . append ( R " ~~~(
return true ;
default :
return false ;
}
}
2022-03-21 10:58:51 +01:00
bool property_affects_stacking_context ( PropertyID property_id )
{
switch ( property_id ) {
) ~ ~ ~ " );
properties . for_each_member ( [ & ] ( auto & name , auto & value ) {
VERIFY ( value . is_object ( ) ) ;
2022-03-25 00:59:42 +01:00
bool affects_stacking_context = false ;
2022-07-11 17:32:29 +00:00
if ( value . as_object ( ) . has ( " affects-stacking-context " sv ) )
2022-12-21 14:37:27 +00:00
affects_stacking_context = value . as_object ( ) . get_bool ( " affects-stacking-context " sv ) . value_or ( false ) ;
2022-03-21 10:58:51 +01:00
2022-03-25 00:59:42 +01:00
if ( affects_stacking_context ) {
2022-03-21 10:58:51 +01:00
auto member_generator = generator . fork ( ) ;
member_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
member_generator . append ( R " ~~~(
case PropertyID : : @ name : titlecase @ :
) ~ ~ ~ " );
}
} ) ;
generator . append ( R " ~~~(
return true ;
default :
return false ;
}
}
2023-05-02 15:09:46 +01:00
ErrorOr < NonnullRefPtr < StyleValue > > property_initial_value ( JS : : Realm & context_realm , PropertyID property_id )
2021-08-16 17:42:09 +01:00
{
2022-03-13 17:15:58 +01:00
static Array < RefPtr < StyleValue > , to_underlying ( last_property_id ) + 1 > initial_values ;
2023-04-02 22:46:22 +01:00
if ( auto initial_value = initial_values [ to_underlying ( property_id ) ] )
return initial_value . release_nonnull ( ) ;
// Lazily parse initial values as needed.
// This ensures the shorthands will always be able to get the initial values of their longhands.
// This also now allows a longhand have its own longhand (like background-position-x).
2021-08-16 17:42:09 +01:00
2023-04-02 22:46:22 +01:00
Parser : : ParsingContext parsing_context ( context_realm ) ;
switch ( property_id ) {
) ~ ~ ~ " );
LibWeb: Generate shorthand initial values after their longhands
When parsing shorthand values, we'd like to use
`property_initial_value()` to get their longhand property values,
instead of hard-coding them as we currently do. That involves
recursively calling that function while the `initial_values` map is
being initialized, which causes problems because the shorthands appear
alphabetically before their longhand components, so the longhands aren't
initialized yet!
The solution here is to perform 2 passes when generating the code,
outputting properties without "longhands" first, and the rest after.
This could potentially cause issues when shorthands have multiple
levels, in particular `border` -> `border-color` -> `border-left-color`.
But, we do not currently define a default value for `border`, and
`border-color` takes only a single value, so it's fine for now. :^)
2021-09-17 16:53:43 +01:00
auto output_initial_value_code = [ & ] ( auto & name , auto & object ) {
2022-07-11 17:32:29 +00:00
if ( ! object . has ( " initial " sv ) ) {
2021-11-10 13:48:41 +00:00
dbgln ( " No initial value specified for property '{}' " , name ) ;
VERIFY_NOT_REACHED ( ) ;
}
2022-12-21 14:37:27 +00:00
auto initial_value = object . get_deprecated_string ( " initial " sv ) ;
VERIFY ( initial_value . has_value ( ) ) ;
auto & initial_value_string = initial_value . value ( ) ;
2021-08-16 17:42:09 +01:00
2021-11-10 13:48:41 +00:00
auto member_generator = generator . fork ( ) ;
member_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
member_generator . set ( " initial_value_string " , initial_value_string ) ;
2023-04-02 22:46:22 +01:00
member_generator . append (
R " ~~~( case PropertyID::@name:titlecase@:
2021-11-10 13:48:41 +00:00
{
2023-05-02 15:09:46 +01:00
auto parsed_value = TRY ( parse_css_value ( parsing_context , " @initial_value_string@ " sv , PropertyID : : @ name : titlecase @ ) ) ;
2021-11-10 13:48:41 +00:00
VERIFY ( ! parsed_value . is_null ( ) ) ;
2023-04-02 22:46:22 +01:00
auto initial_value = parsed_value . release_nonnull ( ) ;
initial_values [ to_underlying ( PropertyID : : @ name : titlecase @ ) ] = initial_value ;
return initial_value ;
2021-08-16 17:42:09 +01:00
}
2021-11-10 13:48:41 +00:00
) ~ ~ ~ " );
LibWeb: Generate shorthand initial values after their longhands
When parsing shorthand values, we'd like to use
`property_initial_value()` to get their longhand property values,
instead of hard-coding them as we currently do. That involves
recursively calling that function while the `initial_values` map is
being initialized, which causes problems because the shorthands appear
alphabetically before their longhand components, so the longhands aren't
initialized yet!
The solution here is to perform 2 passes when generating the code,
outputting properties without "longhands" first, and the rest after.
This could potentially cause issues when shorthands have multiple
levels, in particular `border` -> `border-color` -> `border-left-color`.
But, we do not currently define a default value for `border`, and
`border-color` takes only a single value, so it's fine for now. :^)
2021-09-17 16:53:43 +01:00
} ;
properties . for_each_member ( [ & ] ( auto & name , auto & value ) {
VERIFY ( value . is_object ( ) ) ;
output_initial_value_code ( name , value . as_object ( ) ) ;
} ) ;
2023-04-02 22:46:22 +01:00
generator . append (
R " ~~~( default: VERIFY_NOT_REACHED();
2021-08-16 17:42:09 +01:00
}
2023-04-02 22:46:22 +01:00
VERIFY_NOT_REACHED ( ) ;
2021-08-16 17:42:09 +01:00
}
2021-09-11 17:26:38 +01:00
bool property_has_quirk ( PropertyID property_id , Quirk quirk )
{
switch ( property_id ) {
) ~ ~ ~ " );
properties . for_each_member ( [ & ] ( auto & name , auto & value ) {
VERIFY ( value . is_object ( ) ) ;
2022-07-11 17:32:29 +00:00
if ( value . as_object ( ) . has ( " quirks " sv ) ) {
2022-12-21 14:37:27 +00:00
auto quirks_value = value . as_object ( ) . get_array ( " quirks " sv ) ;
VERIFY ( quirks_value . has_value ( ) ) ;
auto & quirks = quirks_value . value ( ) ;
2021-09-11 17:26:38 +01:00
if ( ! quirks . is_empty ( ) ) {
auto property_generator = generator . fork ( ) ;
property_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
property_generator . append ( R " ~~~(
case PropertyID : : @ name : titlecase @ : {
switch ( quirk ) {
) ~ ~ ~ " );
for ( auto & quirk : quirks . values ( ) ) {
VERIFY ( quirk . is_string ( ) ) ;
auto quirk_generator = property_generator . fork ( ) ;
quirk_generator . set ( " quirk:titlecase " , title_casify ( quirk . as_string ( ) ) ) ;
quirk_generator . append ( R " ~~~(
case Quirk : : @ quirk : titlecase @ :
return true ;
) ~ ~ ~ " );
}
property_generator . append ( R " ~~~(
default :
return false ;
}
}
) ~ ~ ~ " );
}
}
} ) ;
generator . append ( R " ~~~(
default :
return false ;
}
}
2023-05-10 17:28:15 +01:00
bool property_accepts_type ( PropertyID property_id , ValueType value_type )
{
switch ( property_id ) {
) ~ ~ ~ " );
properties . for_each_member ( [ & ] ( auto & name , auto & value ) {
VERIFY ( value . is_object ( ) ) ;
auto & object = value . as_object ( ) ;
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 ) ) ;
property_generator . append ( R " ~~~(
case PropertyID : : @ name : titlecase @ : {
switch ( value_type ) {
) ~ ~ ~ " );
bool did_output_accepted_type = false ;
for ( auto & type : valid_types . values ( ) ) {
VERIFY ( type . is_string ( ) ) ;
auto type_name = type . as_string ( ) . split_view ( ' ' ) . first ( ) ;
if ( type_name_is_enum ( type_name ) )
continue ;
if ( type_name = = " angle " ) {
property_generator . appendln ( " case ValueType::Angle: " ) ;
} else if ( type_name = = " color " ) {
property_generator . appendln ( " case ValueType::Color: " ) ;
2023-05-25 12:43:52 +01:00
} else if ( type_name = = " custom-ident " ) {
property_generator . appendln ( " case ValueType::CustomIdent: " ) ;
2023-05-10 17:28:15 +01:00
} else if ( type_name = = " frequency " ) {
property_generator . appendln ( " case ValueType::Frequency: " ) ;
} else if ( type_name = = " image " ) {
property_generator . appendln ( " case ValueType::Image: " ) ;
} else if ( type_name = = " integer " ) {
property_generator . appendln ( " case ValueType::Integer: " ) ;
} else if ( type_name = = " length " ) {
property_generator . appendln ( " case ValueType::Length: " ) ;
} else if ( type_name = = " number " ) {
property_generator . appendln ( " case ValueType::Number: " ) ;
} else if ( type_name = = " percentage " ) {
property_generator . appendln ( " case ValueType::Percentage: " ) ;
} else if ( type_name = = " rect " ) {
property_generator . appendln ( " case ValueType::Rect: " ) ;
} else if ( type_name = = " resolution " ) {
property_generator . appendln ( " case ValueType::Resolution: " ) ;
} else if ( type_name = = " string " ) {
property_generator . appendln ( " case ValueType::String: " ) ;
} else if ( type_name = = " time " ) {
property_generator . appendln ( " case ValueType::Time: " ) ;
} else if ( type_name = = " url " ) {
property_generator . appendln ( " case ValueType::Url: " ) ;
} else {
VERIFY_NOT_REACHED ( ) ;
}
did_output_accepted_type = true ;
}
if ( did_output_accepted_type )
property_generator . appendln ( " return true; " ) ;
property_generator . append ( R " ~~~(
default :
return false ;
}
}
) ~ ~ ~ " );
}
} ) ;
generator . append ( R " ~~~(
default :
return false ;
}
}
bool property_accepts_identifier ( PropertyID property_id , ValueID identifier )
{
switch ( property_id ) {
) ~ ~ ~ " );
properties . for_each_member ( [ & ] ( auto & name , auto & value ) {
VERIFY ( value . is_object ( ) ) ;
auto & object = value . as_object ( ) ;
auto property_generator = generator . fork ( ) ;
property_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
property_generator . appendln ( " case PropertyID::@name:titlecase@: { " ) ;
if ( auto maybe_valid_identifiers = object . get_array ( " valid-identifiers " sv ) ; maybe_valid_identifiers . has_value ( ) & & ! maybe_valid_identifiers - > is_empty ( ) ) {
property_generator . appendln ( " switch (identifier) { " ) ;
auto & valid_identifiers = maybe_valid_identifiers . value ( ) ;
for ( auto & identifier : valid_identifiers . values ( ) ) {
auto identifier_generator = generator . fork ( ) ;
identifier_generator . set ( " identifier:titlecase " , title_casify ( identifier . as_string ( ) ) ) ;
identifier_generator . appendln ( " case ValueID::@identifier:titlecase@: " ) ;
}
property_generator . append ( R " ~~~(
return true ;
default :
break ;
}
) ~ ~ ~ " );
}
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 & valid_type : valid_types . values ( ) ) {
auto type_name = valid_type . as_string ( ) . split_view ( ' ' ) . first ( ) ;
if ( ! type_name_is_enum ( type_name ) )
continue ;
auto type_generator = generator . fork ( ) ;
type_generator . set ( " type_name:snakecase " , snake_casify ( type_name ) ) ;
type_generator . append ( R " ~~~(
if ( value_id_to_ @ type_name : snakecase @ ( identifier ) . has_value ( ) )
return true ;
) ~ ~ ~ " );
}
}
property_generator . append ( R " ~~~(
return false ;
}
) ~ ~ ~ " );
} ) ;
generator . append ( R " ~~~(
default :
return false ;
}
}
2021-09-22 12:24:33 +01:00
size_t property_maximum_value_count ( PropertyID property_id )
{
switch ( property_id ) {
) ~ ~ ~ " );
properties . for_each_member ( [ & ] ( auto & name , auto & value ) {
VERIFY ( value . is_object ( ) ) ;
2022-07-11 17:32:29 +00:00
if ( value . as_object ( ) . has ( " max-values " sv ) ) {
2022-12-21 14:37:27 +00:00
auto max_values = value . as_object ( ) . get ( " max-values " sv ) ;
VERIFY ( max_values . has_value ( ) & & max_values - > is_number ( ) & & ! max_values - > is_double ( ) ) ;
2021-09-22 12:24:33 +01:00
auto property_generator = generator . fork ( ) ;
property_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
2022-12-21 14:37:27 +00:00
property_generator . set ( " max_values " , max_values - > to_deprecated_string ( ) ) ;
2021-09-22 12:24:33 +01:00
property_generator . append ( R " ~~~(
case PropertyID : : @ name : titlecase @ :
return @ max_values @ ;
) ~ ~ ~ " );
}
} ) ;
generator . append ( R " ~~~(
default :
return 1 ;
}
}
2020-10-23 18:37:35 +02:00
} // namespace Web::CSS
2021-04-05 10:12:37 -04:00
2020-10-23 18:37:35 +02:00
) ~ ~ ~ " );
2023-03-01 16:28:32 +01:00
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
2022-04-01 17:41:43 +01:00
return { } ;
2019-11-18 11:12:58 +01:00
}