Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Support for Patterns in JSON Schema #312

Merged
merged 7 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion src/zcl_aff_abap_doc_parser.clas.abap
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ CLASS zcl_aff_abap_doc_parser DEFINITION
content_media_type TYPE string VALUE `$contentMediaType`,
content_encoding TYPE string VALUE `$contentEncoding`,
enum_value TYPE string VALUE `$enumValue`,
pattern TYPE string VALUE `$pattern`,
END OF abap_doc_annotation.

TYPES:
Expand All @@ -41,6 +42,7 @@ CLASS zcl_aff_abap_doc_parser DEFINITION
content_media_type TYPE string,
content_encoding TYPE string,
enum_value TYPE string,
pattern TYPE string,
END OF abap_doc.

METHODS: parse
Expand Down Expand Up @@ -99,6 +101,7 @@ CLASS zcl_aff_abap_doc_parser DEFINITION
annotation_name TYPE string
RETURNING
VALUE(number) TYPE string,
parse_pattern,
check_next_word
IMPORTING
offset TYPE i
Expand Down Expand Up @@ -164,7 +167,7 @@ CLASS zcl_aff_abap_doc_parser IMPLEMENTATION.
ENDMETHOD.

METHOD parse_description.
FIND FIRST OCCURRENCE OF PCRE `(\$callbackClass|\$default|\$values|\$required|\$showAlways|\$minimum|\$maximum|\$exclusiveMinimum|\$exclusiveMaximum|\$multipleOf|\$maxLength|\$minLength|\$enumValue|\$contentMediaType|\$contentEncoding)`
FIND FIRST OCCURRENCE OF PCRE `(\$callbackClass|\$default|\$values|\$required|\$showAlways|\$minimum|\$maximum|\$exclusiveMinimum|\$exclusiveMaximum|\$multipleOf|\$maxLength|\$minLength|\$enumValue|\$contentMediaType|\$contentEncoding|\$pattern)`
IN abap_doc_string MATCH OFFSET DATA(offset).
IF sy-subrc = 0.
DATA(description) = abap_doc_string+0(offset).
Expand Down Expand Up @@ -195,6 +198,8 @@ CLASS zcl_aff_abap_doc_parser IMPLEMENTATION.
parse_required( ).
WHEN abap_doc_annotation-show_always.
parse_show_always( ).
WHEN abap_doc_annotation-pattern.
parse_pattern( ).
WHEN abap_doc_annotation-minimum OR abap_doc_annotation-maximum OR abap_doc_annotation-exclusive_minimum OR abap_doc_annotation-exclusive_maximum
OR abap_doc_annotation-max_length OR abap_doc_annotation-multiple_of OR abap_doc_annotation-min_length.
parse_number_annotations( key_word = key_word ).
Expand Down Expand Up @@ -543,4 +548,35 @@ CLASS zcl_aff_abap_doc_parser IMPLEMENTATION.
ENDIF.
ENDMETHOD.

METHOD parse_pattern.
IF decoded_abap_doc-pattern IS NOT INITIAL.
RETURN.
ENDIF.

DATA(string_to_parse) = abap_doc_string.

FIND ALL OCCURRENCES OF PCRE `\$pattern[\s]*(:[\s]*)?'([^']*)'` IN string_to_parse RESULTS DATA(result_table).

