<commit_before><?php declare(strict_types=1);

namespace Rector\YamlRector\Rector;

use Nette\Utils\Strings;
use Rector\YamlRector\Contract\YamlRectorInterface;

final class RenameSubKeyYamlRector implements YamlRectorInterface
{
    /**
     * @var string[]
     */
    private $pathsToNewKeys = [];

    /**
     * @param string[] $pathsToNewKeys
     */
    public function __construct(array $pathsToNewKeys)
    {
        $this->pathsToNewKeys = $pathsToNewKeys;
    }

    public function isCandidate(string $content): bool
    {
        foreach ($this->pathsToNewKeys as $path => $newKey) {
            $pathPattern = $this->createPatternFromPath($path);

            if ((bool) Strings::match($content, $pathPattern)) {
                return true;
            }
        }

        return false;
    }

    public function refactor(string $content): string
    {
        foreach ($this->pathsToNewKeys as $path => $newKey) {
            $pathPattern = $this->createPatternFromPath($path);

            while (Strings::match($content, $pathPattern)) {
                $replacement = $this->createReplacementFromPathAndNewKey($path, $newKey);
                $content = Strings::replace($content, $pathPattern, $replacement, 1);
            }
        }

        return $content;
    }

    private function createPatternFromPath(string $path): string
    {
        $pathParts = Strings::split($path, '#[\s+]?>[\s+]?#');

        $pattern = '';
        foreach ($pathParts as $key => $pathPart) {
            if ($key === (count($pathParts) - 1)) {
                // last only up-to the key name
                $pattern .= sprintf('(%s)(.*?)', preg_quote($pathPart));
            } else {
                // see https://regex101.com/r/n8XPbV/3/ for ([^:]*?)
                $pattern .= sprintf('(%s:\s+)([^:]*?)', preg_quote($pathPart));
            }
        }

        return '#^' . $pattern . '#ms';
    }

    /**
     * @param string[] $pathSteps
     */
    private function createReplacementFromPathAndNewKey(string $path, string $newKey): string
    {
        $replacement = '';

        $pathParts = Strings::split($path, '#[\s+]?>[\s+]?#');

        $final = 2 * count($pathParts);
        for ($i = 1; $i < $final - 1; ++$i) {
            $replacement .= '$' . $i;
        }

        $replacement .= preg_quote($newKey);
        $replacement .= '$' . ($i + 3);

        return $replacement;
    }
}<commit_msg>decouple splitPathToParts() method<commit_after><?php declare(strict_types=1);

namespace Rector\YamlRector\Rector;

use Nette\Utils\Strings;
use Rector\YamlRector\Contract\YamlRectorInterface;

final class RenameSubKeyYamlRector implements YamlRectorInterface
{
    /**
     * @var string[]
     */
    private $pathsToNewKeys = [];

    /**
     * @param string[] $pathsToNewKeys
     */
    public function __construct(array $pathsToNewKeys)
    {
        $this->pathsToNewKeys = $pathsToNewKeys;
    }

    public function isCandidate(string $content): bool
    {
        foreach ($this->pathsToNewKeys as $path => $newKey) {
            $pathPattern = $this->createPatternFromPath($path);

            if ((bool) Strings::match($content, $pathPattern)) {
                return true;
            }
        }

        return false;
    }

    public function refactor(string $content): string
    {
        foreach ($this->pathsToNewKeys as $path => $newKey) {
            $pathPattern = $this->createPatternFromPath($path);

            while (Strings::match($content, $pathPattern)) {
                $replacement = $this->createReplacementFromPathAndNewKey($path, $newKey);
                $content = Strings::replace($content, $pathPattern, $replacement, 1);
            }
        }

        return $content;
    }

    private function createPatternFromPath(string $path): string
    {
        $pathParts = $this->splitPathToParts($path);

        $pattern = '';
        foreach ($pathParts as $key => $pathPart) {
            if ($key === (count($pathParts) - 1)) {
                // last only up-to the key name
                $pattern .= sprintf('(%s)(.*?)', preg_quote($pathPart));
            } else {
                // see https://regex101.com/r/n8XPbV/3/ for ([^:]*?)
                $pattern .= sprintf('(%s:\s+)([^:]*?)', preg_quote($pathPart));
            }
        }

        return '#^' . $pattern . '#ms';
    }

    private function createReplacementFromPathAndNewKey(string $path, string $newKey): string
    {
        $replacement = '';

        $pathParts = $this->splitPathToParts($path);

        $final = 2 * count($pathParts);
        for ($i = 1; $i < $final - 1; ++$i) {
            $replacement .= '$' . $i;
        }

        $replacement .= preg_quote($newKey);
        $replacement .= '$' . ($i + 3);

        return $replacement;
    }

    /**
     * @return string[]
     */
    private function splitPathToParts(string $path): array
    {
        return Strings::split($path, '#[\s+]?>[\s+]?#');
    }
}
{'fraction_non_alphanumeric': 0.1594290309609972, 'fraction_numerical': 0.0048250904704463205, 'mean_word_length': 2.1269641734758014, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 26, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3136626', 'n_tokens_mistral': 1541, 'n_tokens_neox': 1478, 'n_words': 289}