diff --git a/src/objects/aff/zcl_abapgit_aff_registry.clas.abap b/src/objects/aff/zcl_abapgit_aff_registry.clas.abap
new file mode 100644
index 000000000..e533a5919
--- /dev/null
+++ b/src/objects/aff/zcl_abapgit_aff_registry.clas.abap
@@ -0,0 +1,79 @@
+CLASS zcl_abapgit_aff_registry DEFINITION
+ PUBLIC
+ FINAL
+ CREATE PUBLIC .
+
+ PUBLIC SECTION.
+ INTERFACES:
+ zif_abapgit_aff_registry.
+
+ METHODS:
+ constructor
+ IMPORTING
+ io_settings TYPE REF TO zcl_abapgit_settings OPTIONAL.
+ PROTECTED SECTION.
+ PRIVATE SECTION.
+ TYPES:
+ BEGIN OF ty_registry_entry,
+ obj_type TYPE tadir-object,
+ experimental TYPE abap_bool,
+ END OF ty_registry_entry.
+
+ CLASS-DATA:
+ gt_registry TYPE HASHED TABLE OF ty_registry_entry WITH UNIQUE KEY obj_type.
+
+ DATA:
+ mo_settings TYPE REF TO zcl_abapgit_settings.
+
+ CLASS-METHODS:
+ register
+ IMPORTING
+ iv_obj_type TYPE tadir-object
+ iv_experimental TYPE abap_bool DEFAULT abap_false.
+
+ENDCLASS.
+
+
+CLASS zcl_abapgit_aff_registry IMPLEMENTATION.
+
+ METHOD constructor.
+ IF io_settings IS SUPPLIED.
+ mo_settings = io_settings.
+ ELSE.
+ mo_settings = zcl_abapgit_persist_factory=>get_settings( )->read( ).
+ ENDIF.
+ ENDMETHOD.
+
+ METHOD zif_abapgit_aff_registry~is_supported_object_type.
+
+ DATA ls_registry_entry TYPE ty_registry_entry.
+
+ IF gt_registry IS INITIAL.
+ register( iv_obj_type = 'CHKC' ).
+ register( iv_obj_type = 'CHKO' ).
+ register( iv_obj_type = 'CHKV' ).
+ register( iv_obj_type = 'EVTB' ).
+ register( iv_obj_type = 'INTF'
+ iv_experimental = abap_true ).
+ register( iv_obj_type = 'SMBC' ).
+ ENDIF.
+
+ READ TABLE gt_registry WITH TABLE KEY obj_type = iv_obj_type INTO ls_registry_entry.
+ IF sy-subrc = 0 AND ls_registry_entry-experimental = abap_false.
+ rv_result = abap_true.
+ ELSEIF sy-subrc = 0 AND mo_settings->get_experimental_features( ) = abap_true.
+ rv_result = abap_true.
+ ELSE.
+ rv_result = abap_false.
+ ENDIF.
+ ENDMETHOD.
+
+ METHOD register.
+ DATA ls_registry_entry TYPE ty_registry_entry.
+
+ ls_registry_entry-obj_type = iv_obj_type.
+ ls_registry_entry-experimental = iv_experimental.
+ INSERT ls_registry_entry INTO TABLE gt_registry.
+ ENDMETHOD.
+
+ENDCLASS.
diff --git a/src/objects/aff/zcl_abapgit_aff_registry.clas.testclasses.abap b/src/objects/aff/zcl_abapgit_aff_registry.clas.testclasses.abap
new file mode 100644
index 000000000..a66fa6b34
--- /dev/null
+++ b/src/objects/aff/zcl_abapgit_aff_registry.clas.testclasses.abap
@@ -0,0 +1,84 @@
+"! @testing zcl_abapgit_filename_logic
+CLASS ltcl_aff_registry DEFINITION FINAL FOR TESTING
+ DURATION SHORT
+ RISK LEVEL HARMLESS.
+
+ PRIVATE SECTION.
+ METHODS:
+ assert_that
+ IMPORTING
+ iv_obj_type TYPE tadir-object
+ iv_is_supported TYPE abap_bool
+ iv_experimental TYPE abap_bool DEFAULT abap_false,
+ clas_not_supported FOR TESTING RAISING cx_static_check,
+ chkc FOR TESTING RAISING cx_static_check,
+ chko FOR TESTING RAISING cx_static_check,
+ chkv FOR TESTING RAISING cx_static_check,
+ evtb FOR TESTING RAISING cx_static_check,
+ intf_not_supported FOR TESTING RAISING cx_static_check,
+ intf_experimental FOR TESTING RAISING cx_static_check,
+ smbc FOR TESTING RAISING cx_static_check.
+ENDCLASS.
+
+
+CLASS ltcl_aff_registry IMPLEMENTATION.
+
+ METHOD assert_that.
+ DATA:
+ lo_cut TYPE REF TO zif_abapgit_aff_registry,
+ lo_settings_stub TYPE REF TO zcl_abapgit_settings,
+ lv_act TYPE abap_bool.
+
+
+ CREATE OBJECT lo_settings_stub.
+ lo_settings_stub->set_experimental_features( iv_experimental ).
+ CREATE OBJECT lo_cut TYPE zcl_abapgit_aff_registry
+ EXPORTING
+ io_settings = lo_settings_stub.
+ lv_act = lo_cut->is_supported_object_type( iv_obj_type ).
+ cl_abap_unit_assert=>assert_equals( exp = iv_is_supported
+ act = lv_act ).
+ ENDMETHOD.
+
+ METHOD clas_not_supported.
+ assert_that( iv_obj_type = 'CLAS'
+ iv_is_supported = abap_false ).
+ ENDMETHOD.
+
+ METHOD chkc.
+ assert_that( iv_obj_type = 'CHKC'
+ iv_is_supported = abap_true ).
+ ENDMETHOD.
+
+ METHOD chko.
+ assert_that( iv_obj_type = 'CHKO'
+ iv_is_supported = abap_true ).
+ ENDMETHOD.
+
+ METHOD chkv.
+ assert_that( iv_obj_type = 'CHKV'
+ iv_is_supported = abap_true ).
+ ENDMETHOD.
+
+ METHOD evtb.
+ assert_that( iv_obj_type = 'EVTB'
+ iv_is_supported = abap_true ).
+ ENDMETHOD.
+
+ METHOD intf_not_supported.
+ assert_that( iv_obj_type = 'INTF'
+ iv_is_supported = abap_false ).
+ ENDMETHOD.
+
+ METHOD intf_experimental.
+ assert_that( iv_obj_type = 'INTF'
+ iv_is_supported = abap_true
+ iv_experimental = abap_true ).
+ ENDMETHOD.
+
+ METHOD smbc.
+ assert_that( iv_obj_type = 'SMBC'
+ iv_is_supported = abap_true ).
+ ENDMETHOD.
+
+ENDCLASS.
diff --git a/src/objects/aff/zcl_abapgit_aff_registry.clas.xml b/src/objects/aff/zcl_abapgit_aff_registry.clas.xml
new file mode 100644
index 000000000..1750c5917
--- /dev/null
+++ b/src/objects/aff/zcl_abapgit_aff_registry.clas.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ ZCL_ABAPGIT_AFF_REGISTRY
+ E
+ abapGit - Class that tells you whether object type has AFF
+ 1
+ X
+ X
+ X
+ X
+
+
+
+
diff --git a/src/objects/aff/zcl_abapgit_object_common_aff.clas.abap b/src/objects/aff/zcl_abapgit_object_common_aff.clas.abap
index f21c97184..590323cca 100644
--- a/src/objects/aff/zcl_abapgit_object_common_aff.clas.abap
+++ b/src/objects/aff/zcl_abapgit_object_common_aff.clas.abap
@@ -134,6 +134,8 @@ CLASS zcl_abapgit_object_common_aff IMPLEMENTATION.
lr_messages TYPE REF TO data,
lv_json_as_xstring TYPE xstring,
lx_exception TYPE REF TO cx_root,
+ lv_file_name TYPE string,
+ lo_file_name_mapper TYPE REF TO object,
lv_name TYPE c LENGTH 120.
FIELD-SYMBOLS: TYPE any,
@@ -161,11 +163,6 @@ CLASS zcl_abapgit_object_common_aff IMPLEMENTATION.
RECEIVING
result = lo_object_handler.
- CREATE OBJECT lo_object_json_file TYPE ('CL_AFF_FILE')
- EXPORTING
- name = |{ to_lower( lv_name ) }.{ to_lower( ms_item-obj_type ) }.json|
- content = lv_json_as_xstring.
-
CREATE OBJECT lo_object_aff TYPE ('CL_AFF_OBJ')
EXPORTING
package = ms_item-devclass
@@ -180,12 +177,27 @@ CLASS zcl_abapgit_object_common_aff IMPLEMENTATION.
EXPORTING
object = .
+ CALL METHOD ('CL_AFF_FILE_NAME_MAPPER')=>for_json
+ RECEIVING
+ result = lo_file_name_mapper.
+
+ CALL METHOD lo_file_name_mapper->('IF_AFF_FILE_NAME_MAPPER~GET_FILE_NAME_FROM_OBJECT')
+ EXPORTING
+ object =
+ RECEIVING
+ result = lv_file_name.
+
CREATE OBJECT lo_settings TYPE ('CL_AFF_SETTINGS_DESERIALIZE')
EXPORTING
version = 'A'
language = mv_language
user = sy-uname.
+ CREATE OBJECT lo_object_json_file TYPE ('CL_AFF_FILE')
+ EXPORTING
+ name = lv_file_name
+ content = lv_json_as_xstring.
+
CREATE DATA lr_intf_aff_file TYPE REF TO ('IF_AFF_FILE').
ASSIGN lr_intf_aff_file->* TO .
?= lo_object_json_file.
@@ -356,6 +368,9 @@ CLASS zcl_abapgit_object_common_aff IMPLEMENTATION.
lv_json_as_xstring TYPE xstring,
lx_exception TYPE REF TO cx_root,
lv_name TYPE c LENGTH 120,
+ lv_file_name TYPE string,
+ lo_file_name_mapper TYPE REF TO object,
+ lv_is_deletion TYPE abap_bool VALUE abap_false,
lv_dummy TYPE string.
FIELD-SYMBOLS: TYPE any,
@@ -432,9 +447,19 @@ CLASS zcl_abapgit_object_common_aff IMPLEMENTATION.
ENDIF.
ENDLOOP.
+ CALL METHOD ('CL_AFF_FILE_NAME_MAPPER')=>for_json
+ RECEIVING
+ result = lo_file_name_mapper.
+
+ CALL METHOD lo_file_name_mapper->('IF_AFF_FILE_NAME_MAPPER~GET_FILE_NAME_FROM_OBJECT')
+ EXPORTING
+ object =
+ RECEIVING
+ result = lv_file_name.
+
CALL METHOD lo_files_container->('IF_AFF_FILES_CONTAINER~GET_FILE')
EXPORTING
- name = |{ to_lower( lv_name ) }.{ to_lower( ms_item-obj_type ) }.json|
+ name = lv_file_name
RECEIVING
result = lo_object_json_file.
diff --git a/src/objects/aff/zif_abapgit_aff_registry.intf.abap b/src/objects/aff/zif_abapgit_aff_registry.intf.abap
new file mode 100644
index 000000000..27b6a4c7f
--- /dev/null
+++ b/src/objects/aff/zif_abapgit_aff_registry.intf.abap
@@ -0,0 +1,13 @@
+INTERFACE zif_abapgit_aff_registry
+ PUBLIC .
+
+ METHODS:
+ "! Returns TRUE if the object type is supported by ABAP file formats (AFF) in abapGit.
+ "! Either there is a (standalone AFF capable) object handler,
+ "! or object handler calls the AFF framework in newer ABAP systems.
+ is_supported_object_type
+ IMPORTING
+ iv_obj_type TYPE tadir-object
+ RETURNING
+ VALUE(rv_result) TYPE abap_bool.
+ENDINTERFACE.
diff --git a/src/objects/aff/zif_abapgit_aff_registry.intf.xml b/src/objects/aff/zif_abapgit_aff_registry.intf.xml
new file mode 100644
index 000000000..26c1fa815
--- /dev/null
+++ b/src/objects/aff/zif_abapgit_aff_registry.intf.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ ZIF_ABAPGIT_AFF_REGISTRY
+ E
+ abapGit - interface for the aff registry
+ 2
+ 1
+ X
+
+
+
+
diff --git a/src/objects/core/zcl_abapgit_filename_logic.clas.abap b/src/objects/core/zcl_abapgit_filename_logic.clas.abap
index 8d90da0fd..f7d77c008 100644
--- a/src/objects/core/zcl_abapgit_filename_logic.clas.abap
+++ b/src/objects/core/zcl_abapgit_filename_logic.clas.abap
@@ -19,6 +19,7 @@ CLASS zcl_abapgit_filename_logic DEFINITION
extension TYPE c LENGTH 4 VALUE 'json',
END OF c_json_file.
+
CLASS-METHODS file_to_object
IMPORTING
!iv_filename TYPE string
@@ -40,6 +41,9 @@ CLASS zcl_abapgit_filename_logic DEFINITION
VALUE(rv_filename) TYPE string .
PROTECTED SECTION.
PRIVATE SECTION.
+ CLASS-DATA:
+ go_aff_registry TYPE REF TO zif_abapgit_aff_registry.
+
ENDCLASS.
@@ -51,7 +55,7 @@ CLASS zcl_abapgit_filename_logic IMPLEMENTATION.
DATA:
lv_name TYPE string,
- lv_type TYPE string,
+ lv_type TYPE trobjtype,
lv_ext TYPE string.
" Guess object type and name
@@ -61,6 +65,12 @@ CLASS zcl_abapgit_filename_logic IMPLEMENTATION.
REPLACE ALL OCCURRENCES OF '#' IN lv_name WITH '/'.
REPLACE ALL OCCURRENCES OF '#' IN lv_type WITH '/'.
REPLACE ALL OCCURRENCES OF '#' IN lv_ext WITH '/'.
+ " Assume AFF namespace convention
+ CREATE OBJECT go_aff_registry TYPE zcl_abapgit_aff_registry.
+ IF go_aff_registry->is_supported_object_type( lv_type ) = abap_true.
+ REPLACE ALL OCCURRENCES OF '(' IN lv_name WITH '/'.
+ REPLACE ALL OCCURRENCES OF ')' IN lv_name WITH '/'.
+ ENDIF.
" The counter part to this logic must be maintained in OBJECT_TO_FILE
IF lv_type = to_upper( c_package_file-obj_type ).
@@ -88,6 +98,8 @@ CLASS zcl_abapgit_filename_logic IMPLEMENTATION.
METHOD object_to_file.
DATA lv_obj_name TYPE string.
+ DATA lv_nb_of_slash TYPE string.
+
lv_obj_name = is_item-obj_name.
@@ -121,8 +133,18 @@ CLASS zcl_abapgit_filename_logic IMPLEMENTATION.
ENDIF.
" handle namespaces
- REPLACE ALL OCCURRENCES OF '/' IN rv_filename WITH '#'.
- TRANSLATE rv_filename TO LOWER CASE.
+ CREATE OBJECT go_aff_registry TYPE zcl_abapgit_aff_registry.
+ IF go_aff_registry->is_supported_object_type( is_item-obj_type ) = abap_true.
+ FIND ALL OCCURRENCES OF `/` IN rv_filename MATCH COUNT lv_nb_of_slash.
+ IF lv_nb_of_slash = 2.
+ REPLACE FIRST OCCURRENCE OF `/` IN rv_filename WITH `(`.
+ REPLACE `/` IN rv_filename WITH `)`.
+ ENDIF.
+ ELSE.
+ REPLACE ALL OCCURRENCES OF '/' IN rv_filename WITH '#'.
+ ENDIF.
+ TRANSLATE rv_filename TO LOWER CASE.
ENDMETHOD.
+
ENDCLASS.
diff --git a/src/objects/core/zcl_abapgit_filename_logic.clas.testclasses.abap b/src/objects/core/zcl_abapgit_filename_logic.clas.testclasses.abap
index 35ea5633f..ac5396e8b 100644
--- a/src/objects/core/zcl_abapgit_filename_logic.clas.testclasses.abap
+++ b/src/objects/core/zcl_abapgit_filename_logic.clas.testclasses.abap
@@ -128,7 +128,24 @@ CLASS ltcl_run_checks IMPLEMENTATION.
exp = 'ZMIME_<>_?'
act = ls_item-obj_name ).
- " JSON
+ zcl_abapgit_filename_logic=>file_to_object(
+ EXPORTING
+ iv_filename = 'ztest(name).w3mi.data,json'
+ iv_path = '/src/'
+ iv_devclass = '$PACK'
+ io_dot = mo_dot
+ IMPORTING
+ es_item = ls_item
+ ev_is_xml = lv_is_xml ).
+
+ cl_abap_unit_assert=>assert_equals(
+ exp = 'W3MI'
+ act = ls_item-obj_type ).
+ cl_abap_unit_assert=>assert_equals(
+ exp = 'ZTEST(NAME)'
+ act = ls_item-obj_name ).
+
+ " AFF file
zcl_abapgit_filename_logic=>file_to_object(
EXPORTING
iv_filename = 'ztest.chko.json'
@@ -149,6 +166,28 @@ CLASS ltcl_run_checks IMPLEMENTATION.
exp = abap_true
act = lv_is_json ).
+
+ " AFF file with namespace
+ zcl_abapgit_filename_logic=>file_to_object(
+ EXPORTING
+ iv_filename = '(abcd)ztest.chko.json'
+ iv_path = '/src/'
+ iv_devclass = '$PACK'
+ io_dot = mo_dot
+ IMPORTING
+ es_item = ls_item
+ ev_is_json = lv_is_json ).
+
+ cl_abap_unit_assert=>assert_equals(
+ exp = 'CHKO'
+ act = ls_item-obj_type ).
+ cl_abap_unit_assert=>assert_equals(
+ exp = '/ABCD/ZTEST'
+ act = ls_item-obj_name ).
+ cl_abap_unit_assert=>assert_equals(
+ exp = abap_true
+ act = lv_is_json ).
+
ENDMETHOD.
METHOD object_to_file.
@@ -215,6 +254,29 @@ CLASS ltcl_run_checks IMPLEMENTATION.
exp = 'zmime_%3c%3e_%3f.w3mi.jpg'
act = lv_filename ).
+ ls_item-obj_type = 'W3MI'.
+ ls_item-obj_name = 'ZTEST(NAME)'.
+
+ lv_filename = zcl_abapgit_filename_logic=>object_to_file(
+ is_item = ls_item
+ iv_ext = 'json' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ exp = 'ztest(name).w3mi.json'
+ act = lv_filename ).
+
+ " AFF object with namespace
+ ls_item-obj_type = 'CHKO'.
+ ls_item-obj_name = '/TEST/ZTEST'.
+
+ lv_filename = zcl_abapgit_filename_logic=>object_to_file(
+ is_item = ls_item
+ iv_ext = 'json' ).
+
+ cl_abap_unit_assert=>assert_equals(
+ exp = '(test)ztest.chko.json'
+ act = lv_filename ).
+
ENDMETHOD.
METHOD file_to_object_pack.
diff --git a/test/abap_transpile.json b/test/abap_transpile.json
index 600182d5b..9b185981f 100644
--- a/test/abap_transpile.json
+++ b/test/abap_transpile.json
@@ -5,6 +5,7 @@
"src/ui/zcl_abapgit_e",
"src/zcl_abapgit_e",
"zcl_abapgit_adt_link",
+ "zcl_abapgit_aff_registry",
"zcl_abapgit_ajson*",
"zcl_abapgit_apack_reader",
"zcl_abapgit_auth",