2021-03-05 17:55:40 +07:00
|
|
|
<?php
|
|
|
|
|
2021-05-09 20:15:43 +00:00
|
|
|
declare (strict_types=1);
|
2021-03-05 17:55:40 +07:00
|
|
|
namespace Rector\Naming\ExpectedNameResolver;
|
|
|
|
|
2021-11-28 00:36:13 +00:00
|
|
|
use RectorPrefix20211128\Doctrine\Inflector\Inflector;
|
|
|
|
use RectorPrefix20211128\Nette\Utils\Strings;
|
2021-11-28 16:42:02 +00:00
|
|
|
use Rector\Core\Util\StringUtils;
|
2021-10-29 23:49:05 +00:00
|
|
|
/**
|
|
|
|
* @see \Rector\Core\Tests\Naming\ExpectedNameResolver\InflectorSingularResolverTest
|
|
|
|
*/
|
2021-03-05 17:55:40 +07:00
|
|
|
final class InflectorSingularResolver
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var array<string, string>
|
|
|
|
*/
|
2021-10-29 23:49:05 +00:00
|
|
|
private const SINGULARIZE_MAP = ['news' => 'new'];
|
2021-03-05 17:55:40 +07:00
|
|
|
/**
|
|
|
|
* @var string
|
2021-06-17 09:49:16 +00:00
|
|
|
* @see https://regex101.com/r/lbQaGC/3
|
2021-03-05 17:55:40 +07:00
|
|
|
*/
|
2021-10-29 23:49:05 +00:00
|
|
|
private const CAMELCASE_REGEX = '#(?<camelcase>([a-z\\d]+|[A-Z\\d]{1,}[a-z\\d]+|_))#';
|
2021-03-05 17:55:40 +07:00
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
* @see https://regex101.com/r/2aGdkZ/2
|
|
|
|
*/
|
|
|
|
private const BY_MIDDLE_REGEX = '#(?<by>By[A-Z][a-zA-Z]+)#';
|
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
private const SINGLE = 'single';
|
2021-11-13 08:43:40 +00:00
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
private const CAMELCASE = 'camelcase';
|
2021-03-05 17:55:40 +07:00
|
|
|
/**
|
2021-10-26 09:20:50 +00:00
|
|
|
* @var \Doctrine\Inflector\Inflector
|
2021-03-05 17:55:40 +07:00
|
|
|
*/
|
|
|
|
private $inflector;
|
2021-11-28 00:36:13 +00:00
|
|
|
public function __construct(\RectorPrefix20211128\Doctrine\Inflector\Inflector $inflector)
|
2021-03-05 17:55:40 +07:00
|
|
|
{
|
|
|
|
$this->inflector = $inflector;
|
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
public function resolve(string $currentName) : string
|
2021-03-05 17:55:40 +07:00
|
|
|
{
|
2021-11-28 00:36:13 +00:00
|
|
|
$matchBy = \RectorPrefix20211128\Nette\Utils\Strings::match($currentName, self::BY_MIDDLE_REGEX);
|
2021-11-28 18:05:13 +00:00
|
|
|
if ($matchBy !== null) {
|
2021-11-28 00:36:13 +00:00
|
|
|
return \RectorPrefix20211128\Nette\Utils\Strings::substring($currentName, 0, -\strlen($matchBy['by']));
|
2021-03-05 17:55:40 +07:00
|
|
|
}
|
2021-10-29 23:49:05 +00:00
|
|
|
$resolvedValue = $this->resolveSingularizeMap($currentName);
|
|
|
|
if ($resolvedValue !== null) {
|
|
|
|
return $resolvedValue;
|
2021-03-05 17:55:40 +07:00
|
|
|
}
|
2021-10-26 09:20:50 +00:00
|
|
|
if (\strncmp($currentName, self::SINGLE, \strlen(self::SINGLE)) === 0) {
|
2021-03-05 17:55:40 +07:00
|
|
|
return $currentName;
|
|
|
|
}
|
2021-10-30 00:06:50 +00:00
|
|
|
$singularValueVarName = $this->singularizeCamelParts($currentName);
|
2021-10-29 23:49:05 +00:00
|
|
|
if (\in_array($singularValueVarName, ['', '_'], \true)) {
|
2021-03-25 05:36:11 +07:00
|
|
|
return $currentName;
|
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
$singularValueVarName = $singularValueVarName === $currentName ? self::SINGLE . \ucfirst($singularValueVarName) : $singularValueVarName;
|
2021-10-26 09:20:50 +00:00
|
|
|
if (\strncmp($singularValueVarName, self::SINGLE, \strlen(self::SINGLE)) !== 0) {
|
2021-03-05 17:55:40 +07:00
|
|
|
return $singularValueVarName;
|
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
$length = \strlen($singularValueVarName);
|
2021-03-05 17:55:40 +07:00
|
|
|
if ($length < 40) {
|
|
|
|
return $singularValueVarName;
|
|
|
|
}
|
|
|
|
return $currentName;
|
|
|
|
}
|
2021-10-29 23:49:05 +00:00
|
|
|
/**
|
|
|
|
* @return string|null
|
|
|
|
*/
|
|
|
|
private function resolveSingularizeMap(string $currentName)
|
|
|
|
{
|
|
|
|
foreach (self::SINGULARIZE_MAP as $plural => $singular) {
|
|
|
|
if ($currentName === $plural) {
|
|
|
|
return $singular;
|
|
|
|
}
|
2021-11-28 16:42:02 +00:00
|
|
|
if (\Rector\Core\Util\StringUtils::isMatch($currentName, '#' . \ucfirst($plural) . '#')) {
|
2021-11-28 00:36:13 +00:00
|
|
|
$resolvedValue = \RectorPrefix20211128\Nette\Utils\Strings::replace($currentName, '#' . \ucfirst($plural) . '#', \ucfirst($singular));
|
2021-10-30 00:06:50 +00:00
|
|
|
return $this->singularizeCamelParts($resolvedValue);
|
2021-10-29 23:49:05 +00:00
|
|
|
}
|
2021-11-28 16:42:02 +00:00
|
|
|
if (\Rector\Core\Util\StringUtils::isMatch($currentName, '#' . $plural . '#')) {
|
2021-11-28 00:36:13 +00:00
|
|
|
$resolvedValue = \RectorPrefix20211128\Nette\Utils\Strings::replace($currentName, '#' . $plural . '#', $singular);
|
2021-10-30 00:06:50 +00:00
|
|
|
return $this->singularizeCamelParts($resolvedValue);
|
2021-10-29 23:49:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2021-10-30 00:06:50 +00:00
|
|
|
private function singularizeCamelParts(string $currentName) : string
|
|
|
|
{
|
2021-11-28 00:36:13 +00:00
|
|
|
$camelCases = \RectorPrefix20211128\Nette\Utils\Strings::matchAll($currentName, self::CAMELCASE_REGEX);
|
2021-10-30 00:06:50 +00:00
|
|
|
$resolvedName = '';
|
|
|
|
foreach ($camelCases as $camelCase) {
|
2021-11-13 08:43:40 +00:00
|
|
|
$value = $this->inflector->singularize($camelCase[self::CAMELCASE]);
|
|
|
|
if (\in_array($camelCase[self::CAMELCASE], ['is', 'has'], \true)) {
|
|
|
|
$value = $camelCase[self::CAMELCASE];
|
2021-11-13 08:28:51 +00:00
|
|
|
}
|
|
|
|
$resolvedName .= $value;
|
2021-10-30 00:06:50 +00:00
|
|
|
}
|
|
|
|
return $resolvedName;
|
|
|
|
}
|
2021-03-05 17:55:40 +07:00
|
|
|
}
|