2022-04-13 16:48:03 +01:00
/*
2023-06-17 14:05:21 +01:00
* Copyright ( c ) 2022 - 2023 , Sam Atkins < atkinssj @ serenityos . org >
2022-04-13 16:48:03 +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>
2023-02-09 03:02:46 +01:00
ErrorOr < void > generate_header_file ( JsonObject & enums_data , Core : : File & file ) ;
ErrorOr < void > generate_implementation_file ( JsonObject & enums_data , Core : : File & file ) ;
2022-04-13 16:48:03 +01:00
2025-07-08 12:14:08 +02:00
ErrorOr < int > ladybird_main ( Main : : Arguments arguments )
2022-04-13 16:48:03 +01:00
{
StringView generated_header_path ;
StringView generated_implementation_path ;
2024-08-14 14:06:03 +01:00
StringView json_path ;
2022-04-13 16:48:03 +01:00
Core : : ArgsParser args_parser ;
args_parser . add_option ( generated_header_path , " Path to the Enums header file to generate " , " generated-header-path " , ' h ' , " generated-header-path " ) ;
args_parser . add_option ( generated_implementation_path , " Path to the Enums implementation file to generate " , " generated-implementation-path " , ' c ' , " generated-implementation-path " ) ;
2024-08-14 14:06:03 +01:00
args_parser . add_option ( json_path , " Path to the JSON file to read from " , " json-path " , ' j ' , " json-path " ) ;
2022-04-13 16:48:03 +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-13 16:48:03 +01:00
VERIFY ( json . is_object ( ) ) ;
auto enums_data = 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-13 16:48:03 +01:00
TRY ( generate_header_file ( enums_data , * generated_header_file ) ) ;
TRY ( generate_implementation_file ( enums_data , * generated_implementation_file ) ) ;
return 0 ;
}
2023-02-09 03:02:46 +01:00
ErrorOr < void > generate_header_file ( JsonObject & enums_data , Core : : File & file )
2022-04-13 16:48:03 +01:00
{
StringBuilder builder ;
SourceGenerator generator { builder } ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-13 16:48:03 +01:00
# pragma once
2022-04-13 17:46:47 +01:00
# include <AK/Optional.h>
2025-05-19 12:51:01 +01:00
# include <LibWeb/Forward.h>
2022-04-13 17:46:47 +01:00
2022-04-13 16:48:03 +01:00
namespace Web : : CSS {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-13 16:48:03 +01:00
2023-08-22 09:09:07 +02:00
enums_data . for_each_member ( [ & ] ( auto & name , auto & value ) {
2022-04-13 16:48:03 +01:00
VERIFY ( value . is_array ( ) ) ;
auto & members = value . as_array ( ) ;
2023-08-21 16:42:48 +02:00
auto enum_generator = generator . fork ( ) ;
2023-08-21 16:59:41 +02:00
enum_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
enum_generator . set ( " name:snakecase " , snake_casify ( name ) ) ;
2025-05-19 12:34:15 +01:00
enum_generator . set ( " enum_type " , underlying_type_for_enum ( members . size ( ) ) ) ;
2022-04-13 20:28:17 +01:00
2023-08-21 16:06:29 +02:00
enum_generator . appendln ( " enum class @name:titlecase@ : @enum_type@ { " ) ;
2022-04-13 16:48:03 +01:00
for ( auto & member : members . values ( ) ) {
2024-01-06 15:49:17 -05:00
auto member_name = member . as_string ( ) ;
2022-04-13 16:48:03 +01:00
// Don't include aliases in the enum.
if ( member_name . contains ( ' = ' ) )
continue ;
2023-08-21 16:42:48 +02:00
auto member_generator = enum_generator . fork ( ) ;
2023-08-21 16:59:41 +02:00
member_generator . set ( " member:titlecase " , title_casify ( member_name ) ) ;
2023-08-21 16:06:29 +02:00
member_generator . appendln ( " @member:titlecase@, " ) ;
2022-04-13 16:48:03 +01:00
}
2023-08-21 16:06:29 +02:00
enum_generator . appendln ( " }; " ) ;
2024-08-14 14:06:03 +01:00
enum_generator . appendln ( " Optional<@name:titlecase@> keyword_to_@name:snakecase@(Keyword); " ) ;
enum_generator . appendln ( " Keyword to_keyword(@name:titlecase@); " ) ;
2023-08-21 16:06:29 +02:00
enum_generator . appendln ( " StringView to_string(@name:titlecase@); " ) ;
2023-08-21 16:39:43 +02:00
enum_generator . append ( " \n " ) ;
2023-08-22 09:09:07 +02:00
} ) ;
2022-04-13 16:48:03 +01:00
2023-08-21 16:06:29 +02:00
generator . appendln ( " } " ) ;
2022-04-13 16:48:03 +01:00
2023-03-01 16:28:32 +01:00
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
2022-04-13 16:48:03 +01:00
return { } ;
}
2023-02-09 03:02:46 +01:00
ErrorOr < void > generate_implementation_file ( JsonObject & enums_data , Core : : File & file )
2022-04-13 16:48:03 +01:00
{
StringBuilder builder ;
SourceGenerator generator { builder } ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-13 16:48:03 +01:00
# include <LibWeb/CSS/Enums.h>
2024-08-14 14:06:03 +01:00
# include <LibWeb/CSS/Keyword.h>
2022-04-13 16:48:03 +01:00
namespace Web : : CSS {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-13 16:48:03 +01:00
2025-02-22 09:19:23 -06:00
enums_data . for_each_member ( [ & ] ( String const & name , JsonValue const & value ) {
2022-04-13 17:46:47 +01:00
VERIFY ( value . is_array ( ) ) ;
auto & members = value . as_array ( ) ;
2023-08-21 16:42:48 +02:00
auto enum_generator = generator . fork ( ) ;
2023-08-21 16:59:41 +02:00
enum_generator . set ( " name:titlecase " , title_casify ( name ) ) ;
enum_generator . set ( " name:snakecase " , snake_casify ( name ) ) ;
2022-04-13 17:46:47 +01:00
2023-08-21 16:39:43 +02:00
enum_generator . append ( R " ~~~(
2024-08-14 14:06:03 +01:00
Optional < @ name : titlecase @ > keyword_to_ @ name : snakecase @ ( Keyword keyword )
2022-04-13 17:46:47 +01:00
{
2024-08-14 14:06:03 +01:00
switch ( keyword ) { ) ~ ~ ~ " );
2022-04-13 17:46:47 +01:00
for ( auto & member : members . values ( ) ) {
2023-08-21 16:42:48 +02:00
auto member_generator = enum_generator . fork ( ) ;
2024-01-06 15:49:17 -05:00
auto member_name = member . as_string ( ) ;
2022-04-13 17:46:47 +01:00
if ( member_name . contains ( ' = ' ) ) {
2025-02-17 13:21:07 -05:00
auto parts = MUST ( member_name . split ( ' = ' ) ) ;
2023-08-21 16:59:41 +02:00
member_generator . set ( " valueid:titlecase " , title_casify ( parts [ 0 ] ) ) ;
member_generator . set ( " member:titlecase " , title_casify ( parts [ 1 ] ) ) ;
2022-04-13 17:46:47 +01:00
} else {
2023-08-21 16:59:41 +02:00
member_generator . set ( " valueid:titlecase " , title_casify ( member_name ) ) ;
member_generator . set ( " member:titlecase " , title_casify ( member_name ) ) ;
2022-04-13 17:46:47 +01:00
}
2023-08-21 16:39:43 +02:00
member_generator . append ( R " ~~~(
2024-08-14 14:06:03 +01:00
case Keyword : : @ valueid : titlecase @ :
2023-08-21 16:39:43 +02:00
return @ name : titlecase @ : : @ member : titlecase @ ; ) ~ ~ ~ " );
2022-04-13 17:46:47 +01:00
}
2023-08-21 16:39:43 +02:00
enum_generator . append ( R " ~~~(
2022-04-13 17:46:47 +01:00
default :
return { } ;
}
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-13 20:00:06 +01:00
2023-08-21 16:39:43 +02:00
enum_generator . append ( R " ~~~(
2024-08-14 14:06:03 +01:00
Keyword to_keyword ( @ name : titlecase @ @ name : snakecase @ _value )
2022-04-13 20:00:06 +01:00
{
2023-08-21 16:39:43 +02:00
switch ( @ name : snakecase @ _value ) { ) ~ ~ ~ " );
2022-04-13 20:00:06 +01:00
for ( auto & member : members . values ( ) ) {
2023-08-21 16:42:48 +02:00
auto member_generator = enum_generator . fork ( ) ;
2024-01-06 15:49:17 -05:00
auto member_name = member . as_string ( ) ;
2022-04-13 20:00:06 +01:00
if ( member_name . contains ( ' = ' ) )
continue ;
2023-08-21 16:59:41 +02:00
member_generator . set ( " member:titlecase " , title_casify ( member_name ) ) ;
2022-04-13 20:00:06 +01:00
2023-08-21 16:39:43 +02:00
member_generator . append ( R " ~~~(
2022-04-13 20:00:06 +01:00
case @ name : titlecase @ : : @ member : titlecase @ :
2024-08-14 14:06:03 +01:00
return Keyword : : @ member : titlecase @ ; ) ~ ~ ~ " );
2022-04-13 20:00:06 +01:00
}
2023-08-21 16:39:43 +02:00
enum_generator . append ( R " ~~~(
2022-04-13 20:00:06 +01:00
default :
VERIFY_NOT_REACHED ( ) ;
}
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-13 20:15:20 +01:00
2023-08-21 16:39:43 +02:00
enum_generator . append ( R " ~~~(
2022-04-13 20:15:20 +01:00
StringView to_string ( @ name : titlecase @ value )
{
2023-08-21 16:39:43 +02:00
switch ( value ) { ) ~ ~ ~ " );
2022-04-13 20:15:20 +01:00
for ( auto & member : members . values ( ) ) {
2023-08-21 16:42:48 +02:00
auto member_generator = enum_generator . fork ( ) ;
2024-01-06 15:49:17 -05:00
auto member_name = member . as_string ( ) ;
2022-04-13 20:15:20 +01:00
if ( member_name . contains ( ' = ' ) )
continue ;
2023-08-22 09:09:07 +02:00
member_generator . set ( " member:css " , member_name ) ;
2023-08-21 16:59:41 +02:00
member_generator . set ( " member:titlecase " , title_casify ( member_name ) ) ;
2022-04-13 20:15:20 +01:00
2023-08-21 16:39:43 +02:00
member_generator . append ( R " ~~~(
2022-04-13 20:15:20 +01:00
case @ name : titlecase @ : : @ member : titlecase @ :
2023-08-21 16:39:43 +02:00
return " @member:css@ " sv ; ) ~ ~ ~ " );
2022-04-13 20:15:20 +01:00
}
2023-08-21 16:39:43 +02:00
enum_generator . append ( R " ~~~(
2022-04-13 20:15:20 +01:00
default :
VERIFY_NOT_REACHED ( ) ;
}
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
} ) ;
2022-04-13 16:48:03 +01:00
2023-08-21 16:06:29 +02:00
generator . appendln ( " } " ) ;
2022-04-13 16:48:03 +01:00
2023-03-01 16:28:32 +01:00
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
2022-04-13 16:48:03 +01:00
return { } ;
}