Combining composite, decorator and visitor patterns

I am currently working on a project where I need to manipulate a tree-like data structure, which I implemented with a composite pattern.
I want to be able to do different actions on this data structure, so I implemented a visitor pattern.

I was starting to see some code duplication in between my visitors, so I decided to implement a decorator pattern over my visitors. The decorators implement the Visitor interface, and their constructor accepts a Visitor as a parameter.

The idea is that the decorator executes some code before, executes its base visitor (the one passed as a parameter), and executes some code after, a bit like that:

class ConcreteDecorator {
decoratedVisitor: Visitor
visitLeaf(leaf) {
// Do some stuff before
result := decoratedVisitor.visitLeaf(leaf)
// Do some stuff after
return result;
}
visitComposite(composite) {
// Do some stuff before
result := decoratedVisitor.visitComposite(leaf)
// Do some stuff after
return result;
}
}

The problem is that once I call visitComposite on a decorator, for example, the decorator does its stuff, then calls its child visitor's visitComposite. Since visitComposite is a recursive method, when it is called on the ConcreteVisitor and the method does its recursive calls, we lose the decorators. The decorators are only applied to the first visited node.

I thought of different solutions, like using inheritance instead of decorators, but I want to be able to reuse the decorators on different visitors, so that's not a viable option.

I also thought of using some kind of strategy pattern. The strategies would have a beforeVisitLeaf/afterVisitLeaf and beforeVisitComposite/afterVisitComposite methods. The problem is I can't implement a filter decorator, which abort the visit of certain nodes.

I managed to do a hack this solution and make it work by keeping a hook on the child visitor methods and substituting the child visitor instance methods by the decorator methods manually (I can do that because... JavaScript).

This solution is super hacky, so I was wondering if you guys had any design ideas on how to fix this.