2022-04-17 15:33:50 +01:00
/*
2023-06-17 14:29:33 +01:00
* Copyright ( c ) 2022 - 2023 , Sam Atkins < atkinssj @ serenityos . org >
2022-04-17 15:33:50 +01:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "GeneratorUtil.h"
2022-04-17 16:56:52 +01:00
# include <AK/GenericLexer.h>
2022-04-17 15:33:50 +01:00
# 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 & transforms_data , Core : : File & file ) ;
ErrorOr < void > generate_implementation_file ( JsonObject & transforms_data , Core : : File & file ) ;
2022-04-17 15:33:50 +01:00
ErrorOr < int > serenity_main ( Main : : Arguments arguments )
{
StringView generated_header_path ;
StringView generated_implementation_path ;
StringView identifiers_json_path ;
Core : : ArgsParser args_parser ;
args_parser . add_option ( generated_header_path , " Path to the TransformFunctions header file to generate " , " generated-header-path " , ' h ' , " generated-header-path " ) ;
args_parser . add_option ( generated_implementation_path , " Path to the TransformFunctions implementation file to generate " , " generated-implementation-path " , ' c ' , " generated-implementation-path " ) ;
args_parser . add_option ( identifiers_json_path , " Path to the JSON file to read from " , " json-path " , ' j ' , " json-path " ) ;
args_parser . parse ( arguments ) ;
auto json = TRY ( read_entire_file_as_json ( identifiers_json_path ) ) ;
VERIFY ( json . is_object ( ) ) ;
auto transforms_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-17 15:33:50 +01:00
TRY ( generate_header_file ( transforms_data , * generated_header_file ) ) ;
TRY ( generate_implementation_file ( transforms_data , * generated_implementation_file ) ) ;
return 0 ;
}
2023-08-21 16:59:41 +02:00
static String title_casify_transform_function ( StringView input )
2022-04-17 15:33:50 +01:00
{
// Transform function names look like `fooBar`, so we just have to make the first character uppercase.
StringBuilder builder ;
2023-08-21 16:59:41 +02:00
builder . append ( toupper ( input [ 0 ] ) ) ;
builder . append ( input . substring_view ( 1 ) ) ;
return MUST ( builder . to_string ( ) ) ;
2022-04-17 15:33:50 +01:00
}
2023-02-09 03:02:46 +01:00
ErrorOr < void > generate_header_file ( JsonObject & transforms_data , Core : : File & file )
2022-04-17 15:33:50 +01:00
{
StringBuilder builder ;
SourceGenerator generator { builder } ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-17 15:48:49 +01:00
# pragma once
# include <AK/Optional.h>
# include <AK/StringView.h>
2022-10-26 16:09:20 +03:00
# include <AK/Vector.h>
2022-04-17 15:48:49 +01:00
2022-04-17 15:33:50 +01:00
namespace Web : : CSS {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-17 15:33:50 +01:00
2023-08-21 16:06:29 +02:00
generator . appendln ( " enum class TransformFunction { " ) ;
2023-08-22 09:09:07 +02:00
transforms_data . for_each_member ( [ & ] ( auto & name , auto & ) {
2023-08-21 16:42:48 +02:00
auto member_generator = generator . fork ( ) ;
2023-08-21 16:59:41 +02:00
member_generator . set ( " name:titlecase " , title_casify_transform_function ( name ) ) ;
2023-08-21 16:06:29 +02:00
member_generator . appendln ( " @name:titlecase@, " ) ;
2023-08-22 09:09:07 +02:00
} ) ;
2023-08-21 16:06:29 +02:00
generator . appendln ( " }; " ) ;
2022-04-17 15:33:50 +01:00
2023-08-21 16:06:29 +02:00
generator . appendln ( " Optional<TransformFunction> transform_function_from_string(StringView); " ) ;
generator . appendln ( " StringView to_string(TransformFunction); " ) ;
2022-04-17 15:48:49 +01:00
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-17 16:56:52 +01:00
enum class TransformFunctionParameterType {
Angle ,
2022-10-28 02:46:27 +03:00
Length ,
2022-04-17 16:56:52 +01:00
LengthPercentage ,
Number ,
} ;
2022-10-26 16:09:20 +03:00
struct TransformFunctionParameter {
TransformFunctionParameterType type ;
bool required ;
} ;
2022-04-17 16:56:52 +01:00
struct TransformFunctionMetadata {
2022-10-26 16:09:20 +03:00
Vector < TransformFunctionParameter > parameters ;
2022-04-17 16:56:52 +01:00
} ;
TransformFunctionMetadata transform_function_metadata ( TransformFunction ) ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-17 16:56:52 +01:00
2023-08-21 16:06:29 +02:00
generator . appendln ( " \n } " ) ;
2022-04-17 15:33:50 +01:00
2023-03-01 16:28:32 +01:00
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
2022-04-17 15:33:50 +01:00
return { } ;
}
2023-02-09 03:02:46 +01:00
ErrorOr < void > generate_implementation_file ( JsonObject & transforms_data , Core : : File & file )
2022-04-17 15:33:50 +01:00
{
StringBuilder builder ;
SourceGenerator generator { builder } ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-17 15:48:49 +01:00
# include <LibWeb/CSS/TransformFunctions.h>
# include <AK/Assertions.h>
2022-04-17 15:33:50 +01:00
namespace Web : : CSS {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-17 15:33:50 +01:00
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-17 15:48:49 +01:00
Optional < TransformFunction > transform_function_from_string ( StringView name )
{
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
transforms_data . for_each_member ( [ & ] ( auto & name , auto & ) {
2023-08-21 16:42:48 +02:00
auto member_generator = generator . fork ( ) ;
2023-08-22 09:09:07 +02:00
member_generator . set ( " name " , name ) ;
2023-08-21 16:59:41 +02:00
member_generator . set ( " name:titlecase " , title_casify_transform_function ( name ) ) ;
2023-08-21 16:39:43 +02:00
member_generator . append ( R " ~~~(
2023-03-10 08:48:54 +01:00
if ( name . equals_ignoring_ascii_case ( " @name@ " sv ) )
2022-04-17 15:48:49 +01:00
return TransformFunction : : @ name : titlecase @ ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
} ) ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-17 15:48:49 +01:00
return { } ;
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-17 15:48:49 +01:00
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-17 15:48:49 +01:00
StringView to_string ( TransformFunction transform_function )
{
switch ( transform_function ) {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
transforms_data . for_each_member ( [ & ] ( auto & name , auto & ) {
2023-08-21 16:42:48 +02:00
auto member_generator = generator . fork ( ) ;
2023-08-22 09:09:07 +02:00
member_generator . set ( " name " , name ) ;
2023-08-21 16:59:41 +02:00
member_generator . set ( " name:titlecase " , title_casify_transform_function ( name ) ) ;
2023-08-21 16:39:43 +02:00
member_generator . append ( R " ~~~(
2022-04-17 15:48:49 +01:00
case TransformFunction : : @ name : titlecase @ :
return " @name@ " sv ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
} ) ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-17 15:48:49 +01:00
default :
VERIFY_NOT_REACHED ( ) ;
}
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-17 16:56:52 +01:00
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-17 16:56:52 +01:00
TransformFunctionMetadata transform_function_metadata ( TransformFunction transform_function )
{
switch ( transform_function ) {
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
transforms_data . for_each_member ( [ & ] ( auto & name , auto & value ) {
2022-04-17 16:56:52 +01:00
VERIFY ( value . is_object ( ) ) ;
2023-08-21 16:42:48 +02:00
auto member_generator = generator . fork ( ) ;
2023-08-21 16:59:41 +02:00
member_generator . set ( " name:titlecase " , title_casify_transform_function ( name ) ) ;
2023-08-21 16:39:43 +02:00
member_generator . append ( R " ~~~(
2022-04-17 16:56:52 +01:00
case TransformFunction : : @ name : titlecase @ :
return TransformFunctionMetadata {
2023-08-21 16:39:43 +02:00
. parameters = { ) ~ ~ ~ " );
2022-10-26 16:09:20 +03:00
2022-12-21 14:37:27 +00:00
JsonArray const & parameters = value . as_object ( ) . get_array ( " parameters " sv ) . value ( ) ;
2022-10-26 16:09:20 +03:00
bool first = true ;
2023-08-22 09:09:07 +02:00
parameters . for_each ( [ & ] ( JsonValue const & value ) {
2022-12-21 14:37:27 +00:00
GenericLexer lexer { value . as_object ( ) . get_deprecated_string ( " type " sv ) . value ( ) } ;
2022-10-26 16:09:20 +03:00
VERIFY ( lexer . consume_specific ( ' < ' ) ) ;
auto parameter_type_name = lexer . consume_until ( ' > ' ) ;
VERIFY ( lexer . consume_specific ( ' > ' ) ) ;
StringView parameter_type = " " sv ;
if ( parameter_type_name = = " angle " sv )
parameter_type = " Angle " sv ;
2022-10-28 02:46:27 +03:00
else if ( parameter_type_name = = " length " sv )
parameter_type = " Length " sv ;
2022-10-26 16:09:20 +03:00
else if ( parameter_type_name = = " length-percentage " sv )
parameter_type = " LengthPercentage " sv ;
else if ( parameter_type_name = = " number " sv )
parameter_type = " Number " sv ;
else
VERIFY_NOT_REACHED ( ) ;
2023-08-21 16:39:43 +02:00
member_generator . append ( first ? " " sv : " , " sv ) ;
2022-10-26 16:09:20 +03:00
first = false ;
2023-08-22 09:09:07 +02:00
member_generator . append ( MUST ( String : : formatted ( " {{ TransformFunctionParameterType::{}, {}}} " , parameter_type , value . as_object ( ) . get ( " required " sv ) - > to_deprecated_string ( ) ) ) ) ;
} ) ;
2022-10-26 16:09:20 +03:00
2023-08-21 16:39:43 +02:00
member_generator . append ( R " ~~~( }
2022-10-26 16:09:20 +03:00
} ;
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2023-08-22 09:09:07 +02:00
} ) ;
2023-08-21 16:39:43 +02:00
generator . append ( R " ~~~(
2022-04-17 16:56:52 +01:00
default :
VERIFY_NOT_REACHED ( ) ;
}
}
2023-08-21 16:39:43 +02:00
) ~ ~ ~ " );
2022-04-17 15:33:50 +01:00
2023-08-21 16:06:29 +02:00
generator . appendln ( " \n } " ) ;
2022-04-17 15:33:50 +01:00
2023-03-01 16:28:32 +01:00
TRY ( file . write_until_depleted ( generator . as_string_view ( ) . bytes ( ) ) ) ;
2022-04-17 15:33:50 +01:00
return { } ;
}