Главное правило рефакторинга: все повторяющиеся элементы кода выносим в функцию.
Дальнейшие действия зависят от степени прокачки скилла "абстрагирование".
Вот это, понятно, далеко не идеал, но всё же:
const copyObj = (obj, name, id) => {
const { trees, names } = obj;
const type_array_adder = ( array, suffix ) => array.map( type => type + '_' + suffix );
const types = {
tree: type_array_adder( [ 'obj', 'obj_feature', 'regexp' ], 'tree' ),
name: type_array_adder( [ 'unmark', 'shift', 'fill' ], 'name' )
};
const id_setter = ( item, obj, prop, ID ) => {
if ( item.id === obj[ prop ] ){
obj[ prop ] = ID;
}
}
const parent_id_setter = ( item, obj, type, ID ) => {
if (obj.name_type === type || obj.tree_type === type) {
id_setter( item, obj[ type ], 'parent_element', ID );
}
};
obj[name].map(item => {
const newId = uuid();
trees.map(tree => {
types['tree'].map( type => {
parent_id_setter( item, tree, type, newId );
});
});
names.map(name => {
types['name'].map( type => {
parent_id_setter( item, name, type, newId );
if (name.name_type === 'shift_name') {
id_setter( name[ type ], 'parent_element_from', newId );
id_setter( name[ type ], 'parent_element_to', newId );
}
if (name.name_type === 'fill_name') {
name[ type ].feature_values.map(val => {
if (val.value_type === 'dynamic') {
id_setter( item, val.dvalue, 'parent_element', newId );
}
});
}
});
});
});
return {
trees,
names
};
};