Fixing the function
You're close. The problem is that you are passing an object to the initial delete call, extracting the nested property id
to use properly, but then when you make the recursive call, you're using only that id, not the whole object.
The quickest fix would probably to keep a reference to that object, and not destructure it in the parameter. I don't have enough understanding of the context to name it appropriately, so I'll just call it foo
. Then we can pass foo
to the recursive call, and it will just work.
With that fix, a variant of your function will work properly:
function _worktreeItemDelete(tree, foo) {
const currentId = foo.detail.item.id;
const filtered = tree.filter(entry => entry.id !== currentId);
const updTree = filtered.map(entry => {
if (!entry.children) return entry;
return {...entry, children: _worktreeItemDelete(entry.children, foo)};
});
return updTree
}
const arr = [{id: "8bfc-2b82-68ad-fb78", name: "inventory", type: "directory", path: "inventory/", children: [{id: "bccf-3788-6ec9-ba33", name: "inventory.yaml", type: "file", path: "inventory/inventory.yaml", }]}, {id: "4a28-4d63-6c30-4569", name: "model", type: "directory", path: "model/", children: [{id: "21d1-f4d2-e1c5-34b0", name: "model.yaml", type: "file", path: "model/model.yaml"}]}]
console .log (
_worktreeItemDelete (arr, {detail: {item: {id: 'bccf-3788-6ec9-ba33'}}})
)
.as-console-wrapper {max-height: 100% !important; top: 0}
Note that I changed this to a pure function rather than a method, hence skipping this.set("tree", updTree)
, adding a tree
parameter, and removing the this
references. They should be easy to put back.
However, the above does not explain the recursion depth error you described. I would expect something more like
Cannot read property 'item' of undefined
So there may be something additional happening.
An alternate approach
I would write this code differently. I would use a generic version of a tree-filtering function and pass it a predicate for node-selection.
My version might look like this:
const deepFilter = (pred) => (xs) =>
xs .flatMap (({children = [], ...rest}) =>
pred (rest)
? [{... rest, children: deepFilter (pred) (children)}]
: []
)
const removeById = ({detail: {item: {id: target}}}) =>
deepFilter (({id}) => id !== target)
const arr = [{id: "8bfc-2b82-68ad-fb78", name: "inventory", type: "directory", path: "inventory/", children: [{id: "bccf-3788-6ec9-ba33", name: "inventory.yaml", type: "file", path: "inventory/inventory.yaml", }]}, {id: "4a28-4d63-6c30-4569", name: "model", type: "directory", path: "model/", children: [{id: "21d1-f4d2-e1c5-34b0", name: "model.yaml", type: "file", path: "model/model.yaml"}]}]
console .log (
removeById ({detail: {item: {id: 'bccf-3788-6ec9-ba33'}}}) (arr)
)
.as-console-wrapper {max-height: 100% !important; top: 0}
Note that deepFilter
is generic. It works for any tree where the descendent nodes are in the property children
. (See another answer for a more generic version that lets you configure this property.)
So the custom code here is just removeById
. To my mind, that's a nice win.
If it is important, we can -- at the price of a little additional complexity -- choose to only include the children
node if the data is not empty. If you want that and need help with it, just add a comment.