2022-04-01 17:34:47 +01:00
/*
2024-10-04 13:19:50 +02:00
* Copyright ( c ) 2020 , Andreas Kling < andreas @ ladybird . org >
2024-08-14 14:06:03 +01:00
* Copyright ( c ) 2022 - 2024 , Sam Atkins < sam @ ladybird . org >
2022-04-01 17:34:47 +01:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "GeneratorUtil.h"
# include <AK/SourceGenerator.h>
# include <AK/StringBuilder.h>
# include <LibCore/ArgsParser.h>
# include <LibMain/Main.h>
2024-08-14 14:06:03 +01:00
ErrorOr < void > generate_header_file ( JsonArray & keyword_data , Core : : File & file ) ;
ErrorOr < void > generate_implementation_file ( JsonArray & keyword_data , Core : : File & file ) ;
2022-04-01 17:34:47 +01:00
2025-07-08 12:14:08 +02:00
ErrorOr < int > ladybird_main ( Main : : Arguments arguments )
2022-04-01 17:34:47 +01:00
{
StringView generated_header_path ;
StringView generated_implementation_path ;
2024-08-14 14:06:03 +01:00
StringView json_path ;
2022-04-01 17:34:47 +01:00
Core : : ArgsParser args_parser ;
2024-08-14 14:06:03 +01:00
args_parser . add_option ( generated_header_path , " Path to the Keyword header file to generate " , " generated-header-path " , ' h ' , " generated-header-path " ) ;
args_parser . add_option ( generated_implementation_path , " Path to the Keyword implementation file to generate " , " generated-implementation-path " , ' c ' , " generated-implementation-path " ) ;
args_parser . add_option ( json_path , " Path to the JSON file to read from " , " json-path " , ' j ' , " json-path " ) ;
2022-04-01 17:34:47 +01:00
args_parser . parse ( arguments ) ;
2024-08-14 14:06:03 +01:00
auto json = TRY ( read_entire_file_as_json ( json_path ) ) ;
2022-04-01 17:34:47 +01:00
VERIFY ( json . is_array ( ) ) ;
2024-08-14 14:06:03 +01:00
auto keyword_data = json . as_array ( ) ;
2022-04-01 17:34:47 +01:00
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:34:47 +01:00
2024-08-14 14:06:03 +01:00
TRY ( generate_header_file ( keyword_data , * generated_header_file ) ) ;
TRY ( generate_implementation_file ( keyword_data , * generated_implementation_file ) ) ;
2022-04-01 17:34:47 +01:00
return 0 ;
}
2025-02-25 16:37:10 +00:00
static String keyword_name ( String const & dashy_name )
{
if ( dashy_name = = " -infinity " sv )
return " NegativeInfinity " _string ;
return title_casify ( dashy_name ) ;
}
2024-08-14 14:06:03 +01:00
ErrorOr < void > generate_header_file ( JsonArray & keyword_data , Core : : File & file )
2022-04-01 17:34:47 +01:00
{
StringBuilder builder ;
SourceGenerator generator { builder } ;
2025-05-19 12:51:01 +01:00
generator . set ( " keyword_underlying_type " , underlying_type_for_enum ( keyword_data . size ( ) ) ) ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-01 17:34:47 +01:00
# pragma once
# include <AK/StringView.h>
# include <AK/Traits.h>
namespace Web : : CSS {
2025-05-19 12:51:01 +01:00
enum class Keyword : @ keyword_underlying_type @ {
2022-04-01 17:34:47 +01:00
Invalid ,
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-01 17:34:47 +01:00
2024-08-14 14:06:03 +01:00
keyword_data . for_each ( [ & ] ( auto & name ) {
2023-08-21 16:42:48 +02:00
auto member_generator = generator . fork ( ) ;
2025-02-25 16:37:10 +00:00
member_generator . set ( " name:titlecase " , keyword_name ( name . as_string ( ) ) ) ;
2022-04-01 17:34:47 +01:00
2023-08-21 16:39:43 +02:00
member_generator . append ( R " ~~~(
2022-04-01 17:34:47 +01:00
@ name : titlecase @ ,
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
} ) ;
2022-04-01 17:34:47 +01:00
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-01 17:34:47 +01:00
} ;
2024-08-14 14:06:03 +01:00
Optional < Keyword > keyword_from_string ( StringView ) ;
StringView string_from_keyword ( Keyword ) ;
2022-04-01 17:34:47 +01:00
2023-09-04 14:39:10 +01:00
// https://www.w3.org/TR/css-values-4/#common-keywords
2023-09-20 16:58:45 +01:00
// https://drafts.csswg.org/css-cascade-4/#valdef-all-revert
2023-09-04 14:39:10 +01:00
inline bool is_css_wide_keyword ( StringView name )
{
return name . equals_ignoring_ascii_case ( " inherit " sv )
| | name . equals_ignoring_ascii_case ( " initial " sv )
2023-09-20 16:58:45 +01:00
| | name . equals_ignoring_ascii_case ( " revert " sv )
2024-09-11 20:13:44 +08:00
| | name . equals_ignoring_ascii_case ( " revert-layer " sv )
2023-09-04 14:39:10 +01:00
| | name . equals_ignoring_ascii_case ( " unset " sv ) ;
}
2022-04-01 17:34:47 +01:00
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-01 17:34:47 +01:00
2023-03-01 16:28:32 +01:00
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
2022-04-01 17:34:47 +01:00
return { } ;
}
2024-08-14 14:06:03 +01:00
ErrorOr < void > generate_implementation_file ( JsonArray & keyword_data , Core : : File & file )
2022-04-01 17:34:47 +01:00
{
StringBuilder builder ;
SourceGenerator generator { builder } ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-01 17:34:47 +01:00
# include <AK/Assertions.h>
2023-01-09 19:08:37 +01:00
# include <AK/HashMap.h>
2024-08-14 14:06:03 +01:00
# include <LibWeb/CSS/Keyword.h>
2022-04-01 17:34:47 +01:00
namespace Web : : CSS {
2024-08-14 14:06:03 +01:00
HashMap < StringView , Keyword , AK : : CaseInsensitiveASCIIStringViewTraits > g_stringview_to_keyword_map {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-01 17:34:47 +01:00
2024-08-14 14:06:03 +01:00
keyword_data . for_each ( [ & ] ( auto & name ) {
2023-08-21 16:42:48 +02:00
auto member_generator = generator . fork ( ) ;
2024-01-06 15:49:17 -05:00
member_generator . set ( " name " , name . as_string ( ) ) ;
2025-02-25 16:37:10 +00:00
member_generator . set ( " name:titlecase " , keyword_name ( name . as_string ( ) ) ) ;
2023-08-21 16:39:43 +02:00
member_generator . append ( R " ~~~(
2024-08-14 14:06:03 +01:00
{ " @name@ " sv , Keyword : : @ name : titlecase @ } ,
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
} ) ;
2022-04-01 17:34:47 +01:00
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2023-01-09 19:08:37 +01:00
} ;
2024-08-14 14:06:03 +01:00
Optional < Keyword > keyword_from_string ( StringView string )
2023-01-09 19:08:37 +01:00
{
2024-08-14 14:06:03 +01:00
return g_stringview_to_keyword_map . get ( string ) ;
2022-04-01 17:34:47 +01:00
}
2024-08-14 14:06:03 +01:00
StringView string_from_keyword ( Keyword keyword ) {
switch ( keyword ) {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-01 17:34:47 +01:00
2024-08-14 14:06:03 +01:00
keyword_data . for_each ( [ & ] ( auto & name ) {
2023-08-21 16:42:48 +02:00
auto member_generator = generator . fork ( ) ;
2024-01-06 15:49:17 -05:00
member_generator . set ( " name " , name . as_string ( ) ) ;
2025-02-25 16:37:10 +00:00
member_generator . set ( " name:titlecase " , keyword_name ( name . as_string ( ) ) ) ;
2023-08-21 16:39:43 +02:00
member_generator . append ( R " ~~~(
2024-08-14 14:06:03 +01:00
case Keyword : : @ name : titlecase @ :
2023-01-06 19:02:26 +01:00
return " @name@ " sv ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
} ) ;
2022-04-01 17:34:47 +01:00
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-01 17:34:47 +01:00
default :
2024-08-14 14:06:03 +01:00
return " (invalid CSS::Keyword) " sv ;
2022-04-01 17:34:47 +01:00
}
}
} // namespace Web::CSS
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-01 17:34:47 +01:00
2023-03-01 16:28:32 +01:00
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
2022-04-01 17:34:47 +01:00
return { } ;
}