-
-
Notifications
You must be signed in to change notification settings - Fork 444
Expand file tree
/
Copy pathOnlyRuleResolver.php
More file actions
131 lines (110 loc) · 4.1 KB
/
Copy pathOnlyRuleResolver.php
File metadata and controls
131 lines (110 loc) · 4.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<?php
declare(strict_types=1);
namespace Rector\Configuration;
use PHPStan\Reflection\ReflectionProvider;
use Rector\Contract\Rector\RectorInterface;
use Rector\Exception\Configuration\RectorRuleNameAmbiguousException;
use Rector\Exception\Configuration\RectorRuleNotFoundException;
/**
* @see \Rector\Tests\Configuration\OnlyRuleResolverTest
*/
final readonly class OnlyRuleResolver
{
/**
* @param RectorInterface[] $rectors
*/
public function __construct(
private array $rectors,
private ReflectionProvider $reflectionProvider
) {
}
public function resolve(string $rule): string
{
// fix wrongly double escaped backslashes
$rule = str_replace('\\\\', '\\', $rule);
// remove single quotes appearing when single-quoting arguments on windows
if (str_starts_with($rule, "'") && str_ends_with($rule, "'")) {
$rule = substr($rule, 1, -1);
}
$rule = ltrim($rule, '\\');
foreach ($this->rectors as $rector) {
if ($rector::class === $rule) {
return $rule;
}
}
// allow short rule names if there are not duplicates
$matching = [];
foreach ($this->rectors as $rector) {
if (str_ends_with($rector::class, '\\' . $rule)) {
$matching[] = $rector::class;
}
}
$matching = array_unique($matching);
if (count($matching) === 1) {
return $matching[0];
}
if (count($matching) > 1) {
sort($matching);
$message = sprintf(
'Short rule name "%s" is ambiguous. Specify the full rule name:' . PHP_EOL
. '- ' . implode(PHP_EOL . '- ', $matching),
$rule
);
throw new RectorRuleNameAmbiguousException($message);
}
if (! str_contains($rule, '\\')) {
// the shell has eaten unescaped backslashes, e.g. --only=\Rector\Some\Rule
$flattenMatching = [];
foreach ($this->rectors as $rector) {
if (str_replace('\\', '', $rector::class) === $rule) {
$flattenMatching[] = $rector::class;
}
}
$flattenMatching = array_unique($flattenMatching);
if (count($flattenMatching) === 1) {
return $flattenMatching[0];
}
$message = sprintf(
'Rule "%s" was not found.%sThe rule has no namespace. Make sure to escape the backslashes, and add quotes around the rule name: --only="My\\Rector\\Rule"',
$rule,
PHP_EOL
);
} else {
// the rule class exists, it is just missing in the config
if ($this->isRectorRuleClass($rule)) {
throw new RectorRuleNotFoundException($this->createUnregisteredMessage($rule));
}
$message = sprintf(
'Rule "%s" was not found.%sMake sure it is registered in your config or in one of the sets',
$rule,
PHP_EOL
);
}
throw new RectorRuleNotFoundException($message);
}
/**
* Is this an existing rule class, that is just not registered in the config?
*/
private function isRectorRuleClass(string $className): bool
{
if (! $this->reflectionProvider->hasClass($className)) {
return false;
}
$classReflection = $this->reflectionProvider->getClass($className);
if ($classReflection->isAbstract()) {
return false;
}
return $classReflection->implementsInterface(RectorInterface::class);
}
private function createUnregisteredMessage(string $ruleClass): string
{
$shortRuleClass = substr((string) strrchr($ruleClass, '\\'), 1);
return sprintf(
'Rule "%s" exists, but is not registered in your Rector config.%sRegister it in your rector.php:'
. PHP_EOL . PHP_EOL . ' ->withRules([%s::class])',
$ruleClass,
PHP_EOL,
$shortRuleClass
);
}
}