protected function optimizeTree(array $nodes) : array
    {
        $nodes = array_reduce($nodes, function (array $nodes, $current) {
            $last = end($nodes);
            if ($last instanceof TagNode && $current instanceof TagNode) {
                // If last and current tags are the same.
                $lastTag = $last->getTag();
                $currentTag = $current->getTag();
                if ($lastTag == $currentTag) {
                    // Merge children of last and current nodes.
                    $children = array_merge($last->getChildren(), $current->getChildren());
                    $current = new TagNode($currentTag, $children);
                    // Remove last node.
                    array_pop($nodes);
                }
            }

            return array_merge($nodes, [$current]);
        }, []);

        // Optimize each children tag.
        return array_map(function ($node) {
            if ($node instanceof TagNode) {
                $tag = $node->getTag();
                $children = $this->optimizeTree($node->getChildren());
                return new TagNode($tag, $children);
            }

            return $node;
        }, $nodes);
    }