IF lines( result_table ) = 0.
DATA(msg) = parser_log->get_message_text( msgno = 109 msgv1 = CONV #( abap_doc_annotation-pattern ) ).
parser_log->add_warning( message_text = msg component_name = component_name ).
RETURN.
ENDIF.
write_log_for_multiple_entries( result_table = result_table annotaion = abap_doc_annotation-pattern ).

LOOP AT result_table ASSIGNING FIELD-SYMBOL(<entry>).
IF lines( <entry>-submatches ) = 2 AND decoded_abap_doc-pattern IS INITIAL.
DATA(submatch) = <entry>-submatches[ 2 ].
IF submatch-length = 0.
msg = parser_log->get_message_text( msgno = 109 msgv1 = CONV #( abap_doc_annotation-pattern ) ).
parser_log->add_warning( message_text = msg component_name = component_name ).
ENDIF.

decoded_abap_doc-pattern = substring( val = string_to_parse off = submatch-offset len = submatch-length ).
ENDIF.
ENDLOOP.

ENDMETHOD.

ENDCLASS.

81 changes: 80 additions & 1 deletion src/zcl_aff_abap_doc_parser.clas.testclasses.abap
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ CLASS ltcl_aff_abap_doc_parser DEFINITION FINAL FOR TESTING
METHODS content_media_multiple_entries FOR TESTING RAISING cx_static_check.
METHODS content_media_type_used_wrong FOR TESTING RAISING cx_static_check.
METHODS content_encoding_used_wrong FOR TESTING RAISING cx_static_check.

METHODS too_many_patterns FOR TESTING RAISING cx_static_check.
METHODS pattern_with_colon FOR TESTING RAISING cx_static_check.
METHODS pattern_no_single_quotes FOR TESTING RAISING cx_static_check.
METHODS pattern_no_value FOR TESTING RAISING cx_static_check.
METHODS pattern FOR TESTING RAISING cx_static_check.

ENDCLASS.

Expand Down Expand Up @@ -582,4 +586,79 @@ CLASS ltcl_aff_abap_doc_parser IMPLEMENTATION.
exp_component_name = `Component Name` ).
ENDMETHOD.

METHOD pattern.
DATA(abap_doc_to_parse) = `<p class="shorttext">Title</p> This is the description. $pattern '[a-z]*'`.
DATA(act_abap_doc) = parser->parse(
EXPORTING
component_name = `Component Name`
to_parse = abap_doc_to_parse
CHANGING
log = log ).
exp_abap_doc = VALUE #( title = `Title` description = `This is the description.` pattern = `[a-z]*` ).
cl_abap_unit_assert=>assert_equals( exp = exp_abap_doc act = act_abap_doc ).
zcl_aff_tools_unit_test_helper=>assert_log_has_no_message( log = log message_severity_threshold = zif_aff_log=>c_message_type-info ).
ENDMETHOD.

METHOD pattern_with_colon.
DATA(abap_doc_to_parse) = `<p class="shorttext">Title</p> This is the description. $pattern : '[a-z]*'`.
DATA(act_abap_doc) = parser->parse(
EXPORTING
component_name = `Component Name`
to_parse = abap_doc_to_parse
CHANGING
log = log ).
exp_abap_doc = VALUE #( title = `Title` description = `This is the description.` pattern = `[a-z]*` ).
cl_abap_unit_assert=>assert_equals( exp = exp_abap_doc act = act_abap_doc ).
zcl_aff_tools_unit_test_helper=>assert_log_has_no_message( log = log message_severity_threshold = zif_aff_log=>c_message_type-info ).
ENDMETHOD.

METHOD pattern_no_single_quotes.
DATA(abap_doc_to_parse) = `<p class="shorttext">Title</p> This is the description. $pattern [a-z]*`.
DATA(act_abap_doc) = parser->parse(
EXPORTING
component_name = `Component Name`
to_parse = abap_doc_to_parse
CHANGING
log = log ).
exp_abap_doc = VALUE #( title = `Title` description = `This is the description.` ).
cl_abap_unit_assert=>assert_equals( exp = exp_abap_doc act = act_abap_doc ).
zcl_aff_tools_unit_test_helper=>assert_log_contains_text( log = log
exp_text = `Annotation $pattern was used incorrectly`
exp_type = zif_aff_log=>c_message_type-warning
exp_component_name = `Component Name` ).
ENDMETHOD.

METHOD pattern_no_value.
DATA(abap_doc_to_parse) = `<p class="shorttext">Title</p> This is the description. $pattern ''`.
DATA(act_abap_doc) = parser->parse(
EXPORTING
component_name = `Component Name`
to_parse = abap_doc_to_parse
CHANGING
log = log ).
exp_abap_doc = VALUE #( title = `Title` description = `This is the description.` ).
cl_abap_unit_assert=>assert_equals( exp = exp_abap_doc act = act_abap_doc ).
zcl_aff_tools_unit_test_helper=>assert_log_contains_text( log = log
exp_text = `Annotation $pattern was used incorrectly`
exp_type = zif_aff_log=>c_message_type-warning
exp_component_name = `Component Name` ).
ENDMETHOD.

METHOD too_many_patterns.
DATA(abap_doc_to_parse) = `<p class="shorttext">Title</p> This is the description. $pattern '[a-z]*' $pattern '[A-Z]*'`.
DATA(act_abap_doc) = parser->parse(
EXPORTING
component_name = `Component Name`
to_parse = abap_doc_to_parse
CHANGING
log = log ).
exp_abap_doc = VALUE #( title = `Title` description = `This is the description.` pattern = `[a-z]*` ).
cl_abap_unit_assert=>assert_equals( exp = exp_abap_doc act = act_abap_doc ).
zcl_aff_tools_unit_test_helper=>assert_log_contains_text( log = log
exp_text = |There are several occurrences of annotation { zcl_aff_abap_doc_parser=>abap_doc_annotation-pattern } . First valid is used|
exp_type = zif_aff_log=>c_message_type-info
exp_component_name = `Component Name` ).

ENDMETHOD.

ENDCLASS.
22 changes: 22 additions & 0 deletions src/zcl_aff_test_types.clas.abap
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,28 @@ CLASS zcl_aff_test_types DEFINITION
default_link TYPE default_link,
END OF struc_link_wrong_type.

TYPES:
"! $pattern '[a-Z]*'
ty_string TYPE string.

TYPES:
"! <p class="shorttext">Structure With Pattern Annotation</p>
"! Structure with pattern annotation
BEGIN OF string_pattern_complex,
"! <p class="shorttext">String with pattern</p>
"! description
string_pattern TYPE ty_string,
END OF string_pattern_complex.

TYPES:
"! <p class="shorttext">Structure With Pattern Annotation</p>
"! Structure with pattern annotation
BEGIN OF string_pattern_simple,
"! <p class="shorttext">String with pattern</p>
"! description
"! $pattern '[a-Z]*'
string_pattern TYPE string,
END OF string_pattern_simple.

TYPES:
"! in ST val(I()) only allow integers
Expand Down
3 changes: 3 additions & 0 deletions src/zcl_aff_writer.clas.abap
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,9 @@ CLASS zcl_aff_writer IMPLEMENTATION.
IF abap_doc_base-content_media_type IS INITIAL.
abap_doc_base-content_media_type = abap_doc_additional-content_media_type.
ENDIF.
IF abap_doc_base-pattern IS INITIAL.
abap_doc_base-pattern = abap_doc_additional-pattern.
ENDIF.
ENDMETHOD.


Expand Down
3 changes: 3 additions & 0 deletions src/zcl_aff_writer_json_schema.clas.abap
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,9 @@ CLASS zcl_aff_writer_json_schema IMPLEMENTATION.
write_tag( `"pattern": "^[0-9]+$",` ).
ENDIF.
ENDIF.
IF abap_doc-pattern IS NOT INITIAL.
write_tag( |"pattern": "{ abap_doc-pattern }",| ).
ENDIF.
ENDMETHOD.


Expand Down
57 changes: 56 additions & 1 deletion src/zcl_aff_writer_json_schema.clas.testclasses.abap
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,9 @@ CLASS ltcl_json_writer_abap_doc DEFINITION FINAL FOR TESTING
content_encoding FOR TESTING RAISING cx_static_check,
content_media_type_integer FOR TESTING RAISING cx_static_check,
content_media_type_string FOR TESTING RAISING cx_static_check,
encoding_type_next_level FOR TESTING RAISING cx_static_check.
encoding_type_next_level FOR TESTING RAISING cx_static_check,
pattern_simple FOR TESTING RAISING cx_static_check,
pattern_complex FOR TESTING RAISING cx_static_check.

ENDCLASS.

Expand Down Expand Up @@ -2788,4 +2790,57 @@ CLASS ltcl_json_writer_abap_doc IMPLEMENTATION.
zcl_aff_tools_unit_test_helper=>assert_log_has_no_message( log = log message_severity_threshold = zif_aff_log=>c_message_type-info ).
ENDMETHOD.


METHOD pattern_simple.
DATA(act_schema) = test_generator->generate_type( VALUE zcl_aff_test_types=>string_pattern_simple( ) ).
DATA(exp_schema) = VALUE string_table(
( ` { ` )
( | "$comment": "This file is autogenerated, do not edit manually, see { zcl_aff_writer_json_schema=>c_link_to_repository } for more information.", | )
( | "$schema": "{ zcl_aff_writer_json_schema=>c_schema_specification }",| )
( | "$id": "{ schema_id }",| )
( ` "title": "Structure With Pattern Annotation", ` )
( ` "description": "Structure with pattern annotation", ` )
( ` "type": "object", ` )
( ` "properties": { ` )
( ` "stringPattern": { ` )
( ` "title": "String with pattern",` )
( ` "description": "description",` )
( ` "type": "string", ` )
( ` "pattern": "[a-Z]*" ` )
( ` } ` )
( ` }, ` )
( ` "additionalProperties": false ` )
( ` } ` )
( ) ).
zcl_aff_tools_unit_test_helper=>assert_equals_ignore_spaces( act_data = act_schema exp_data = exp_schema ).
log = cut->zif_aff_writer~get_log( ).
zcl_aff_tools_unit_test_helper=>assert_log_has_no_message( log = log message_severity_threshold = zif_aff_log=>c_message_type-info ).
ENDMETHOD.

METHOD pattern_complex.
DATA(act_schema) = test_generator->generate_type( VALUE zcl_aff_test_types=>string_pattern_complex( ) ).
DATA(exp_schema) = VALUE string_table(
( ` { ` )
( | "$comment": "This file is autogenerated, do not edit manually, see { zcl_aff_writer_json_schema=>c_link_to_repository } for more information.", | )
( | "$schema": "{ zcl_aff_writer_json_schema=>c_schema_specification }",| )
( | "$id": "{ schema_id }",| )
( ` "title": "Structure With Pattern Annotation", ` )
( ` "description": "Structure with pattern annotation", ` )
( ` "type": "object", ` )
( ` "properties": { ` )
( ` "stringPattern": { ` )
( ` "title": "String with pattern",` )
( ` "description": "description",` )
( ` "type": "string", ` )
( ` "pattern": "[a-Z]*" ` )
( ` } ` )
( ` }, ` )
( ` "additionalProperties": false ` )
( ` } ` )
( ) ).
zcl_aff_tools_unit_test_helper=>assert_equals_ignore_spaces( act_data = act_schema exp_data = exp_schema ).
log = cut->zif_aff_writer~get_log( ).
zcl_aff_tools_unit_test_helper=>assert_log_has_no_message( log = log message_severity_threshold = zif_aff_log=>c_message_type-info ).
ENDMETHOD.

ENDCLASS.
Loading