Я бы выделил здесь служебную функцию, глубокую версию функции filterMap
, которая принимает предикат и функцию преобразования и рекурсивно отфильтровывает каждый уровень дочерних элементов в соответствии с предикатом, а затем преобразует остальные с помощью предоставленная функция.
Вы можете использовать это, сначала переформатировав B для отображения - здесь мы называем это perms
- между именами и списками разрешений, затем вызывая это deepFilterMap
с предикатом, который проверяет если имя объекта в perms
и преобразование, которое устанавливает meta.permissions
в это значение.
Эта версия deepFilterMap
задает c для структур, в которых узлы-потомки находятся в массиве с именем children
. Мы могли бы сделать его более обобщенным c, но для этого потребовался бы другой параметр функции. Это интересное упражнение, но, возможно, здесь слишком много.
const deepFilterMap = (pred, transform) => (tree) =>
pred (tree)
? {
... transform (tree),
... (tree.children
? {children: tree .children
.filter (pred)
.map (deepFilterMap (pred, transform))
}
: {}
)
}
: {}
const transform = (A, B) => {
const perms = Object .fromEntries (B .map (
({name, permissions}) => [name, permissions])
)
return deepFilterMap (
({name}) => name in perms,
({name, meta, ...rest}) => ({
name,
meta: {...meta, permissions: perms [name]},
...rest
})
) (A)
}
const A = {name: "activityRelatedManager", meta: {title: "Activity Related Manager", permissions: []}, children: [{name: "activityPublish", meta: {title: "Publish Activity", permissions: []}}, {name: "activityManager", meta: {title: "Manage Activity", permissions: []}}, {name: "activityTypeManager", meta: {title: " Manage Activity Type", permissions: []}}, {name: "activityLocationManager", meta: {title: " Manage Activity Location", permissions: []}}]};
const B = [{id: 1, name: "activityRelatedManager", permissions: ["activity: publish"]}, {id: 2, name: "activityManager", permissions: ["activity: index", "activity: show"]}, {id: 3, name: "activityTypeManager", permissions: []}];
console .log (transform (A, B))
.as-console-wrapper {min-height: 100% !important; top: 0}
Конечно, мы могли бы включить работу deepFilterMap
в нашу основную функцию. В целом, у нас было бы меньше строк кода. Но, на мой взгляд, разбить сложность таким способом гораздо удобнее. И теперь у вас есть потенциально многократно используемая функция.