From 27eca9b766280614a1e5f8b80a18dc5d0d4610a8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 20 Oct 2021 17:50:51 +0200 Subject: [PATCH] ajson, Automatic Update (#5036) * [create-pull-request] automated change * upd * fix Co-authored-by: larshp Co-authored-by: Marc Bernard <59966492+mbtools@users.noreply.github.com> Co-authored-by: Lars Hvam --- package.json | 6 +- src/json/zcl_abapgit_ajson.clas.abap | 51 ++- .../zcl_abapgit_ajson.clas.locals_imp.abap | 311 ++++++++++++------ .../zcl_abapgit_ajson.clas.testclasses.abap | 189 ++++++++++- .../zcl_abapgit_ajson_filter_lib.clas.abap | 56 ++++ ...pgit_ajson_filter_lib.clas.locals_imp.abap | 129 ++++++++ ...git_ajson_filter_lib.clas.testclasses.abap | 168 ++++++++++ .../zcl_abapgit_ajson_filter_lib.clas.xml | 17 + src/json/zif_abapgit_ajson.intf.abap | 2 +- src/json/zif_abapgit_ajson_filter.intf.abap | 23 ++ src/json/zif_abapgit_ajson_filter.intf.xml | 15 + test/abap_transpile.json | 25 ++ 12 files changed, 880 insertions(+), 112 deletions(-) create mode 100644 src/json/zcl_abapgit_ajson_filter_lib.clas.abap create mode 100644 src/json/zcl_abapgit_ajson_filter_lib.clas.locals_imp.abap create mode 100644 src/json/zcl_abapgit_ajson_filter_lib.clas.testclasses.abap create mode 100644 src/json/zcl_abapgit_ajson_filter_lib.clas.xml create mode 100644 src/json/zif_abapgit_ajson_filter.intf.abap create mode 100644 src/json/zif_abapgit_ajson_filter.intf.xml diff --git a/package.json b/package.json index d189303fd..e59435fde 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,9 @@ "url": "git+https://github.com/abapGit/abapGit.git" }, "devDependencies": { - "@abaplint/cli": "^2.79.30", - "@abaplint/transpiler-cli": "^1.6.50", - "@abaplint/runtime": "^1.6.50", + "@abaplint/cli": "^2.79.32", + "@abaplint/transpiler-cli": "^1.6.53", + "@abaplint/runtime": "^1.6.53", "abapmerge": "^0.14.3", "eslint": "^8.0.1" } diff --git a/src/json/zcl_abapgit_ajson.clas.abap b/src/json/zcl_abapgit_ajson.clas.abap index b46cc5260..4b6c5c490 100644 --- a/src/json/zcl_abapgit_ajson.clas.abap +++ b/src/json/zcl_abapgit_ajson.clas.abap @@ -55,6 +55,16 @@ CLASS zcl_abapgit_ajson DEFINITION RETURNING VALUE(ro_instance) TYPE REF TO zcl_abapgit_ajson. + " Experimental ! May change + CLASS-METHODS create_from + IMPORTING + !ii_source_json TYPE REF TO zif_abapgit_ajson + !ii_filter TYPE REF TO zif_abapgit_ajson_filter OPTIONAL + RETURNING + VALUE(ro_instance) TYPE REF TO zcl_abapgit_ajson + RAISING + zcx_abapgit_ajson_error . + PROTECTED SECTION. PRIVATE SECTION. @@ -84,7 +94,6 @@ CLASS zcl_abapgit_ajson DEFINITION iv_name TYPE string RETURNING VALUE(rv_deleted) TYPE abap_bool. - ENDCLASS. @@ -98,6 +107,32 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION. ENDMETHOD. + METHOD create_from. + + DATA lo_filter_runner TYPE REF TO lcl_filter_runner. + + IF ii_source_json IS NOT BOUND. + zcx_abapgit_ajson_error=>raise( 'Source not bound' ). + ENDIF. + + CREATE OBJECT ro_instance. + + IF ii_filter IS BOUND. + CREATE OBJECT lo_filter_runner. + lo_filter_runner->run( + EXPORTING + ii_filter = ii_filter + it_source_tree = ii_source_json->mt_json_tree + CHANGING + ct_dest_tree = ro_instance->mt_json_tree ). + ELSE. + ro_instance->mt_json_tree = ii_source_json->mt_json_tree. + " Copy keep order and custom mapping ??? + ENDIF. + + ENDMETHOD. + + METHOD delete_subtree. DATA lv_parent_path TYPE string. @@ -453,9 +488,11 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION. DATA lt_new_nodes TYPE zif_abapgit_ajson=>ty_nodes_tt. DATA ls_new_path TYPE zif_abapgit_ajson=>ty_path_name. + DATA lv_new_index TYPE i. + lv_new_index = lr_parent->children + 1. ls_new_path-path = lcl_utils=>normalize_path( iv_path ). - ls_new_path-name = |{ lr_parent->children + 1 }|. + ls_new_path-name = |{ lv_new_index }|. lt_new_nodes = lcl_abap_to_json=>convert( iv_keep_item_order = mv_keep_item_order @@ -463,10 +500,10 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION. is_prefix = ls_new_path ). READ TABLE lt_new_nodes INDEX 1 REFERENCE INTO lr_new_node. " assume first record is the array item - not ideal ! ASSERT sy-subrc = 0. - lr_new_node->index = lr_parent->children + 1. + lr_new_node->index = lv_new_index. " update data - lr_parent->children = lr_parent->children + 1. + lr_parent->children = lv_new_index. INSERT LINES OF lt_new_nodes INTO TABLE mt_json_tree. ri_json = me. @@ -553,8 +590,10 @@ CLASS zcl_abapgit_ajson IMPLEMENTATION. ENDIF. " update data - lr_parent->children = lr_parent->children + 1. - INSERT LINES OF lt_new_nodes INTO TABLE mt_json_tree. + IF lines( lt_new_nodes ) > 0. + lr_parent->children = lr_parent->children + 1. + INSERT LINES OF lt_new_nodes INTO TABLE mt_json_tree. + ENDIF. ENDMETHOD. diff --git a/src/json/zcl_abapgit_ajson.clas.locals_imp.abap b/src/json/zcl_abapgit_ajson.clas.locals_imp.abap index 1845ca4ae..18f7e4db7 100644 --- a/src/json/zcl_abapgit_ajson.clas.locals_imp.abap +++ b/src/json/zcl_abapgit_ajson.clas.locals_imp.abap @@ -776,7 +776,7 @@ CLASS lcl_json_to_abap IMPLEMENTATION. DATA lv_date TYPE d. DATA lv_time TYPE t. DATA lv_seconds_conv TYPE i. - DATA lv_timestamp TYPE timestamp. + DATA lv_timestamp TYPE timestampl. FIND FIRST OCCURRENCE OF REGEX lc_regex_ts_with_hour IN is_path-value SUBMATCHES ls_timestamp-year ls_timestamp-month ls_timestamp-day ls_timestamp-t @@ -823,7 +823,8 @@ CLASS lcl_json_to_abap IMPLEMENTATION. iv_location = is_path-path && is_path-name ). ENDTRY. - rv_result = lv_timestamp. + cl_abap_tstmp=>move( EXPORTING tstmp_src = lv_timestamp + IMPORTING tstmp_tgt = rv_result ). ENDMETHOD. @@ -887,7 +888,9 @@ CLASS lcl_abap_to_json DEFINITION FINAL. is_prefix TYPE zif_abapgit_ajson=>ty_path_name iv_index TYPE i DEFAULT 0 CHANGING - ct_nodes TYPE zif_abapgit_ajson=>ty_nodes_tt. + ct_nodes TYPE zif_abapgit_ajson=>ty_nodes_tt + RAISING + zcx_abapgit_ajson_error. METHODS convert_value IMPORTING @@ -971,7 +974,7 @@ CLASS lcl_abap_to_json IMPLEMENTATION. lo_type = cl_abap_typedescr=>describe_by_data( iv_data ). CREATE OBJECT lo_converter. - lo_converter->mi_custom_mapping = ii_custom_mapping. + lo_converter->mi_custom_mapping = ii_custom_mapping. lo_converter->mv_keep_item_order = iv_keep_item_order. lo_converter->convert_any( @@ -1053,17 +1056,22 @@ CLASS lcl_abap_to_json IMPLEMENTATION. METHOD convert_ajson. - FIELD-SYMBOLS LIKE LINE OF ct_nodes. + FIELD-SYMBOLS LIKE LINE OF ct_nodes. + FIELD-SYMBOLS LIKE LINE OF ct_nodes. - ct_nodes = io_json->mt_json_tree. + IF io_json IS NOT BOUND. + RETURN. + ENDIF. - LOOP AT ct_nodes ASSIGNING . - IF -path IS INITIAL AND -name IS INITIAL. " root node - -path = is_prefix-path. - -name = is_prefix-name. - -index = iv_index. + LOOP AT io_json->mt_json_tree ASSIGNING . + APPEND TO ct_nodes ASSIGNING . + + IF -path IS INITIAL AND -name IS INITIAL. " root node + -path = is_prefix-path. + -name = is_prefix-name. + -index = iv_index. ELSE. - -path = is_prefix-path && is_prefix-name && -path. + -path = is_prefix-path && is_prefix-name && -path. ENDIF. ENDLOOP. @@ -1071,22 +1079,21 @@ CLASS lcl_abap_to_json IMPLEMENTATION. METHOD convert_value. - FIELD-SYMBOLS LIKE LINE OF ct_nodes. + DATA ls_node LIKE LINE OF ct_nodes. - APPEND INITIAL LINE TO ct_nodes ASSIGNING . - - -path = is_prefix-path. - -name = is_prefix-name. - -index = iv_index. - -order = iv_item_order. + ls_node-path = is_prefix-path. + ls_node-name = is_prefix-name. + ls_node-index = iv_index. + ls_node-order = iv_item_order. IF mi_custom_mapping IS BOUND. - -name = mi_custom_mapping->to_json( iv_path = is_prefix-path - iv_name = is_prefix-name ). + ls_node-name = mi_custom_mapping->to_json( + iv_path = is_prefix-path + iv_name = is_prefix-name ). ENDIF. - IF -name IS INITIAL. - -name = is_prefix-name. + IF ls_node-name IS INITIAL. + ls_node-name = is_prefix-name. ENDIF. IF io_type->absolute_name = '\TYPE-POOL=ABAP\TYPE=ABAP_BOOL' @@ -1094,53 +1101,56 @@ CLASS lcl_abap_to_json IMPLEMENTATION. OR io_type->absolute_name = '\TYPE=XSDBOOLEAN' OR io_type->absolute_name = '\TYPE=FLAG' OR io_type->absolute_name = '\TYPE=XFELD'. - -type = zif_abapgit_ajson=>node_type-boolean. + ls_node-type = zif_abapgit_ajson=>node_type-boolean. IF iv_data IS NOT INITIAL. - -value = 'true'. + ls_node-value = 'true'. ELSE. - -value = 'false'. + ls_node-value = 'false'. ENDIF. ELSEIF io_type->type_kind CO 'CNgXyDT'. " Char like, date/time, xstring - -type = zif_abapgit_ajson=>node_type-string. - -value = |{ iv_data }|. + ls_node-type = zif_abapgit_ajson=>node_type-string. + ls_node-value = |{ iv_data }|. ELSEIF io_type->type_kind CO 'bsI8PaeF'. " Numeric - -type = zif_abapgit_ajson=>node_type-number. - -value = |{ iv_data }|. + ls_node-type = zif_abapgit_ajson=>node_type-number. + ls_node-value = |{ iv_data }|. ELSE. zcx_abapgit_ajson_error=>raise( |Unexpected elementary type [{ io_type->type_kind }] @{ is_prefix-path && is_prefix-name }| ). ENDIF. + APPEND ls_node TO ct_nodes. + ENDMETHOD. METHOD convert_ref. - FIELD-SYMBOLS LIKE LINE OF ct_nodes. + DATA ls_node LIKE LINE OF ct_nodes. - APPEND INITIAL LINE TO ct_nodes ASSIGNING . - - -path = is_prefix-path. - -name = is_prefix-name. - -index = iv_index. - -order = iv_item_order. + ls_node-path = is_prefix-path. + ls_node-name = is_prefix-name. + ls_node-index = iv_index. + ls_node-order = iv_item_order. IF mi_custom_mapping IS BOUND. - -name = mi_custom_mapping->to_json( iv_path = is_prefix-path - iv_name = is_prefix-name ). + ls_node-name = mi_custom_mapping->to_json( + iv_path = is_prefix-path + iv_name = is_prefix-name ). ENDIF. - IF -name IS INITIAL. - -name = is_prefix-name. + IF ls_node-name IS INITIAL. + ls_node-name = is_prefix-name. ENDIF. IF iv_data IS INITIAL. - -type = zif_abapgit_ajson=>node_type-null. - -value = 'null'. + ls_node-type = zif_abapgit_ajson=>node_type-null. + ls_node-value = 'null'. ELSE. " TODO support data references zcx_abapgit_ajson_error=>raise( |Unexpected reference @{ is_prefix-path && is_prefix-name }| ). ENDIF. + APPEND ls_node TO ct_nodes. + ENDMETHOD. METHOD convert_struc. @@ -1149,11 +1159,40 @@ CLASS lcl_abap_to_json IMPLEMENTATION. DATA lt_comps TYPE cl_abap_structdescr=>component_table. DATA ls_next_prefix LIKE is_prefix. DATA lv_item_order TYPE i. + DATA ls_root LIKE LINE OF ct_nodes. - FIELD-SYMBOLS LIKE LINE OF ct_nodes. + FIELD-SYMBOLS LIKE ls_root. FIELD-SYMBOLS LIKE LINE OF lt_comps. FIELD-SYMBOLS TYPE any. + " Object root + + IF cs_root IS SUPPLIED. " call for include structure + ASSIGN cs_root TO . + ELSE. " First call + ls_root-path = is_prefix-path. + ls_root-name = is_prefix-name. + ls_root-type = zif_abapgit_ajson=>node_type-object. + ls_root-index = iv_index. + + IF mi_custom_mapping IS BOUND. + ls_root-name = mi_custom_mapping->to_json( + iv_path = is_prefix-path + iv_name = is_prefix-name ). + ENDIF. + + IF ls_root-name IS INITIAL. + ls_root-name = is_prefix-name. + ENDIF. + + ls_root-order = iv_item_order. + + APPEND ls_root TO ct_nodes ASSIGNING . + + ENDIF. + + " Object attributes + lo_struc ?= io_type. lt_comps = lo_struc->get_components( ). " get_components is potentially much slower than lo_struc->components @@ -1161,27 +1200,6 @@ CLASS lcl_abap_to_json IMPLEMENTATION. " and rtti seems to cache type descriptions really well (https://github.com/sbcgua/benchmarks.git) " the structures will be repeated in real life - IF cs_root IS SUPPLIED. " call for include structure - ASSIGN cs_root TO . - ELSE. " First call - APPEND INITIAL LINE TO ct_nodes ASSIGNING . - -path = is_prefix-path. - -name = is_prefix-name. - -type = zif_abapgit_ajson=>node_type-object. - -index = iv_index. - - IF mi_custom_mapping IS BOUND. - -name = mi_custom_mapping->to_json( iv_path = is_prefix-path - iv_name = is_prefix-name ). - ENDIF. - - IF -name IS INITIAL. - -name = is_prefix-name. - ENDIF. - - -order = iv_item_order. - ENDIF. - ls_next_prefix-path = is_prefix-path && is_prefix-name && '/'. LOOP AT lt_comps ASSIGNING . @@ -1229,30 +1247,37 @@ CLASS lcl_abap_to_json IMPLEMENTATION. DATA lo_ltype TYPE REF TO cl_abap_typedescr. DATA ls_next_prefix LIKE is_prefix. DATA lv_tabix TYPE sy-tabix. + DATA ls_root LIKE LINE OF ct_nodes. - FIELD-SYMBOLS LIKE LINE OF ct_nodes. + FIELD-SYMBOLS LIKE ls_root. FIELD-SYMBOLS TYPE ANY TABLE. FIELD-SYMBOLS TYPE any. - lo_table ?= io_type. - lo_ltype = lo_table->get_table_line_type( ). + " Array root - APPEND INITIAL LINE TO ct_nodes ASSIGNING . - -path = is_prefix-path. - -name = is_prefix-name. - -type = zif_abapgit_ajson=>node_type-array. - -index = iv_index. - -order = iv_item_order. + ls_root-path = is_prefix-path. + ls_root-name = is_prefix-name. + ls_root-type = zif_abapgit_ajson=>node_type-array. + ls_root-index = iv_index. + ls_root-order = iv_item_order. IF mi_custom_mapping IS BOUND. - -name = mi_custom_mapping->to_json( iv_path = is_prefix-path - iv_name = is_prefix-name ). + ls_root-name = mi_custom_mapping->to_json( + iv_path = is_prefix-path + iv_name = is_prefix-name ). ENDIF. - IF -name IS INITIAL. - -name = is_prefix-name. + IF ls_root-name IS INITIAL. + ls_root-name = is_prefix-name. ENDIF. + APPEND ls_root TO ct_nodes ASSIGNING . + + " Array items + + lo_table ?= io_type. + lo_ltype = lo_table->get_table_line_type( ). + ls_next_prefix-path = is_prefix-path && is_prefix-name && '/'. ASSIGN iv_data TO . @@ -1283,7 +1308,7 @@ CLASS lcl_abap_to_json IMPLEMENTATION. lo_type = cl_abap_typedescr=>describe_by_data( iv_data ). CREATE OBJECT lo_converter. - lo_converter->mi_custom_mapping = ii_custom_mapping. + lo_converter->mi_custom_mapping = ii_custom_mapping. lo_converter->mv_keep_item_order = iv_keep_item_order. lo_converter->insert_value_with_type( @@ -1301,8 +1326,7 @@ CLASS lcl_abap_to_json IMPLEMENTATION. METHOD insert_value_with_type. DATA lv_prefix TYPE string. - - FIELD-SYMBOLS LIKE LINE OF ct_nodes. + DATA ls_node LIKE LINE OF ct_nodes. lv_prefix = is_prefix-path && is_prefix-name. IF io_type->type_kind CO 'CNgXyDT'. " Char like, date/time, xstring @@ -1324,24 +1348,125 @@ CLASS lcl_abap_to_json IMPLEMENTATION. zcx_abapgit_ajson_error=>raise( |Unexpected type [{ io_type->type_kind }] @{ lv_prefix }| ). ENDIF. - APPEND INITIAL LINE TO ct_nodes ASSIGNING . - - -path = is_prefix-path. - -name = is_prefix-name. - -index = iv_index. - -value = iv_data. - -type = iv_type. - -order = iv_item_order. + ls_node-path = is_prefix-path. + ls_node-name = is_prefix-name. + ls_node-index = iv_index. + ls_node-value = iv_data. + ls_node-type = iv_type. + ls_node-order = iv_item_order. IF mi_custom_mapping IS BOUND. - -name = mi_custom_mapping->to_json( iv_path = is_prefix-path - iv_name = is_prefix-name ). + ls_node-name = mi_custom_mapping->to_json( + iv_path = is_prefix-path + iv_name = is_prefix-name ). ENDIF. - IF -name IS INITIAL. - -name = is_prefix-name. + IF ls_node-name IS INITIAL. + ls_node-name = is_prefix-name. ENDIF. + APPEND ls_node TO ct_nodes. + + ENDMETHOD. + +ENDCLASS. + +********************************************************************** +* FILTER RUNNER +********************************************************************** + +CLASS lcl_filter_runner DEFINITION FINAL. + PUBLIC SECTION. + METHODS run + IMPORTING + ii_filter TYPE REF TO zif_abapgit_ajson_filter + it_source_tree TYPE zif_abapgit_ajson=>ty_nodes_ts + CHANGING + ct_dest_tree TYPE zif_abapgit_ajson=>ty_nodes_ts + RAISING + zcx_abapgit_ajson_error. + + PRIVATE SECTION. + DATA mi_filter TYPE REF TO zif_abapgit_ajson_filter. + DATA mr_source_tree TYPE REF TO zif_abapgit_ajson=>ty_nodes_ts. + DATA mr_dest_tree TYPE REF TO zif_abapgit_ajson=>ty_nodes_ts. + + METHODS walk + IMPORTING + iv_path TYPE string + CHANGING + cs_parent TYPE zif_abapgit_ajson=>ty_node OPTIONAL + RAISING + zcx_abapgit_ajson_error. + +ENDCLASS. + +CLASS lcl_filter_runner IMPLEMENTATION. + + METHOD run. + + ASSERT ii_filter IS BOUND. + mi_filter = ii_filter. + CLEAR ct_dest_tree. + + GET REFERENCE OF it_source_tree INTO mr_source_tree. + GET REFERENCE OF ct_dest_tree INTO mr_dest_tree. + + walk( iv_path = '' ). + + ENDMETHOD. + + METHOD walk. + + DATA ls_node TYPE zif_abapgit_ajson=>ty_node. + + LOOP AT mr_source_tree->* INTO ls_node WHERE path = iv_path. + CASE ls_node-type. + WHEN zif_abapgit_ajson=>node_type-boolean OR zif_abapgit_ajson=>node_type-null + OR zif_abapgit_ajson=>node_type-number OR zif_abapgit_ajson=>node_type-string. + + IF mi_filter->keep_node( ls_node ) = abap_false. + CONTINUE. + ENDIF. + + WHEN zif_abapgit_ajson=>node_type-array OR zif_abapgit_ajson=>node_type-object. + + IF mi_filter->keep_node( + is_node = ls_node + iv_visit = zif_abapgit_ajson_filter=>visit_type-open ) = abap_false. + CONTINUE. + ENDIF. + + " Intentionally clear AFTER "open" + CLEAR ls_node-children. + + walk( + EXPORTING + iv_path = iv_path && ls_node-name && `/` + CHANGING + cs_parent = ls_node ). + + IF mi_filter->keep_node( + is_node = ls_node + iv_visit = zif_abapgit_ajson_filter=>visit_type-close ) = abap_false. + CONTINUE. + ENDIF. + + WHEN OTHERS. + zcx_abapgit_ajson_error=>raise( |Unexpected node type { ls_node-type }| ). + ENDCASE. + + IF cs_parent IS SUPPLIED. + cs_parent-children = cs_parent-children + 1. + IF cs_parent-type = zif_abapgit_ajson=>node_type-array. + ls_node-name = |{ cs_parent-children }|. + ls_node-index = cs_parent-children. + ENDIF. + ENDIF. + INSERT ls_node INTO TABLE mr_dest_tree->*. + + ENDLOOP. + ENDMETHOD. ENDCLASS. diff --git a/src/json/zcl_abapgit_ajson.clas.testclasses.abap b/src/json/zcl_abapgit_ajson.clas.testclasses.abap index 87349bc40..0c1061599 100644 --- a/src/json/zcl_abapgit_ajson.clas.testclasses.abap +++ b/src/json/zcl_abapgit_ajson.clas.testclasses.abap @@ -1695,6 +1695,7 @@ CLASS ltcl_writer_test DEFINITION FINAL METHODS read_only FOR TESTING RAISING zcx_abapgit_ajson_error. METHODS set_array_obj FOR TESTING RAISING zcx_abapgit_ajson_error. METHODS set_with_type FOR TESTING RAISING zcx_abapgit_ajson_error. + METHODS set_with_type_slice IMPORTING io_json_in TYPE REF TO zcl_abapgit_ajson @@ -1920,24 +1921,22 @@ CLASS ltcl_writer_test IMPLEMENTATION. METHOD ignore_empty. DATA lo_nodes TYPE REF TO lcl_nodes_helper. - DATA lo_cut TYPE REF TO zcl_abapgit_ajson. - DATA li_writer TYPE REF TO zif_abapgit_ajson. + DATA li_cut TYPE REF TO zif_abapgit_ajson. - lo_cut = zcl_abapgit_ajson=>create_empty( ). - li_writer = lo_cut. + li_cut = zcl_abapgit_ajson=>create_empty( ). CREATE OBJECT lo_nodes. lo_nodes->add( ' | |object | ||1' ). lo_nodes->add( '/ |a |num |1 ||0' ). - li_writer->set( + li_cut->set( iv_path = '/a' iv_val = 1 ). - li_writer->set( " ignore empty + li_cut->set( " ignore empty iv_path = '/b' iv_val = 0 ). cl_abap_unit_assert=>assert_equals( - act = lo_cut->mt_json_tree + act = li_cut->mt_json_tree exp = lo_nodes->sorted( ) ). CREATE OBJECT lo_nodes. @@ -1945,12 +1944,12 @@ CLASS ltcl_writer_test IMPLEMENTATION. lo_nodes->add( '/ |a |num |1 ||0' ). lo_nodes->add( '/ |b |num |0 ||0' ). - li_writer->set( + li_cut->set( iv_ignore_empty = abap_false iv_path = '/b' iv_val = 0 ). cl_abap_unit_assert=>assert_equals( - act = lo_cut->mt_json_tree + act = li_cut->mt_json_tree exp = lo_nodes->sorted( ) ). ENDMETHOD. @@ -2610,6 +2609,7 @@ CLASS ltcl_writer_test IMPLEMENTATION. ENDLOOP. ENDMETHOD. + ENDCLASS. @@ -3243,3 +3243,174 @@ CLASS ltcl_abap_to_json IMPLEMENTATION. ENDMETHOD. ENDCLASS. + +********************************************************************** +* FILTER TEST +********************************************************************** + +CLASS ltcl_filter_test DEFINITION FINAL + FOR TESTING + DURATION SHORT + RISK LEVEL HARMLESS. + + PUBLIC SECTION. + INTERFACES zif_abapgit_ajson_filter. + + PRIVATE SECTION. + + TYPES: + BEGIN OF ty_visit_history, + path TYPE string, + type TYPE zif_abapgit_ajson_filter=>ty_visit_type, + END OF ty_visit_history. + + DATA mt_visit_history TYPE TABLE OF ty_visit_history. + + METHODS simple_test FOR TESTING RAISING zcx_abapgit_ajson_error. + METHODS array_test FOR TESTING RAISING zcx_abapgit_ajson_error. + METHODS visit_types FOR TESTING RAISING zcx_abapgit_ajson_error. + + +ENDCLASS. + +CLASS ltcl_filter_test IMPLEMENTATION. + + METHOD zif_abapgit_ajson_filter~keep_node. + + DATA ls_visit_history LIKE LINE OF mt_visit_history. + + IF iv_visit > 0. + ls_visit_history-type = iv_visit. + ls_visit_history-path = is_node-path && is_node-name && '/'. + APPEND ls_visit_history TO mt_visit_history. + ENDIF. + + rv_keep = boolc( NOT is_node-name CA 'xX' AND NOT is_node-value CA 'xX' ). + + ENDMETHOD. + + METHOD simple_test. + + DATA lo_json TYPE REF TO zcl_abapgit_ajson. + DATA lo_json_filtered TYPE REF TO zcl_abapgit_ajson. + DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper. + + lo_json = zcl_abapgit_ajson=>create_empty( ). + lo_json->set( + iv_path = '/a' + iv_val = 1 ). + lo_json->set( + iv_path = '/b' + iv_val = 1 ). + lo_json->set( + iv_path = '/x' + iv_val = 1 ). + lo_json->set( + iv_path = '/c/x' + iv_val = 1 ). + lo_json->set( + iv_path = '/c/y' + iv_val = 1 ). + + lo_json_filtered = zcl_abapgit_ajson=>create_from( + ii_source_json = lo_json + ii_filter = me ). + + CREATE OBJECT lo_nodes_exp. + lo_nodes_exp->add( ' | |object | | |3' ). + lo_nodes_exp->add( '/ |a |num |1 | |0' ). + lo_nodes_exp->add( '/ |b |num |1 | |0' ). + lo_nodes_exp->add( '/ |c |object | | |1' ). + lo_nodes_exp->add( '/c/ |y |num |1 | |0' ). + + cl_abap_unit_assert=>assert_equals( + act = lo_json_filtered->mt_json_tree + exp = lo_nodes_exp->sorted( ) ). + + ENDMETHOD. + + METHOD array_test. + + DATA lo_json TYPE REF TO zcl_abapgit_ajson. + DATA lo_json_filtered TYPE REF TO zcl_abapgit_ajson. + DATA lo_nodes_exp TYPE REF TO lcl_nodes_helper. + + lo_json = zcl_abapgit_ajson=>create_empty( ). + lo_json->touch_array( '/' ). + lo_json->push( + iv_path = '/' + iv_val = 'a' ). + lo_json->push( + iv_path = '/' + iv_val = 'x' ). + lo_json->push( + iv_path = '/' + iv_val = 'b' ). + + lo_json_filtered = zcl_abapgit_ajson=>create_from( + ii_source_json = lo_json + ii_filter = me ). + + CREATE OBJECT lo_nodes_exp. + lo_nodes_exp->add( ' | |array | | |2' ). + lo_nodes_exp->add( '/ |1 |str |a |1|0' ). + lo_nodes_exp->add( '/ |2 |str |b |2|0' ). + + cl_abap_unit_assert=>assert_equals( + act = lo_json_filtered->mt_json_tree + exp = lo_nodes_exp->sorted( ) ). + + ENDMETHOD. + + METHOD visit_types. + + DATA lo_json TYPE REF TO zcl_abapgit_ajson. + DATA lo_json_filtered TYPE REF TO zcl_abapgit_ajson. + + DATA lt_visits_exp LIKE mt_visit_history. + FIELD-SYMBOLS LIKE LINE OF lt_visits_exp. + + DATA: + BEGIN OF ls_dummy, + d TYPE i VALUE 10, + e TYPE i VALUE 20, + END OF ls_dummy. + + CLEAR mt_visit_history. + + lo_json = zcl_abapgit_ajson=>create_empty( ). + lo_json->touch_array( '/' ). + lo_json->push( + iv_path = '/' + iv_val = 'a' ). + lo_json->push( + iv_path = '/' + iv_val = 'b' ). + lo_json->push( + iv_path = '/' + iv_val = ls_dummy ). + + lo_json_filtered = zcl_abapgit_ajson=>create_from( + ii_source_json = lo_json + ii_filter = me ). + + APPEND INITIAL LINE TO lt_visits_exp ASSIGNING . + -path = '/'. + -type = zif_abapgit_ajson_filter=>visit_type-open. + APPEND INITIAL LINE TO lt_visits_exp ASSIGNING . + -path = '/3/'. + -type = zif_abapgit_ajson_filter=>visit_type-open. + APPEND INITIAL LINE TO lt_visits_exp ASSIGNING . + -path = '/3/'. + -type = zif_abapgit_ajson_filter=>visit_type-close. + APPEND INITIAL LINE TO lt_visits_exp ASSIGNING . + -path = '/'. + -type = zif_abapgit_ajson_filter=>visit_type-close. + + cl_abap_unit_assert=>assert_equals( + act = mt_visit_history + exp = lt_visits_exp ). + + ENDMETHOD. + +ENDCLASS. diff --git a/src/json/zcl_abapgit_ajson_filter_lib.clas.abap b/src/json/zcl_abapgit_ajson_filter_lib.clas.abap new file mode 100644 index 000000000..5b3f3a9a5 --- /dev/null +++ b/src/json/zcl_abapgit_ajson_filter_lib.clas.abap @@ -0,0 +1,56 @@ +CLASS zcl_abapgit_ajson_filter_lib DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + + CLASS-METHODS create_empty_filter + RETURNING + VALUE(ri_filter) TYPE REF TO zif_abapgit_ajson_filter + RAISING + zcx_abapgit_ajson_error . + CLASS-METHODS create_path_filter + IMPORTING + !it_skip_paths TYPE string_table OPTIONAL + !iv_skip_paths TYPE string OPTIONAL + RETURNING + VALUE(ri_filter) TYPE REF TO zif_abapgit_ajson_filter + RAISING + zcx_abapgit_ajson_error . + CLASS-METHODS create_and_filter + IMPORTING + !it_filters TYPE zif_abapgit_ajson_filter=>ty_filter_tab + RETURNING + VALUE(ri_filter) TYPE REF TO zif_abapgit_ajson_filter + RAISING + zcx_abapgit_ajson_error . + + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + + + +CLASS zcl_abapgit_ajson_filter_lib IMPLEMENTATION. + + + METHOD create_and_filter. + CREATE OBJECT ri_filter TYPE lcl_and_filter + EXPORTING + it_filters = it_filters. + ENDMETHOD. + + + METHOD create_empty_filter. + CREATE OBJECT ri_filter TYPE lcl_empty_filter. + ENDMETHOD. + + + METHOD create_path_filter. + CREATE OBJECT ri_filter TYPE lcl_paths_filter + EXPORTING + it_skip_paths = it_skip_paths + iv_skip_paths = iv_skip_paths. + ENDMETHOD. +ENDCLASS. diff --git a/src/json/zcl_abapgit_ajson_filter_lib.clas.locals_imp.abap b/src/json/zcl_abapgit_ajson_filter_lib.clas.locals_imp.abap new file mode 100644 index 000000000..98239177e --- /dev/null +++ b/src/json/zcl_abapgit_ajson_filter_lib.clas.locals_imp.abap @@ -0,0 +1,129 @@ +********************************************************************** +* FILTER EMPTY VALUES +********************************************************************** + +CLASS lcl_empty_filter DEFINITION FINAL. + PUBLIC SECTION. + INTERFACES zif_abapgit_ajson_filter. +ENDCLASS. + +CLASS lcl_empty_filter IMPLEMENTATION. + METHOD zif_abapgit_ajson_filter~keep_node. + + rv_keep = boolc( + ( iv_visit = zif_abapgit_ajson_filter=>visit_type-value AND is_node-value IS NOT INITIAL ) OR + ( iv_visit <> zif_abapgit_ajson_filter=>visit_type-value AND is_node-children > 0 ) ). + " children = 0 on open for initially empty nodes and on close for filtered ones + + ENDMETHOD. +ENDCLASS. + +********************************************************************** +* FILTER PREDEFINED PATHS +********************************************************************** + +CLASS lcl_paths_filter DEFINITION FINAL. + PUBLIC SECTION. + INTERFACES zif_abapgit_ajson_filter. + METHODS constructor + IMPORTING + it_skip_paths TYPE string_table OPTIONAL + iv_skip_paths TYPE string OPTIONAL + RAISING + zcx_abapgit_ajson_error. + PRIVATE SECTION. + DATA mt_skip_paths TYPE HASHED TABLE OF string WITH UNIQUE KEY table_line. +ENDCLASS. + +CLASS lcl_paths_filter IMPLEMENTATION. + + METHOD zif_abapgit_ajson_filter~keep_node. + + DATA lv_path TYPE string. + + lv_path = is_node-path && is_node-name. + READ TABLE mt_skip_paths WITH KEY table_line = lv_path TRANSPORTING NO FIELDS. + rv_keep = boolc( sy-subrc <> 0 ). + + ENDMETHOD. + + METHOD constructor. + + DATA lv_s TYPE string. + DATA lt_tab TYPE string_table. + FIELD-SYMBOLS TYPE string. + + IF boolc( iv_skip_paths IS INITIAL ) = boolc( it_skip_paths IS INITIAL ). " XOR + zcx_abapgit_ajson_error=>raise( 'no filter path specified' ). + ENDIF. + + LOOP AT it_skip_paths INTO lv_s. + lv_s = to_lower( lv_s ). + APPEND lv_s TO lt_tab. + ENDLOOP. + + IF iv_skip_paths IS NOT INITIAL. + SPLIT iv_skip_paths AT ',' INTO TABLE lt_tab. + LOOP AT lt_tab ASSIGNING . + IF IS INITIAL. + DELETE lt_tab INDEX sy-tabix. + CONTINUE. + ENDIF. + = condense( to_lower( ) ). + ENDLOOP. + ENDIF. + + SORT lt_tab BY table_line. + DELETE ADJACENT DUPLICATES FROM lt_tab. + + mt_skip_paths = lt_tab. + + ENDMETHOD. + +ENDCLASS. + +********************************************************************** +* MULTI FILTER +********************************************************************** + +CLASS lcl_and_filter DEFINITION FINAL. + PUBLIC SECTION. + INTERFACES zif_abapgit_ajson_filter. + METHODS constructor + IMPORTING + it_filters TYPE zif_abapgit_ajson_filter=>ty_filter_tab + RAISING + zcx_abapgit_ajson_error. + PRIVATE SECTION. + DATA mt_filters TYPE zif_abapgit_ajson_filter=>ty_filter_tab. +ENDCLASS. + +CLASS lcl_and_filter IMPLEMENTATION. + + METHOD zif_abapgit_ajson_filter~keep_node. + + DATA li_filter LIKE LINE OF mt_filters. + + rv_keep = abap_true. + LOOP AT mt_filters INTO li_filter. + rv_keep = li_filter->keep_node( + is_node = is_node + iv_visit = iv_visit ). + IF rv_keep = abap_false. + RETURN. + ENDIF. + ENDLOOP. + + ENDMETHOD. + + METHOD constructor. + + DATA li_filter LIKE LINE OF it_filters. + + LOOP AT it_filters INTO li_filter WHERE table_line IS BOUND. + APPEND li_filter TO mt_filters. + ENDLOOP. + + ENDMETHOD. + +ENDCLASS. diff --git a/src/json/zcl_abapgit_ajson_filter_lib.clas.testclasses.abap b/src/json/zcl_abapgit_ajson_filter_lib.clas.testclasses.abap new file mode 100644 index 000000000..d055dab26 --- /dev/null +++ b/src/json/zcl_abapgit_ajson_filter_lib.clas.testclasses.abap @@ -0,0 +1,168 @@ +CLASS ltcl_filters_test DEFINITION FINAL + FOR TESTING + RISK LEVEL HARMLESS + DURATION SHORT. + PRIVATE SECTION. + METHODS empty_filter_simple FOR TESTING RAISING zcx_abapgit_ajson_error. + METHODS empty_filter_deep FOR TESTING RAISING zcx_abapgit_ajson_error. + METHODS path_filter FOR TESTING RAISING zcx_abapgit_ajson_error. + METHODS path_filter_deep FOR TESTING RAISING zcx_abapgit_ajson_error. + METHODS and_filter FOR TESTING RAISING zcx_abapgit_ajson_error. +ENDCLASS. + + +CLASS ltcl_filters_test IMPLEMENTATION. + + METHOD empty_filter_simple. + + DATA li_json TYPE REF TO zif_abapgit_ajson. + DATA li_json_filtered TYPE REF TO zif_abapgit_ajson. + + li_json = zcl_abapgit_ajson=>create_empty( ). + li_json->set( + iv_path = '/a' + iv_val = '1' ). + li_json->set( + iv_path = '/b' + iv_val = '' ). + li_json->set( + iv_path = '/c' + iv_val = '3' ). + li_json->set( + iv_path = '/d' + iv_val = 0 ). + + li_json_filtered = zcl_abapgit_ajson=>create_from( + ii_source_json = li_json + ii_filter = zcl_abapgit_ajson_filter_lib=>create_empty_filter( ) ). + + cl_abap_unit_assert=>assert_equals( + act = li_json_filtered->stringify( ) + exp = '{"a":"1","c":"3"}' ). + + ENDMETHOD. + + METHOD empty_filter_deep. + + DATA li_json TYPE REF TO zif_abapgit_ajson. + DATA li_json_filtered TYPE REF TO zif_abapgit_ajson. + + li_json = zcl_abapgit_ajson=>create_empty( ). + li_json->set( + iv_path = '/a' + iv_val = '1' ). + li_json->set( + iv_path = '/b/c' + iv_val = '' ). + li_json->set( + iv_path = '/b/d' + iv_val = 0 ). + li_json->set( + iv_path = '/d/e' + iv_val = 0 ). + + li_json_filtered = zcl_abapgit_ajson=>create_from( + ii_source_json = li_json + ii_filter = zcl_abapgit_ajson_filter_lib=>create_empty_filter( ) ). + + cl_abap_unit_assert=>assert_equals( + act = li_json_filtered->stringify( ) + exp = '{"a":"1"}' ). + + ENDMETHOD. + + METHOD path_filter. + + DATA li_json TYPE REF TO zif_abapgit_ajson. + DATA li_json_filtered TYPE REF TO zif_abapgit_ajson. + DATA lt_paths TYPE string_table. + + APPEND '/b/c' TO lt_paths. + + li_json = zcl_abapgit_ajson=>create_empty( ). + li_json->set( + iv_path = '/a' + iv_val = '1' ). + li_json->set( + iv_path = '/b/c' + iv_val = '2' ). + li_json->set( + iv_path = '/c/d' + iv_val = '3' ). + + li_json_filtered = zcl_abapgit_ajson=>create_from( + ii_source_json = li_json + ii_filter = zcl_abapgit_ajson_filter_lib=>create_path_filter( it_skip_paths = lt_paths ) ). + + cl_abap_unit_assert=>assert_equals( + act = li_json_filtered->stringify( ) + exp = '{"a":"1","b":{},"c":{"d":"3"}}' ). + + ENDMETHOD. + + METHOD path_filter_deep. + + DATA li_json TYPE REF TO zif_abapgit_ajson. + DATA li_json_filtered TYPE REF TO zif_abapgit_ajson. + DATA lt_paths TYPE string_table. + + APPEND '/b' TO lt_paths. + + li_json = zcl_abapgit_ajson=>create_empty( ). + li_json->set( + iv_path = '/a' + iv_val = '1' ). + li_json->set( + iv_path = '/b/c' + iv_val = '2' ). + li_json->set( + iv_path = '/b/d' + iv_val = 'x' ). + li_json->set( + iv_path = '/c/d' + iv_val = '3' ). + + li_json_filtered = zcl_abapgit_ajson=>create_from( + ii_source_json = li_json + ii_filter = zcl_abapgit_ajson_filter_lib=>create_path_filter( it_skip_paths = lt_paths ) ). + + cl_abap_unit_assert=>assert_equals( + act = li_json_filtered->stringify( ) + exp = '{"a":"1","c":{"d":"3"}}' ). + + ENDMETHOD. + + METHOD and_filter. + + DATA li_json TYPE REF TO zif_abapgit_ajson. + DATA li_json_filtered TYPE REF TO zif_abapgit_ajson. + DATA lt_filters TYPE zif_abapgit_ajson_filter=>ty_filter_tab. + + APPEND zcl_abapgit_ajson_filter_lib=>create_empty_filter( ) TO lt_filters. + APPEND zcl_abapgit_ajson_filter_lib=>create_path_filter( iv_skip_paths = '/c' ) TO lt_filters. + + li_json = zcl_abapgit_ajson=>create_empty( ). + li_json->set( + iv_path = '/a' + iv_val = '1' ). + li_json->set( + iv_path = '/b' + iv_val = '' ). + li_json->set( + iv_path = '/c' + iv_val = '3' ). + li_json->set( + iv_path = '/d' + iv_val = 0 ). + + li_json_filtered = zcl_abapgit_ajson=>create_from( + ii_source_json = li_json + ii_filter = zcl_abapgit_ajson_filter_lib=>create_and_filter( lt_filters ) ). + + cl_abap_unit_assert=>assert_equals( + act = li_json_filtered->stringify( ) + exp = '{"a":"1"}' ). + + ENDMETHOD. + +ENDCLASS. diff --git a/src/json/zcl_abapgit_ajson_filter_lib.clas.xml b/src/json/zcl_abapgit_ajson_filter_lib.clas.xml new file mode 100644 index 000000000..bb7a3ed6a --- /dev/null +++ b/src/json/zcl_abapgit_ajson_filter_lib.clas.xml @@ -0,0 +1,17 @@ + + + + + + ZCL_ABAPGIT_AJSON_FILTER_LIB + E + AJson common typical filters + 1 + X + X + X + X + + + + diff --git a/src/json/zif_abapgit_ajson.intf.abap b/src/json/zif_abapgit_ajson.intf.abap index f8453000a..2ee60d8f2 100644 --- a/src/json/zif_abapgit_ajson.intf.abap +++ b/src/json/zif_abapgit_ajson.intf.abap @@ -1,7 +1,7 @@ INTERFACE zif_abapgit_ajson PUBLIC. - CONSTANTS version TYPE string VALUE 'v1.1.0'. "#EC NOTEXT + CONSTANTS version TYPE string VALUE 'v1.1.1-beta'. "#EC NOTEXT CONSTANTS origin TYPE string VALUE 'https://github.com/sbcgua/ajson'. "#EC NOTEXT CONSTANTS license TYPE string VALUE 'MIT'. "#EC NOTEXT diff --git a/src/json/zif_abapgit_ajson_filter.intf.abap b/src/json/zif_abapgit_ajson_filter.intf.abap new file mode 100644 index 000000000..50f4816ee --- /dev/null +++ b/src/json/zif_abapgit_ajson_filter.intf.abap @@ -0,0 +1,23 @@ +INTERFACE zif_abapgit_ajson_filter + PUBLIC. + + TYPES ty_filter_tab TYPE STANDARD TABLE OF REF TO zif_abapgit_ajson_filter WITH DEFAULT KEY. + TYPES ty_visit_type TYPE i. + + CONSTANTS: + BEGIN OF visit_type, + value TYPE ty_visit_type VALUE 0, + open TYPE ty_visit_type VALUE 1, + close TYPE ty_visit_type VALUE 2, + END OF visit_type. + + METHODS keep_node + IMPORTING + is_node TYPE zif_abapgit_ajson=>ty_node + iv_visit TYPE ty_visit_type DEFAULT visit_type-value + RETURNING + VALUE(rv_keep) TYPE abap_bool + RAISING + zcx_abapgit_ajson_error. + +ENDINTERFACE. diff --git a/src/json/zif_abapgit_ajson_filter.intf.xml b/src/json/zif_abapgit_ajson_filter.intf.xml new file mode 100644 index 000000000..f13a0f07c --- /dev/null +++ b/src/json/zif_abapgit_ajson_filter.intf.xml @@ -0,0 +1,15 @@ + + + + + + ZIF_ABAPGIT_AJSON_FILTER + E + AJSON filter interface + 2 + 1 + X + + + + diff --git a/test/abap_transpile.json b/test/abap_transpile.json index 6992f764a..7c13075a8 100644 --- a/test/abap_transpile.json +++ b/test/abap_transpile.json @@ -162,11 +162,15 @@ {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_json_to_abap", "method": "find_loc", "note": "assert failed"}, {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_json_to_abap", "method": "to_abap_negative"}, + {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_json_to_abap", "method": "to_abap", "note": "Void type: TIMESTAMPL"}, {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "set_obj"}, + {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "set_ajson"}, + {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "set_tab"}, {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "set_tab_hashed", "note": "runtime error, SortByLengthZero"}, {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "arrays"}, {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_writer_test", "method": "root_assignment"}, + {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_reader_test", "method": "get_timestamp", "note": "Void type: TIMESTAMPL"}, {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_parser_test", "method": "parse_error"}, @@ -174,8 +178,29 @@ {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_integrated", "method": "array_index", "note": "Index not found in table @/10"}, {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_integrated", "method": "array_simple", "note": "Index not found in table @/10"}, {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_integrated", "method": "item_order_integrated"}, + {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_integrated", "method": "stringify"}, + + {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_abap_to_json", "method": "set_obj"}, + {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_abap_to_json", "method": "set_array"}, + {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_abap_to_json", "method": "set_complex_obj"}, + + {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_filter_test", "method": "simple_test"}, + {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_filter_test", "method": "array_test"}, + {"object": "ZCL_ABAPGIT_AJSON", "class": "ltcl_filter_test", "method": "visit_types"}, + + {"object": "ZCL_ABAPGIT_AJSON_FILTER_LIB", "class": "ltcl_filters_test", "method": "empty_filter_simple"}, + {"object": "ZCL_ABAPGIT_AJSON_FILTER_LIB", "class": "ltcl_filters_test", "method": "empty_filter_deep"}, + {"object": "ZCL_ABAPGIT_AJSON_FILTER_LIB", "class": "ltcl_filters_test", "method": "path_filter"}, + {"object": "ZCL_ABAPGIT_AJSON_FILTER_LIB", "class": "ltcl_filters_test", "method": "path_filter_deep"}, + {"object": "ZCL_ABAPGIT_AJSON_FILTER_LIB", "class": "ltcl_filters_test", "method": "and_filter"}, {"object": "ZCL_ABAPGIT_AJSON_MAPPING", "class": "ltcl_camel_case", "method": "to_abap", "note": "secondary key fields? READ WITH KEY, Path not found @/FieldData"}, + {"object": "ZCL_ABAPGIT_AJSON_MAPPING", "class": "ltcl_camel_case", "method": "to_json"}, + {"object": "ZCL_ABAPGIT_AJSON_MAPPING", "class": "ltcl_camel_case", "method": "to_json_first_lower"}, + + {"object": "ZCL_ABAPGIT_AJSON_MAPPING", "class": "ltcl_fields", "method": "to_json"}, + {"object": "ZCL_ABAPGIT_AJSON_MAPPING", "class": "ltcl_to_lower", "method": "to_json"}, + {"object": "ZCL_ABAPGIT_AJSON_MAPPING", "class": "ltcl_to_upper", "method": "to_json"}, {"object": "ZCL_ABAPGIT_GUI_UTILS", "class": "ltcl_gui_utils", "method": "is_renderable", "note": "casting, https://github.com/abaplint/transpiler/issues/465"}, {"object": "ZCL_ABAPGIT_GUI_UTILS", "class": "ltcl_gui_utils", "method": "is_event_handler", "note": "casting, https://github.com/abaplint/transpiler/issues/465"},